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

Last change on this file since 222 was 222, checked in by Maciej Komosinski, 9 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.