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

Last change on this file since 144 was 144, checked in by sz, 7 years ago

Param and ExtValue? improvements (better control on conversions, "load" returns the number of loaded fields)

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