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

Last change on this file since 109 was 109, checked in by sz, 10 years ago

source reorganization (see README)
new feature added: part/joint shapes (see frams/_demos/part_shapes.cpp)

  • Property svn:eol-style set to native
File size: 11.2 KB
RevLine 
[109]1// This file is a part of the Framsticks GDK library.
2// Copyright (C) 2002-2011  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,"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,"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        }
79//nie tak spektakularny jak rasowe bugi roku ale tez idiotyczny :>
80//wszystko przez to ze poczatkowo bylo tylko uzywane w destruktorze...
81data.clear();
82}
83
84void VectorObject::p_remove(PARAMPROCARGS)
85{
86if (readonly) return;
87int i=args->getInt();
88if ((i<0)||(i>=data.size())) return;
89ExtValue *v=(ExtValue*)data.get(i);
90if (v) delete v;
91data-=i;
92}
93
94void VectorObject::set(int i,const ExtValue& val)
95{
96int oldsize=data.size();
97if (i<0) return;
98ExtValue *v=(ExtValue*)data.get(i);
99if (v) delete v;
100data.set(i,new ExtValue(val));
101i--;
102while(i>=oldsize)
103        {
104        data.set(i,0);
105        i--;
106        }
107}
108
109void VectorObject::p_get(PARAMPROCARGS)
110{
111int i=args->getInt();
112if (listIndexCheck(&data,i,"VectorObject","get"))
113        {
114        ExtValue *v=get(i);
115        if (v)
116                {
117                *ret=*v;
118                return;
119                }
120        }
121*ret=ExtValue();
122}
123
124void VectorObject::get_avg(ExtValue* ret)
125{
126if (!data.size()) {ret->setEmpty(); return;}
127double s=0.0;
128for(int i=data.size()-1;i>=0;i--)
129        s+=((ExtValue*)data.get(i))->getDouble();
130s/=data.size();
131ret->setDouble(s);
132}
133
134SString VectorObject::serialize() const
135{
136SString out="[";
137        {
138        for(int i=0;i<data.size();i++)
139                {
140                ExtValue* v=(ExtValue*)data.get(i);
141                if (i) out+=",";
142                if (v)
143                        out+=v->serialize();
144                else
145                        out+="null";
146                }
147        }
148out+="]";
149//sprintf(out.directAppend(20),"<Vector@%p>",this);out.endAppend();
150return out;
151}
152
153static THREAD_LOCAL_DEF(SList,tostring_trace);
154
155void VectorObject::get_toString(ExtValue* ret)
156{
157SString out="[";
158//static SListTempl<VectorObject*> trace;
159if (tlsGetRef(tostring_trace).find(this)>=0)
160        out+="...";
161else
162        {
163        tlsGetRef(tostring_trace)+=this;
164        for(int i=0;i<data.size();i++)
165                {
166                ExtValue* v=(ExtValue*)data.get(i);
167                if (i) out+=",";
168                if (v)
169                        out+=v->getString();
170                else
171                        out+="null";
172                }
173        tlsGetRef(tostring_trace)-=this;
174        }
175out+="]";
176ret->setString(out);
177}
178
179void VectorObject::get_stdev(ExtValue* ret)
180{
181if (!data.size()) {ret->setEmpty(); return;}
182get_avg(ret);
183double a=ret->getDouble();
184double s=0.0;
185for(int i=data.size()-1;i>=0;i--)
186        {
187        double d=a-((ExtValue*)data.get(i))->getDouble();
188        s+=d*d;
189        }
190ret->setDouble(sqrt(s/max(1,data.size()-1)));
191}
192
193void VectorObject::p_find(PARAMPROCARGS)
194{
195short i;
196for(i=0;i<data.size();i++)
197        {
198        if ((*args)==(*get(i)))
199                {ret->setInt(i);return;}
200        }
201ret->setInt(-1);
202}
203
204class VEComparator
205{
206public:
207bool operator()(const ExtValue *a,const ExtValue *b) {return a->compare(*b)<0;}
208};
209
210#ifndef NO_VMACHINE
211class VMVEComparator
212{
213public:
214VMachine::JumpTargetObject *jto;
215VMachine *vm;
216VMVEComparator(VMachine::JumpTargetObject *_jto):jto(_jto),vm(jto->vm) {}
217bool operator()(const ExtValue *a,const ExtValue *b);
218};
219
220bool VMVEComparator::operator()(const ExtValue *a,const ExtValue *b)
221{
222if (!VMCode::prepareDynamicJumpTarget(jto->pc,jto->code))
223        return false;
224
225vm->push(*a);
226vm->push(*b);
227vm->pushNewCallState();
228vm->jumpDynamicJumpTarget(jto->pc);
229vm->run();
230vm->popCallState();
231bool ret;
232ExtValue& retval=vm->getValue();
233if (retval.type==TInvalid)
234        {
235        ret=false;
236        FMprintf("VectorElementComparator","",FMLV_ERROR,"Comparison function returned no value");
237        }
238else
239        ret=(retval.getInt()!=0);
240vm->drop(2);
241return ret;
242}
243#endif
244
245void VectorObject::p_sort(PARAMPROCARGS)
246{
247#ifndef NO_VMACHINE
248VMachine::JumpTargetObject *jto=VMachine::JumpTargetObject::fromObject(args->getObject());
249if (jto)
250        {
251        VMVEComparator cmp(jto);
252        ExtValue **first=(ExtValue**)&data.getref();
253        std::sort(first,first+data.size(),cmp);
254        }
255else
256#endif
257        {
258        VEComparator cmp;
259        ExtValue **first=(ExtValue**)&data.getref();
260        std::sort(first,first+data.size(),cmp);
261        }
262ret->setEmpty();
263}
264
265void VectorObject::get_iterator(ExtValue* ret)
266{
267ret->setObject(VectorIterator::makeFrom(this));
268}
269
270VectorObject* VectorObject::fromObject(const ExtObject& o)
271{
272return (VectorObject*)o.getTarget(par.getName());
273}
274
275/////////////////////////////
276
277void DictionaryObject::clear()
278{
279for(HashEntryIterator it(hash);it.isValid();)
280        {
281        ExtValue *v=(ExtValue*)hash.remove(it);
282        if (v) delete v;
283        }
284hash.clear();
285hash.init();
286}
287
288void DictionaryObject::p_find(PARAMPROCARGS)
289{
290for(HashEntryIterator it(hash);it.isValid();it++)
291        {
292        if ((*args)==(*((ExtValue*)it->value)))
293                {
294                ret->setString(it->key);
295                return;
296                }
297        }
298ret->setEmpty();
299}
300
301HashEntryIterator* DictionaryObject::getIndexIterator(int i)
302{
303if (i<0) return 0;
304if (i>=hash.getSize()) return 0;
305
306if ((!it.isValid())||(it_index>i))
307        {
308        it=HashEntryIterator(hash);
309        it_index=0;
310        }
311while(it.isValid())
312        {
313        if (it_index==i)
314                return &it;
315        it_index++;
316        it++;
317        }
318return 0;
319}
320
321void DictionaryObject::p_remove(PARAMPROCARGS)
322{
323if ((args->type==TInt)||(args->type==TDouble))
324        {
325        HashEntryIterator* iter=getIndexIterator(args->getInt());
326        if (iter)
327                {
328                ExtValue *oldval=(ExtValue*)hash.remove(*iter);
329                if (oldval) {*ret=*oldval; delete oldval;} else *ret=ExtValue();
330                }
331        }
332else
333        {
334        ExtValue *oldval=(ExtValue*)hash.remove(args[0].getString());
335        if (oldval) {*ret=*oldval; delete oldval;} else *ret=ExtValue();
336        }
337}
338
339void DictionaryObject::p_get(PARAMPROCARGS)
340{
341if ((args->type==TInt)||(args->type==TDouble))
342        {
343        HashEntryIterator* iter=getIndexIterator(args->getInt());
344        if (iter && (*iter)->value)
345                {
346                *ret=*((ExtValue*)(*iter)->value);
347                return;
348                }
349        }
350else
351        {
352        ExtValue *val=(ExtValue*)hash.get(args[0].getString());
353        if (val)
354                {
355                *ret=*val;
356                return;
357                }
358        }
359*ret=ExtValue();
360}
361
362void DictionaryObject::p_getKey(PARAMPROCARGS)
363{
364HashEntryIterator* iter=getIndexIterator(args->getInt());
365if (iter)
366        {
367        *ret=(*iter)->key;
368        return;
369        }
370*ret=ExtValue();
371}
372
373void DictionaryObject::p_set(PARAMPROCARGS)
374{
375ExtValue *newval=(args[0].getType()==TUnknown)?0:new ExtValue(args[0]);
376ExtValue *oldval=(ExtValue*)hash.put(args[1].getString(),newval);
377if (oldval) {*ret=*oldval; delete oldval;} else *ret=ExtValue();
378}
379
380SString DictionaryObject::serialize() const
381{
382SString out="{";
383        {
384        for(HashEntryIterator it(hash);it.isValid();)
385                {
386                out+="\"";
387                SString q=it->key; sstringQuote(q);
388                out+=q;
389                out+="\":";
390                out+=((ExtValue*)it->value)->serialize();
391                it++;
392                if (it.isValid()) out+=",";
393                }
394        }
395out+="}";
396return out;
397}
398
399void DictionaryObject::get_toString(ExtValue* ret)
400{
401SString out="{";
402//static SListTempl<DictionaryObject*> trace;
403if (tlsGetRef(tostring_trace).find(this)>=0)
404        out+="...";
405else
406        {
407        tlsGetRef(tostring_trace)+=this;
408        for(HashEntryIterator it(hash);it.isValid();)
409                {
410                out+=it->key;
411                out+=":";
412                out+=((ExtValue*)it->value)->getString();
413                it++;
414                if (it.isValid()) out+=",";
415                }
416        tlsGetRef(tostring_trace)-=this;
417        }
418out+="}";
419ret->setString(out);
420}
421
422DictionaryObject* DictionaryObject::fromObject(const ExtObject& o)
423{
424return (DictionaryObject*)o.getTarget(par.getName());
425}
426
427////////////////
428
429VectorIterator::VectorIterator(VectorObject* v)
430{
431vec=v;
432vec->incref();
433pos=-1;
434}
435
436#define FIELDSTRUCT VectorIterator
437ParamEntry vectoriterator_paramtab[]=
438{
439 {"VectorIterator",1,2,"VectorIterator","VectorIterator"},
440{"next",0,PARAM_READONLY+PARAM_NOSTATIC,"next","d 0 1",GETONLY(next),},
441{"value",0,PARAM_READONLY+PARAM_NOSTATIC,"value","x",GETONLY(value),},
442{0,0,0,},
443};
444#undef FIELDSTRUCT
445
446ExtObject VectorIterator::makeFrom(VectorObject *v)
447{
448static Param par(vectoriterator_paramtab);
449return ExtObject(&par,new VectorIterator(v));
450}
451
452VectorIterator::~VectorIterator()
453{
454vec->decref();
455}
456
457void VectorIterator::get_next(ExtValue* ret)
458{
459pos++;
460ret->setInt((pos < vec->data.size()) ? 1 : 0);
461}
462
463void VectorIterator::get_value(ExtValue* ret)
464{
465ExtValue *v=(ExtValue*) (((pos>=0)&&(pos<vec->data.size())) ? vec->data(pos) : NULL );
466if (v)
467        *ret=*v;
468else
469        ret->setEmpty();
470}
Note: See TracBrowser for help on using the repository browser.