source: cpp/frams/vm/classes/collectionobj.cpp @ 387

Last change on this file since 387 was 387, checked in by Maciej Komosinski, 7 years ago

Improved help descriptions

  • Property svn:eol-style set to native
File size: 12.0 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "collectionobj.h"
6#include <common/nonstd_math.h> //sqrt in borland
7#include <frams/util/validitychecks.h>
8#include <common/nonstd_stl.h>
9#include <frams/util/sstringutils.h>
10#ifndef NO_VMACHINE
11#include <frams/vm/vmachine.h>
12#endif
13
14#define FIELDSTRUCT VectorObject
15ParamEntry vector_paramtab[]=
16{
17{"Vector",1,13,"Vector","Vector is a 1-dimensional array indexed by an integer value (starting from 0). "
18 "Multidimensional arrays can be simulated by putting other Vector objects into a Vector.\n"
19 "Examples:\n"
20 "var v1=Vector.new(); v1.add(123); v1.add(\"string\");\n"
21 "var v2=[123,\"string\"]; //a short way of doing the same (square brackets create a vector)\n"
22 "var v3=[[1,2,3],[4,5],[6]]; //simulate a 2D array\n"
23 "for(var element in v3) Simulator.print(element); //Vector supports enumeration"
24},
25{"clear",0,PARAM_NOSTATIC,"clear data","p()",PROCEDURE(p_clear),},
26{"size",0,PARAM_READONLY | PARAM_NOSTATIC,"element count","d",GETONLY(size),},
27{"remove",0,PARAM_NOSTATIC,"remove at position","p(d position)",PROCEDURE(p_remove),},
28{"get",0,PARAM_NOSTATIC,"get value at position","p x(d position)",PROCEDURE(p_get),"object[position] can be always used instead of object.get(position)"},
29{"set",0,PARAM_NOSTATIC,"set value at position","p(d position,x value)",PROCEDURE(p_set),"object[position]=value can be always used instead of object.set(position,value)"},
30{"add",0,PARAM_NOSTATIC,"append at the end","p(x value)",PROCEDURE(p_add),},
31{"find",0,PARAM_NOSTATIC,"find","p d(x value)",PROCEDURE(p_find),"returns the element index or -1 if not found"},
32{"avg",0,PARAM_READONLY | PARAM_NOSTATIC,"average","f",GETONLY(avg)},
33{"stdev",0,PARAM_READONLY | PARAM_NOSTATIC,"standard deviation","f",GETONLY(stdev),"=sqrt(sum((element[i]-avg)^2)/(size-1)) which is estimated population std.dev. from sample std.dev."},
34{"toString",0,PARAM_READONLY | PARAM_NOSTATIC,"textual form","s",GETONLY(toString),},
35{"new",0,0,"create new Vector","p oVector()",STATICPROCEDURE(p_new),},
36{"sort",0,PARAM_NOSTATIC,"sort elements (in place)","p(o comparator)",PROCEDURE(p_sort),"comparator can be null, giving the \"natural\" sorting order (depending on element type), otherwise it must be a function reference obtained by the \"function FUNCTIONNAME\" operator.\n\nExample:\nfunction compareLastDigit(a,b) {return (a%10)<(b%10);}\nvar v=[16,23,35,42,54,61];\nv.sort(function compareLastDigit);"},
37{"iterator",0,PARAM_NOSTATIC | PARAM_READONLY,"iterator","o",GETONLY(iterator),},
38{0,0,0,},
39};
40#undef FIELDSTRUCT
41
42#define FIELDSTRUCT DictionaryObject
43ParamEntry dictionary_paramtab[]=
44{
45{"Dictionary",1,9,"Dictionary","Dictionary associates stored values with string keys "
46 "(\"key\" is the first argument in get/set/remove functions). Integer \"key\" can be "
47 "used to enumerate all elements (note that the sequence of elements is not preserved).\n"
48 "Examples:\nvar d1=Dictionary.new(); d1.set(\"name\",\"John\"); d1.set(\"age\",44);\n"
49 "var d2=Dictionary.new(); d2[\"name\"]=\"John\"; d2[\"age\"]=44; //shorthand notation equivalent to the line above\n"
50 "var i;\nfor(i=0;i<d.size;i++) Simulator.print(d.getKey(i)+\" is \"+d.get(i));",},
51{"clear",0,PARAM_NOSTATIC,"clear data","p()",PROCEDURE(p_clear),},
52{"size",0,PARAM_NOSTATIC | PARAM_READONLY,"element count","d",GETONLY(size),},
53{"remove",0,PARAM_NOSTATIC,"remove named or indexed element","p(x key)",PROCEDURE(p_remove),},
54{"get",0,PARAM_NOSTATIC,"get named or indexed element","p x(x key)",PROCEDURE(p_get),"object[position] can be always used instead of object.get(position)"},
55{"getKey",0,PARAM_NOSTATIC,"get a key of the indexed element","p s(d index)",PROCEDURE(p_getKey),},
56{"set",0,PARAM_NOSTATIC,"set named or indexed element","p(x key,x value)",PROCEDURE(p_set),"object[key]=value can be always used instead of object.set(key,value)"},
57{"find",0,PARAM_NOSTATIC,"find","p s(x value)",PROCEDURE(p_find),"returns the element key or null if not found"},
58{"new",0,0,"create new Dictionary","p oDictionary()",STATICPROCEDURE(p_new),},
59{"toString",0,PARAM_READONLY | PARAM_NOSTATIC,"textual form","s",GETONLY(toString),},
60{0,0,0,},
61};
62#undef FIELDSTRUCT
63
64Param VectorObject::par(vector_paramtab);
65Param DictionaryObject::par(dictionary_paramtab);
66
67/////////////////////////////////////////
68
69VectorObject::VectorObject(Pt3D &pt)
70        :readonly(0),owndata(1)
71{
72set(0,ExtValue(pt.x));
73set(1,ExtValue(pt.y));
74set(2,ExtValue(pt.z));
75}
76
77void VectorObject::clear()
78{
79if (owndata)
80for(int i=data.size()-1;i>=0;i--)
81        {
82        ExtValue *v=(ExtValue*)data.get(i);
83        if (v) delete v;
84        }
85data.clear();
86}
87
88void VectorObject::p_remove(PARAMPROCARGS)
89{
90if (readonly) return;
91int i=args->getInt();
92if ((i<0)||(i>=data.size())) return;
93ExtValue *v=(ExtValue*)data.get(i);
94if (v) delete v;
95data-=i;
96}
97
98void VectorObject::set(int i,const ExtValue& val)
99{
100int oldsize=data.size();
101if (i<0) return;
102ExtValue *v=(ExtValue*)data.get(i);
103if (v) delete v;
104data.set(i,new ExtValue(val));
105i--;
106while(i>=oldsize)
107        {
108        data.set(i,0);
109        i--;
110        }
111}
112
113void VectorObject::p_get(PARAMPROCARGS)
114{
115int i=args->getInt();
116if (listIndexCheck(&data,i,"VectorObject","get"))
117        {
118        ExtValue *v=get(i);
119        if (v)
120                {
121                *ret=*v;
122                return;
123                }
124        }
125*ret=ExtValue();
126}
127
128void VectorObject::get_avg(ExtValue* ret)
129{
130if (!data.size()) {ret->setEmpty(); return;}
131double s=0.0;
132for(int i=data.size()-1;i>=0;i--)
133        s+=((ExtValue*)data.get(i))->getDouble();
134s/=data.size();
135ret->setDouble(s);
136}
137
138SString VectorObject::serialize() const
139{
140SString out="[";
141        {
142        for(int i=0;i<data.size();i++)
143                {
144                ExtValue* v=(ExtValue*)data.get(i);
145                if (i) out+=",";
146                if (v)
147                        out+=v->serialize();
148                else
149                        out+="null";
150                }
151        }
152out+="]";
153//sprintf(out.directAppend(20),"<Vector@%p>",this);out.endAppend();
154return out;
155}
156
157static THREAD_LOCAL_DEF(SList,VectorObject_tostring_trace);
158
159void VectorObject::get_toString(ExtValue* ret)
160{
161SString out="[";
162//static SListTempl<VectorObject*> trace;
163if (tlsGetRef(VectorObject_tostring_trace).find(this)>=0)
164        out+="...";
165else
166        {
167        tlsGetRef(VectorObject_tostring_trace)+=this;
168        for(int i=0;i<data.size();i++)
169                {
170                ExtValue* v=(ExtValue*)data.get(i);
171                if (i) out+=",";
172                if (v)
173                        out+=v->getString();
174                else
175                        out+="null";
176                }
177        tlsGetRef(VectorObject_tostring_trace)-=this;
178        }
179out+="]";
180ret->setString(out);
181}
182
183void VectorObject::get_stdev(ExtValue* ret)
184{
185if (!data.size()) {ret->setEmpty(); return;}
186get_avg(ret);
187double a=ret->getDouble();
188double s=0.0;
189for(int i=data.size()-1;i>=0;i--)
190        {
191        double d=a-((ExtValue*)data.get(i))->getDouble();
192        s+=d*d;
193        }
194ret->setDouble(sqrt(s/max(1,data.size()-1)));
195}
196
197void VectorObject::p_find(PARAMPROCARGS)
198{
199short i;
200for(i=0;i<data.size();i++)
201        {
202        if ((*args)==(*get(i)))
203                {ret->setInt(i);return;}
204        }
205ret->setInt(-1);
206}
207
208class VEComparator
209{
210public:
211bool operator()(const ExtValue *a,const ExtValue *b) {return a->compare(*b)==ExtValue::ResultLower;}
212};
213
214#ifndef NO_VMACHINE
215class VMVEComparator
216{
217public:
218VMachine::JumpTargetObject *jto;
219VMachine *vm;
220VMVEComparator(VMachine::JumpTargetObject *_jto):jto(_jto),vm(jto->vm) {}
221bool operator()(const ExtValue *a,const ExtValue *b);
222};
223
224bool VMVEComparator::operator()(const ExtValue *a,const ExtValue *b)
225{
226if (!VMCode::prepareDynamicJumpTarget(jto->pc,jto->code))
227        return false;
228
229vm->push(*a);
230vm->push(*b);
231vm->pushNewCallState();
232vm->jumpDynamicJumpTarget(jto->pc);
233vm->run();
234vm->popCallState();
235bool ret;
236ExtValue& retval=vm->getValue();
237if (retval.type==TInvalid)
238        {
239        ret=false;
240        logPrintf("VectorElementComparator","",LOG_ERROR,"Comparison function returned no value");
241        }
242else
243        ret=(retval.getInt()!=0);
244vm->drop(2);
245return ret;
246}
247#endif
248
249void VectorObject::p_sort(PARAMPROCARGS)
250{
251#ifndef NO_VMACHINE
252VMachine::JumpTargetObject *jto=VMachine::JumpTargetObject::fromObject(args->getObject(),false);
253if (jto)
254        {
255        VMVEComparator cmp(jto);
256        ExtValue **first=(ExtValue**)&data.getref(0);
257        std::sort(first,first+data.size(),cmp);
258        }
259else
260#endif
261        {
262        VEComparator cmp;
263        ExtValue **first=(ExtValue**)&data.getref(0);
264        std::sort(first,first+data.size(),cmp);
265        }
266ret->setEmpty();
267}
268
269void VectorObject::get_iterator(ExtValue* ret)
270{
271ret->setObject(VectorIterator::makeFrom(this));
272}
273
274VectorObject* VectorObject::fromObject(const ExtObject& o, bool warn)
275{
276return (VectorObject*)o.getTarget(par.getName(),true,warn);
277}
278
279/////////////////////////////
280
281void DictionaryObject::clear()
282{
283for(HashEntryIterator it(hash);it.isValid();)
284        {
285        ExtValue *v=(ExtValue*)hash.remove(it);
286        if (v) delete v;
287        }
288hash.clear();
289hash.init();
290}
291
292void DictionaryObject::p_find(PARAMPROCARGS)
293{
294for(HashEntryIterator it(hash);it.isValid();it++)
295        {
296        if ((*args)==(*((ExtValue*)it->value)))
297                {
298                ret->setString(it->key);
299                return;
300                }
301        }
302ret->setEmpty();
303}
304
305HashEntryIterator* DictionaryObject::getIndexIterator(int i)
306{
307if (i<0) return 0;
308if (i>=hash.getSize()) return 0;
309
310if ((!it.isValid())||(it_index>i))
311        {
312        it=HashEntryIterator(hash);
313        it_index=0;
314        }
315while(it.isValid())
316        {
317        if (it_index==i)
318                return &it;
319        it_index++;
320        it++;
321        }
322return 0;
323}
324
325void DictionaryObject::p_remove(PARAMPROCARGS)
326{
327if ((args->type==TInt)||(args->type==TDouble))
328        {
329        HashEntryIterator* iter=getIndexIterator(args->getInt());
330        if (iter)
331                {
332                ExtValue *oldval=(ExtValue*)hash.remove(*iter);
333                if (oldval) {*ret=*oldval; delete oldval;} else *ret=ExtValue();
334                }
335        }
336else
337        {
338        ExtValue *oldval=(ExtValue*)hash.remove(args[0].getString());
339        if (oldval) {*ret=*oldval; delete oldval;} else *ret=ExtValue();
340        }
341}
342
343void DictionaryObject::p_get(PARAMPROCARGS)
344{
345if ((args->type==TInt)||(args->type==TDouble))
346        {
347        HashEntryIterator* iter=getIndexIterator(args->getInt());
348        if (iter && (*iter)->value)
349                {
350                *ret=*((ExtValue*)(*iter)->value);
351                return;
352                }
353        }
354else
355        {
356        ExtValue *val=(ExtValue*)hash.get(args[0].getString());
357        if (val)
358                {
359                *ret=*val;
360                return;
361                }
362        }
363*ret=ExtValue();
364}
365
366void DictionaryObject::p_getKey(PARAMPROCARGS)
367{
368HashEntryIterator* iter=getIndexIterator(args->getInt());
369if (iter)
370        {
371        *ret=(*iter)->key;
372        return;
373        }
374*ret=ExtValue();
375}
376
377void DictionaryObject::p_set(PARAMPROCARGS)
378{
379ExtValue *newval=(args[0].getType()==TUnknown)?0:new ExtValue(args[0]);
380ExtValue *oldval=(ExtValue*)hash.put(args[1].getString(),newval);
381if (oldval) {*ret=*oldval; delete oldval;} else *ret=ExtValue();
382}
383
384SString DictionaryObject::serialize() const
385{
386SString out="{";
387        {
388        for(HashEntryIterator it(hash);it.isValid();)
389                {
390                out+="\"";
391                SString q=it->key; sstringQuote(q);
392                out+=q;
393                out+="\":";
394                if (it->value!=NULL)
395                        out+=((ExtValue*)it->value)->serialize();
396                else
397                        out+="null";
398                it++;
399                if (it.isValid()) out+=",";
400                }
401        }
402out+="}";
403return out;
404}
405
406void DictionaryObject::get_toString(ExtValue* ret)
407{
408SString out="{";
409//static SListTempl<DictionaryObject*> trace;
410if (tlsGetRef(VectorObject_tostring_trace).find(this)>=0)
411        out+="...";
412else
413        {
414        tlsGetRef(VectorObject_tostring_trace)+=this;
415        for(HashEntryIterator it(hash);it.isValid();)
416                {
417                out+=it->key;
418                out+=":";
419                if (it->value!=NULL)
420                        out+=((ExtValue*)it->value)->getString();
421                else
422                        out+="null";
423                it++;
424                if (it.isValid()) out+=",";
425                }
426        tlsGetRef(VectorObject_tostring_trace)-=this;
427        }
428out+="}";
429ret->setString(out);
430}
431
432DictionaryObject* DictionaryObject::fromObject(const ExtObject& o, bool warn)
433{
434return (DictionaryObject*)o.getTarget(par.getName(), true, warn);
435}
436
437////////////////
438
439VectorIterator::VectorIterator(VectorObject* v)
440{
441vec=v;
442vec->incref();
443pos=-1;
444}
445
446#define FIELDSTRUCT VectorIterator
447ParamEntry vectoriterator_paramtab[]=
448{
449 {"VectorIterator",1,2,"VectorIterator","VectorIterator"},
450{"next",0,PARAM_READONLY | PARAM_NOSTATIC,"next","d 0 1",GETONLY(next),},
451{"value",0,PARAM_READONLY | PARAM_NOSTATIC,"value","x",GETONLY(value),},
452{0,0,0,},
453};
454#undef FIELDSTRUCT
455
456ExtObject VectorIterator::makeFrom(VectorObject *v)
457{
458static Param par(vectoriterator_paramtab);
459return ExtObject(&par,new VectorIterator(v));
460}
461
462VectorIterator::~VectorIterator()
463{
464vec->decref();
465}
466
467void VectorIterator::get_next(ExtValue* ret)
468{
469pos++;
470ret->setInt((pos < vec->data.size()) ? 1 : 0);
471}
472
473void VectorIterator::get_value(ExtValue* ret)
474{
475ExtValue *v=(ExtValue*) (((pos>=0)&&(pos<vec->data.size())) ? vec->data(pos) : NULL );
476if (v)
477        *ret=*v;
478else
479        ret->setEmpty();
480}
Note: See TracBrowser for help on using the repository browser.