source: cpp/frams/util/extvalue.cpp @ 224

Last change on this file since 224 was 222, checked in by Maciej Komosinski, 11 years ago

"Distributed" deserializable class registry, so that ExtValue? does not depend on so many other classes

  • Property svn:eol-style set to native
File size: 18.7 KB
Line 
1// This file is a part of the Framsticks GDK.
2// Copyright (C) 1999-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.framsticks.com/ for further information.
4
5#include "extvalue.h"
6#include <frams/param/param.h>
7#include "sstringutils.h"
8#include <ctype.h>
9#include <frams/vm/classes/collectionobj.h>
10#include <frams/vm/classes/3dobject.h>
11#include <frams/vm/classes/genoobj.h>
12#include <common/nonstd_math.h>
13#include <common/Convert.h>
14
15#ifndef NO_BARRIER
16#include <frams/simul/barrier.h>
17#include <common/threads.h>
18#endif
19
20#ifdef MULTITHREADED
21#include <pthread.h>
22//this lock only protects against ref.counter corruption caused by concurrent reads.
23//read/write conficts and nonatomicity are handled by BarrierObject (at least in theory ;-))
24static pthread_mutex_t extobject_ref_lock=PTHREAD_MUTEX_INITIALIZER;
25#define REF_LOCK pthread_mutex_lock(&extobject_ref_lock)
26#define REF_UNLOCK pthread_mutex_unlock(&extobject_ref_lock)
27#else
28#define REF_LOCK
29#define REF_UNLOCK
30#endif
31
32void ExtObject::incref() const
33{
34if (subtype&1)
35        {
36        REF_LOCK;
37        dbobject->refcount++;
38        REF_UNLOCK;
39        }
40}
41
42void ExtObject::decref() const
43{
44if (subtype&1)
45        {
46        REF_LOCK;
47        bool destroy=!--dbobject->refcount;
48        REF_UNLOCK;
49        //another thread can now access the object while we are deleting it
50        //but this is not a bug since we only guarantee read/read safety
51        if (destroy) delete dbobject;
52        }
53}
54
55bool ExtObject::makeUnique()
56{
57if (!(subtype&1)) return false;
58if (dbobject->refcount==1) return false;
59VectorObject* v=VectorObject::fromObject(*this,false);
60if (v)
61        {
62        VectorObject* n=new VectorObject;
63        n->data.setSize(n->data.size());
64        for(int i=0;i<v->data.size();i++)
65                {
66                ExtValue *x=(ExtValue*)v->data(i);
67                n->data.set(i,x?new ExtValue(*x):NULL);
68                }
69        operator=(n->makeObject());
70        return true;
71        }
72return false;
73}
74
75void* ExtObject::getTarget(const char* classname, bool through_barrier, bool warn) const
76{
77if (!strcmp(interfaceName(),classname))
78        return getTarget();
79#ifndef NO_BARRIER
80if (through_barrier)
81        {
82        BarrierObject *bo=BarrierObject::fromObject(*this);
83        if (bo)
84                return bo->getSourceObject().getTarget(classname,true,warn);
85        }
86#endif
87
88if (warn)
89        {
90        FMprintf("ExtValue","getObjectTarget",FMLV_WARN,"%s object expected, %s found",classname,interfaceName());
91        }
92
93return NULL;
94}
95
96
97SString ExtObject::toString() const
98{
99if (isEmpty()) return SString("<empty object>");
100Param tmp_param;
101ParamInterface *p=getParamInterface(tmp_param);
102int tostr=p->findId("toString");
103if (tostr>=0)
104        {
105        return SString(p->getString(tostr));
106        }
107else
108        {
109        SString tmp("<");
110        tmp+=p->getName();
111        tmp+=SString::sprintf(" object at %p>",object?object:paraminterface);
112        return tmp;
113        }
114}
115
116THREAD_LOCAL_DEF(ExtObject::Serialization,ExtObject::serialization);
117
118void ExtObject::Serialization::begin()
119{
120if (level==0)
121        refs.clear();
122level++;
123}
124
125int ExtObject::Serialization::add(const ExtObject &o)
126{
127if (o.isEmpty()) return -1;
128for(int i=0;i<(int)refs.size();i++)
129        {
130        ExtObject& r=refs[i];
131        if (r==o) return i;
132        }
133refs.push_back(o);
134return -1;
135}
136
137void ExtObject::Serialization::replace(const ExtObject& o,const ExtObject& other)
138{
139if (o.isEmpty()) return;
140for(int i=0;i<(int)refs.size();i++)
141        {
142        ExtObject& r=refs[i];
143        if (r==o)
144                {
145                r=other;
146                return;
147                }
148        }
149}
150
151void ExtObject::Serialization::remove(const ExtObject& o)
152{
153if (o.isEmpty()) return;
154for(int i=0;i<(int)refs.size();i++)
155        {
156        ExtObject& r=refs[i];
157        if (o==r) refs.erase(refs.begin()+i);
158        }
159}
160
161const ExtObject* ExtObject::Serialization::get(int ref)
162{
163if (ref<0) return NULL;
164if (ref>=(int)refs.size()) return NULL;
165return &refs[ref];
166}
167
168void ExtObject::Serialization::end()
169{
170level--;
171if (level==0)
172        refs.clear();
173}
174
175SString ExtObject::serialize_inner() const
176{
177int ref=tlsGetRef(serialization).add(*this);
178if (ref>=0)
179        return SString::sprintf("^%d",ref);
180
181if (isEmpty()) return SString();
182VectorObject *vec=VectorObject::fromObject(*this,false);
183if (vec)
184        return vec->serialize();
185DictionaryObject *dic=DictionaryObject::fromObject(*this,false);
186if (dic)
187        return dic->serialize();
188Param tmp_param;
189ParamInterface *p=getParamInterface(tmp_param);
190int m=p->findId("toVector");
191if (m<0)
192        m=p->findId("toDictionary");
193if (m>=0)
194        {
195        ExtObject o(p->getObject(m));
196        SString ret=SString(interfaceName())+o.serialize();
197        return ret;
198        }
199m=p->findId("toString");
200if (m>=0)
201        {
202        SString str=p->getString(m);
203        sstringQuote(str);
204        SString ret=SString(interfaceName())+"\""+str+"\"";
205        return ret;
206        }
207
208tlsGetRef(serialization).remove(*this);//undo nonserializable reference
209SString ret=interfaceName();
210ret+=SString::sprintf("<%p>",object?object:paraminterface);
211return ret;
212}
213
214SString ExtObject::serialize() const
215{
216tlsGetRef(serialization).begin();
217SString ret=serialize_inner();
218tlsGetRef(serialization).end();
219return ret;
220}
221
222///////////////////////////////////////
223
224void *ExtValue::getObjectTarget(const char* classname,bool warn) const
225{
226if (type!=TObj)
227        {
228        if (warn)
229                {
230                SString tmp=getString();
231                if (tmp.len()>30) tmp=tmp.substr(0,30)+"...";
232                if (type==TString) tmp=SString("\"")+tmp+SString("\"");
233                FMprintf("ExtValue","getObjectTarget",FMLV_WARN,"%s object expected, %s found",classname,(const char*)tmp);
234                }
235        return NULL;
236        }
237
238return getObject().getTarget(classname,true,warn);
239}
240
241void ExtValue::set(const ExtValue& src)
242{
243switch(src.type)
244        {
245        case TString: sets(src.sdata()); break;
246        case TInt: seti(src.idata()); break;
247        case TDouble: setd(src.ddata()); break;
248        case TObj: seto(src.odata()); break;
249        default:type=src.type; break;
250        }
251}
252
253void ExtValue::setEmpty()
254{
255switch(type)
256        {
257#ifdef EXTVALUEUNION
258        case TString: sdata().~SString(); break;
259        case TObj: odata().~ExtObject(); break;
260#else
261        case TString: delete s; break;
262        case TObj: delete o; break;
263#endif
264        default:;
265        }
266type=TUnknown;
267}
268
269static long longsign(long x)
270{
271if (x<0) return -1;
272if (x>0) return 1;
273return 0;
274}
275
276static long compareNull(const ExtValue& v)
277{
278switch(v.type)
279        {
280        case TDouble: return v.getDouble()!=0.0;
281        case TInt: return v.getInt()?1:0;
282        case TString: return 1;
283        default: return !v.isNull();
284        }
285}
286
287long ExtValue::compare(const ExtValue& src) const
288{
289if (type==TUnknown)
290        return compareNull(src);
291else if (src.type==TUnknown)
292        return compareNull(*this);
293switch(type)
294        {
295        case TInt:
296        {
297        long t=src.getInt();
298        if (idata()>0)
299                {if (t>0) return longsign(idata()-t); else return +1;}
300        else
301                {if (t<=0) return longsign(idata()-t); else return -1;}
302        }
303        case TDouble:
304                {
305                double t=ddata()-src.getDouble();
306                if (t<0) return -1;
307                else if (t>0) return 1;
308                return 0;
309                }
310        case TString:
311        {
312        SString t=src.getString();
313        SString& t2=sdata();
314        const char* s1=(const char*)t2;
315        const char* s2=(const char*)t;
316        return longsign(strcmp(s1,s2));
317        }
318        case TObj:
319        {
320        if (src.type==TObj)
321                return !(odata()==src.odata());
322        return 1;
323        }
324        default:;
325        }
326return 1;
327}
328
329int ExtValue::operator==(const ExtValue& src) const
330{
331if (type!=src.type) return 0;
332switch(type)
333        {
334        case TInt: return idata()==src.idata();
335        case TDouble: return ddata()==src.ddata();
336        case TString: return sdata()==src.sdata();
337        case TObj: return odata()==src.odata();
338        default:;
339        }
340return 1;
341}
342
343void ExtValue::operator+=(const ExtValue& src)
344{
345switch(type)
346        {
347        case TInt: idata()+=src.getInt(); break;
348        case TDouble: ddata()+=src.getDouble(); break;
349        case TString: sdata()+=src.getString(); break;
350        case TObj:
351                {
352                VectorObject *vec=VectorObject::fromObject(getObject(),false);
353                VectorObject *vec2=VectorObject::fromObject(src.getObject(),false);
354                if (vec && vec2)
355                        {
356                        for(int i=0;i<vec2->data.size();i++)
357                                {
358                                ExtValue *s=(ExtValue*)vec2->data(i);
359                                ExtValue *d=s?new ExtValue(*s):NULL;
360                                vec->data+=d;
361                                }
362                        }
363                }
364        default:;
365        }
366}
367
368void ExtValue::operator-=(const ExtValue& src)
369{
370switch(type)
371        {
372        case TInt: idata()-=src.getInt(); break;
373        case TDouble: ddata()-=src.getDouble(); break;
374        default:;
375        }
376}
377
378void ExtValue::operator*=(const ExtValue& src)
379{
380switch(type)
381        {
382        case TInt: idata()*=src.getInt(); break;
383        case TDouble: ddata()*=src.getDouble(); break;
384        case TString:
385        {
386        SString t;
387        for(int n=src.getInt();n>0;n--)
388                t+=getString();
389        setString(t);
390        break;
391        }
392        case TObj:
393                {
394                VectorObject *vec=VectorObject::fromObject(getObject(),false);
395                if (vec)
396                        {
397                        int n=src.getInt();
398                        int orig_size=vec->data.size();
399                        if (n<=0)
400                                {vec->clear();return;}
401                        for(;n>1;n--)
402                                {
403                                for(int i=0;i<orig_size;i++)
404                                        {
405                                        ExtValue *s=(ExtValue*)vec->data(i);
406                                        ExtValue *d=s?new ExtValue(*s):NULL;
407                                        vec->data+=d;
408                                        }
409                                }
410                        }
411                break;
412                }
413        default:;
414        }
415}
416
417#include <common/framsg.h>
418/*#include "fpu_control.h"
419#include <signal.h>
420
421static int fpuexception;
422void mathhandler(int sig)
423{
424printf("fpu exception!\n");
425fpuexception=1;
426signal(SIGFPE,SIG_IGN);
427} */
428
429void ExtValue::operator/=(const ExtValue& src)
430{
431switch(type)
432        {
433        case TInt:
434        { int a=src.getInt();
435//              idata()/=src.getInt();
436        if (a) idata()/=a;
437        else {FMprintf("ExtValue","divide",FMLV_CRITICAL,"%d/0",idata()); setInvalid();}
438        }
439                break;
440
441        case TDouble:
442                {
443                double d=src.getDouble();
444                if (d==0.0)
445                        {
446                        FMprintf("ExtValue","divide",FMLV_CRITICAL,"%s/0.0",(const char*)getString());
447                        setInvalid();
448                        }
449                else
450                        {
451                        fpExceptDisable();
452                        double tmp=ddata()/d;
453                        if (!finite(tmp))
454                                { FMprintf("ExtValue","divide",FMLV_CRITICAL,"overflow %s/%s",(const char*)getString(),(const char*)src.getString()); setInvalid(); }
455                        else
456                                ddata()=tmp;
457                        // niby dobrze ale lepiej byloby to robic bardziej systematycznie a nie tylko w dzieleniu?
458                        //if (isnan(ddata())) //http://www.digitalmars.com/d/archives/c++/Traping_divide_by_zero_5728.html
459                        //        { FMprintf("ExtValue","divide",FMLV_ERROR,"not-a-number",(const char*)getString()); setInvalid(); }
460                        fpExceptEnable();
461                        }
462                }
463                break;
464
465        default:;
466        }
467}
468
469SString ExtValue::format(SString& fmt,const ExtValue **values,int count)
470{
471SString ret;
472// "..........%.........%..........%........"
473//  ^_cur     ^_next
474//  ^^^^^^^^^^___sub
475//
476// "..........%.........%..........%........"
477//            ^-cur     ^-next
478//            ^^^^^^^^^^___sub
479const char* begin=(const char*)fmt, *end=begin+fmt.len(), *curr=begin;
480int type=0;
481
482class Args
483{
484const ExtValue **values;
485int count;
486int arg;
487public:
488Args(const ExtValue **v,int c):values(v),count(c),arg(0) {}
489bool finished() {return arg>=count;}
490const ExtValue *getNext() {const ExtValue *ret=NULL; if ((arg<count)&&values[arg]) ret=values[arg]; arg++; return ret;}
491};
492Args args(values,count);
493
494while(curr<end)
495        {
496        const char* next=strchr(curr,'%');
497        if (!next) next=end; else if ((next==curr)&&(curr>begin))
498                {next=strchr(next+1,'%'); if (!next) next=end;}
499        type=0;
500        if (curr>begin)
501                {
502                type=0;
503                for(const char* t=curr;t<next;t++)
504                        switch(*t)
505                                {
506                                case 'd': case 'x': case 'X': case 'u': case 'p': case 'c': type='d'; t=next; break;
507                                case 'f': case 'g': case 'e': type='f'; t=next; break;
508                                case 's': type='s'; t=next; break;
509                                case 't': case 'T': type=*t; t=next; break;
510                                case '%': if (t>begin) {type=*t; t=next;} break;
511                                }
512                }
513        if (curr>begin) curr--;
514        const ExtValue *a;
515        if (args.finished() && (type!=0) && (type!='%'))
516                {
517                ret+=fmt.substr(curr-begin);
518                break;
519                }
520        SString sub=fmt.substr(curr-begin,next-curr);
521        switch(type)
522                {
523                case 'd': a=args.getNext(); ret+=SString::sprintf((const char*)sub,a?a->getInt():0); break;
524                case 'f': a=args.getNext(); ret+=SString::sprintf((const char*)sub,a?a->getDouble():0); break;
525                case 's': {a=args.getNext(); SString tmp; if (a) tmp=a->getString(); ret+=SString::sprintf((const char*)sub,(const char*)tmp);} break;
526                case 't': case 'T':
527                        {
528                        a=args.getNext();
529                        time_t ti=a?a->getInt():0;
530                        struct tm tm=Convert::localtime(ti);
531                        SString timtxt;
532                        if (type=='T')
533                                timtxt=SString::sprintf("%04d-%02d-%02d %02d:%02d:%02d",1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec);
534                        else
535                                timtxt=Convert::asctime(tm).c_str();
536                        ret+=timtxt;
537                        ret+=sub.substr(2);
538                        }
539                        break;
540                case '%': ret+='%'; ret+=sub.substr(2); break;
541                case 0: ret+=sub; break;
542                }
543        curr=next+1;
544        }
545return ret;
546}
547
548
549void ExtValue::operator%=(const ExtValue& src)
550{
551switch(type)
552        {
553        case TInt: idata()=idata()%src.getInt(); break;
554        case TDouble: ddata()=fmod(ddata(),src.getDouble()); break;
555
556        case TString:
557        {
558        VectorObject *vec=VectorObject::fromObject(src.getObject(),false);
559        if (vec)
560                sdata()=format(sdata(),(const ExtValue**)&vec->data.getref(0),vec->data.size());
561        else
562                {const ExtValue *ptr=&src; sdata()=ExtValue::format(sdata(),&ptr,1);}
563        }
564        break;
565
566        default:;
567        }
568}
569
570long ExtValue::getInt(const char* s)
571{
572if ((s[0]=='0')&&(s[1]=='x'))
573        {
574        long val;
575        sscanf(s+2,"%lx",&val);
576        return val;
577        }
578else
579        {
580        if (strchr(s,'e')||(strchr(s,'E')))
581                return (long)atof(s);
582        else
583                return atol(s);
584        }
585}
586
587double ExtValue::getDouble(const char* s)
588{
589if ((s[0]=='0')&&(s[1]=='x'))
590        {
591        long val;
592        sscanf(s+2,"%lx",&val);
593        return val;
594        }
595else
596        return atof(s);
597}
598
599long ExtValue::getInt() const
600{
601switch(type)
602        {
603        case TInt: return idata();
604        case TDouble: return (int)ddata();
605        case TString: return getInt((const char*)sdata());
606        case TObj:
607                FMprintf("ExtValue","getInt",FMLV_WARN,"Getting integer value from object reference (%s)",(const char*)getString());
608                return (long)odata().param;
609        default:;
610        }
611return 0;
612}
613
614double ExtValue::getDouble() const
615{
616switch(type)
617        {
618        case TDouble: return ddata();
619        case TInt: return (double)idata();
620        case TString: return getDouble((const char*)sdata());
621        case TObj:
622                FMprintf("ExtValue","getDouble",FMLV_WARN,"Getting floating point value from object reference (%s)",(const char*)getString());
623                return (double)(long)odata().param;
624        default:;
625        }
626return 0.0;
627}
628SString ExtValue::getString() const
629{
630switch(type)
631        {
632        case TString: return sdata();
633        case TInt: return SString::valueOf(idata());
634        case TDouble: return SString::valueOf(ddata());
635        case TObj: return odata().toString();
636        case TInvalid:  return SString("invalid");
637        default: return SString("null");
638        }
639}
640
641const SString* ExtValue::getStringPtr() const
642{
643if (type==TString)
644        return &sdata();
645return NULL;
646}
647
648SString ExtValue::serialize() const
649{
650switch(type)
651        {
652        case TString:
653                {
654                SString q=sdata();
655                sstringQuote(q);
656                return SString("\"")+q+SString("\"");
657                }
658        case TInt:
659                return SString::valueOf(idata());
660        case TDouble:
661                return SString::valueOf(ddata());
662        case TObj:
663                return odata().serialize();
664        case TInvalid:
665                return SString("invalid");
666        default:
667                return SString("null");
668        }
669}
670
671//returns the first character after the parsed number or NULL if not a number
672const char* ExtValue::parseNumber(const char* in)
673{
674if (isdigit(*in)||((*in=='-')&&(isdigit(in[1]))))
675        {
676        const char* p=in;
677        if (*p=='-') p++;
678        while(isdigit(*p)) p++;
679        bool fp=false;
680        if ((*p=='.') && isdigit(p[1]))
681                {
682                p++;
683                while(isdigit(*p)) p++;
684                fp=true;
685                }
686        if (((*p=='e')||(*p=='E')) && (isdigit(p[1]) || (((p[1]=='-') || (p[1]=='+')) && isdigit(p[2]))))
687                {
688                p++;
689                if ((*p=='-')||(*p=='+')) p++;
690                while(isdigit(*p)) p++;
691                fp=true;
692                }
693
694        if (fp)
695                {
696                setDouble(atof(in));
697                return p;
698                }
699        else
700                {
701                setInt(atol(in));
702                return p;
703                }
704        }
705return NULL;
706}
707
708PtrListTempl<ParamInterface*> &ExtValue::getDeserializableClasses()
709{
710static PtrListTempl<ParamInterface*> classes;
711return classes;
712}
713
714ParamInterface *ExtValue::findDeserializableClass(const char* name)
715{
716FOREACH(ParamInterface*,cls,getDeserializableClasses())
717        if (!strcmp(cls->getName(),name))
718                return cls;
719return NULL;
720}
721
722static const char* skipWord(const char* in)
723{
724while(isalpha(*in)||(*in=='_'))
725        in++;
726return in;
727}
728
729//returns the first character after the parsed portion or NULL if invalid format
730const char* ExtValue::deserialize_inner(const char* in)
731{
732const char* ret=parseNumber(in);
733if (ret)
734        return ret;
735else if (*in=='\"')
736        {
737        ret=skipQuoteString(in+1,NULL);
738        SString s(in+1,ret-(in+1));
739        sstringUnquote(s);
740        setString(s);
741        if (*ret=='\"')
742                return ret+1;
743        else
744                return NULL;
745        }
746else if (*in=='[')
747        {
748        VectorObject *vec=new VectorObject;
749        ExtObject o(&VectorObject::par,vec);
750        tlsGetRef(ExtObject::serialization).add(o);
751        const char* p=in+1;
752        ExtValue tmp;
753        while(*p)
754                {
755                if (*p==']') {p++;break;}
756                ret=tmp.deserialize(p);
757                if (ret)
758                        {
759                        vec->data+=new ExtValue(tmp);
760                        p=ret;
761                        if (*p==',') p++;
762                        }
763                else
764                        {
765                        p=NULL;
766                        break;
767                        }
768                }
769        setObject(o);
770        return p;
771        }
772else if (*in=='{')
773        {
774        DictionaryObject *dic=new DictionaryObject;
775        ExtObject o(&DictionaryObject::par,dic);
776        tlsGetRef(ExtObject::serialization).add(o);
777        const char* p=in+1;
778        ExtValue args[2]/*={value,key}*/, dummy_ret;
779        while(*p)
780                {
781                if (*p=='}') {p++;break;}
782                ret=args[1].deserialize(p);
783                if ((!ret)||(args[1].getType()!=TString)) {p=NULL;break;}
784                p=ret;
785                if (*p!=':') {p=NULL;break;}
786                p++;
787                ret=args[0].deserialize(p);
788                if (!ret) {p=NULL;break;}
789                p=ret;
790                dic->p_set(args,&dummy_ret);
791                if (*p==',') p++;
792                }
793        setObject(o);
794        return p;
795        }
796else if (!strncmp(in,"null",4))
797        {
798        setEmpty();
799        return in+4;
800        }
801else if (!strncmp(in,"invalid",9))
802        {
803        setInvalid();
804        return in+9;
805        }
806else if (*in=='<')
807        { //unserializable object
808        setInvalid();
809        while(*in)
810                if (*in=='>')
811                        return in+1;
812                else in++;
813        return in;
814        }
815else if (*in=='^')
816        {
817        in++;
818        ExtValue ref;
819        ret=ref.parseNumber(in);
820        if (ret && (ref.getType()==TInt))
821                {
822                const ExtObject* o=tlsGetRef(ExtObject::serialization).get(ref.getInt());
823                if (o)
824                        {
825                        setObject(*o);
826                        return ret;
827                        }
828                }
829        return NULL;
830        }
831else if ((ret=skipWord(in))&&(ret!=in))
832        {
833        SString clsname(in,ret-in);
834        ExtValue tmp;
835        ret=tmp.deserialize(ret);
836        ParamInterface *cls=findDeserializableClass(clsname);
837        if (cls && (tmp.getType()!=TUnknown) && (tmp.getType()!=TInvalid))
838                {
839                VectorObject *vec=VectorObject::fromObject(tmp.getObject(),false);
840                if (vec)
841                        {
842                        int m=cls->findId("newFromVector");
843                        if (m>=0)
844                                {
845                                cls->call(m,&tmp,this);
846                                tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
847                                return ret;
848                                }
849                        }
850                DictionaryObject *dic=DictionaryObject::fromObject(tmp.getObject(),false);
851                if (dic)
852                        {
853                        int m=cls->findId("newFromDictionary");
854                        if (m>=0)
855                                {
856                                cls->call(m,&tmp,this);
857                                tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
858                                return ret;
859                                }
860                        }
861                if (tmp.getType()==TString)
862                        {
863                        int m=cls->findId("newFromString");
864                        if (m>=0)
865                                {
866                                cls->call(m,&tmp,this);
867                                tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
868                                return ret;
869                                }
870                        }
871                tlsGetRef(ExtObject::serialization).remove(tmp.getObject());
872                setEmpty();
873                }
874        setEmpty();
875        FMprintf("ExtValue","deserialize",FMLV_WARN,"object of class \"%s\" could not be deserialized",(const char*)clsname);
876        return ret;
877        }
878setEmpty();
879return NULL;
880}
881
882const char* ExtValue::deserialize(const char* in)
883{
884tlsGetRef(ExtObject::serialization).begin();
885const char* ret=deserialize_inner(in);
886tlsGetRef(ExtObject::serialization).end();
887return ret;
888}
889
890ExtObject ExtValue::getObject() const
891{
892if (type==TObj) return odata();
893return ExtObject();
894}
895
896ExtValue ExtValue::getExtType()
897{
898if (getType()!=TObj) return ExtValue((long)getType());
899ExtObject& o=odata();
900return ExtValue(SString(o.isEmpty()?"":o.interfaceName()));
901}
902
903SString SString::valueOf(const ExtValue& v)
904{
905return v.getString();
906}
907SString SString::valueOf(const ExtObject& v)
908{
909return v.toString();
910}
Note: See TracBrowser for help on using the repository browser.