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

Last change on this file since 420 was 409, checked in by Maciej Komosinski, 9 years ago

Improved documentation

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