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

Last change on this file since 144 was 144, checked in by sz, 10 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.