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

Last change on this file since 132 was 127, checked in by sz, 11 years ago

bug fixed: all param items having GETONLY accessor must also have PARAM_READONLY flag

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