Changeset 104 for cpp/gdk/extvalue.cpp


Ignore:
Timestamp:
07/23/13 18:15:30 (11 years ago)
Author:
sz
Message:

introducing object de/serialization - see serialtest.cpp
the core GDK classes can be now used in multiple threads (ifdef MULTITHREADED)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpp/gdk/extvalue.cpp

    r92 r104  
    55#include "extvalue.h"
    66#include "param.h"
     7#include "sstringutils.h"
    78#include <math.h>
     9#include <ctype.h>
     10#include "collectionobj.h"
     11#include "3dobject.h"
    812
    913SString ExtObject::toString() const
    1014{
    1115if (isEmpty()) return SString("<empty object>");
    12 ParamInterface *p=getParamInterface();
     16Param tmp_param;
     17ParamInterface *p=getParamInterface(tmp_param);
    1318int tostr=p->findId("toString");
    1419if (tostr>=0)
     
    2530        return tmp;
    2631        }
     32}
     33
     34ThreadSingleton<ExtObject::Serialization> ExtObject::serialization;
     35
     36void ExtObject::Serialization::begin()
     37{
     38if (level==0)
     39        refs.clear();
     40level++;
     41}
     42
     43int ExtObject::Serialization::add(const ExtObject &o)
     44{
     45if (o.isEmpty()) return -1;
     46for(int i=0;i<refs.size();i++)
     47        {
     48        ExtObject& r=refs[i];
     49        if (r==o) return i;
     50        }
     51refs.push_back(o);
     52return -1;
     53}
     54
     55void ExtObject::Serialization::replace(const ExtObject& o,const ExtObject& other)
     56{
     57if (o.isEmpty()) return;
     58for(int i=0;i<refs.size();i++)
     59        {
     60        ExtObject& r=refs[i];
     61        if (r==o)
     62                {
     63                r=other;
     64                return;
     65                }
     66        }
     67}
     68
     69void ExtObject::Serialization::remove(const ExtObject& o)
     70{
     71if (o.isEmpty()) return;
     72for(int i=0;i<refs.size();i++)
     73        {
     74        ExtObject& r=refs[i];
     75        if (o==r) refs.erase(refs.begin()+i);
     76        }
     77}
     78
     79const ExtObject* ExtObject::Serialization::get(int ref)
     80{
     81if (ref<0) return NULL;
     82if (ref>=refs.size()) return NULL;
     83return &refs[ref];
     84}
     85
     86void ExtObject::Serialization::end()
     87{
     88level--;
     89if (level==0)
     90        refs.clear();
     91}
     92
     93SString ExtObject::serialize_inner() const
     94{
     95int ref=serialization.getref().add(*this);
     96if (ref>=0)
     97        {
     98        SString ret;
     99        sprintf(ret.directAppend(20),"^%d",ref);ret.endAppend();
     100        return ret;
     101        }
     102
     103if (isEmpty()) return SString();
     104VectorObject *vec=VectorObject::fromObject(*this);
     105if (vec)
     106        return vec->serialize();
     107DictionaryObject *dic=DictionaryObject::fromObject(*this);
     108if (dic)
     109        return dic->serialize();
     110Param tmp_param;
     111ParamInterface *p=getParamInterface(tmp_param);
     112int m=p->findId("toVector");
     113if (m<0)
     114        m=p->findId("toDictionary");
     115if (m>=0)
     116        {
     117        ExtObject o(p->getObject(m));
     118        SString ret=SString(interfaceName())+o.serialize();
     119        return ret;
     120        }
     121m=p->findId("toString");
     122if (m>=0)
     123        {
     124        SString str=p->getString(m);
     125        sstringQuote(str);
     126        SString ret=SString(interfaceName())+"\""+str+"\"";
     127        return ret;
     128        }
     129
     130SString ret=interfaceName();
     131sprintf(ret.directAppend(30),"<%p>",object?object:paraminterface);ret.endAppend();
     132return ret;
     133}
     134
     135SString ExtObject::serialize() const
     136{
     137serialization.getref().begin();
     138SString ret=serialize_inner();
     139serialization.getref().end();
     140return ret;
    27141}
    28142
     
    297411}
    298412
     413SString ExtValue::serialize() const
     414{
     415switch(type)
     416        {
     417        case TString:
     418                {
     419                SString q=sdata();
     420                sstringQuote(q);
     421                return SString("\"")+q+SString("\"");
     422                }
     423        case TInt:
     424                {
     425                SString tmp;
     426                sprintf(tmp.directAppend(20),"%d",idata());
     427                tmp.endAppend();
     428                return tmp;
     429                }
     430        case TDouble:
     431                {
     432                SString tmp;
     433                sprintf(tmp.directAppend(20),"%.15g",ddata());
     434                tmp.endAppend();
     435                if ((!strchr(tmp,'.'))&&(!strchr(tmp,'e'))) tmp+=".0";
     436                return tmp;
     437                }
     438        case TObj:
     439                return odata().serialize();
     440        case TInvalid:
     441                return SString("undefined");
     442        default:
     443                return SString("null");
     444        }
     445}
     446
     447//returns the first character after the parsed number or NULL if not a number
     448const char* ExtValue::parseNumber(const char* in)
     449{
     450if (isdigit(*in)||((*in=='-')&&(isdigit(in[1]))))
     451        {
     452        const char* p=in;
     453        if (*p=='-') p++;
     454        while(isdigit(*p)) p++;
     455        bool fp=false;
     456        if ((*p=='.') && isdigit(p[1]))
     457                {
     458                p++;
     459                while(isdigit(*p)) p++;
     460                fp=true;
     461                }
     462        if (((*p=='e')||(*p=='E')) && (isdigit(p[1]) || (((p[1]=='-') || (p[1]=='+')) && isdigit(p[2]))))
     463                {
     464                p++;
     465                if ((*p=='-')||(*p=='+')) p++;
     466                while(isdigit(*p)) p++;
     467                fp=true;
     468                }
     469
     470        if (fp)
     471                {
     472                setDouble(atof(in));
     473                return p;
     474                }
     475        else
     476                {
     477                setInt(atol(in));
     478                return p;
     479                }
     480        }
     481return NULL;
     482}
     483
     484PtrListTempl<ParamInterface*> ExtValue::deserializable_classes;
     485
     486void ExtValue::initDeserializableClasses()
     487{
     488deserializable_classes+=&Pt3D_Ext::getStaticParam();
     489deserializable_classes+=&Orient_Ext::getStaticParam();
     490}
     491
     492ParamInterface *ExtValue::findDeserializableClass(const char* name)
     493{
     494FOREACH(ParamInterface*,cls,deserializable_classes)
     495        if (!strcmp(cls->getName(),name))
     496                return cls;
     497return NULL;
     498}
     499
     500static const char* skipWord(const char* in)
     501{
     502while(isalpha(*in))
     503        in++;
     504return in;
     505}
     506
     507//returns the first character after the parsed portion or NULL if invalid format
     508const char* ExtValue::deserialize_inner(const char* in)
     509{
     510const char* ret=parseNumber(in);
     511if (ret)
     512        return ret;
     513else if (*in=='\"')
     514        {
     515        ret=skipQuoteString(in+1,NULL);
     516        SString s(in+1,ret-(in+1));
     517        sstringUnquote(s);
     518        setString(s);
     519        if (*ret=='\"')
     520                return ret+1;
     521        else
     522                return NULL;
     523        }
     524else if (*in=='[')
     525        {
     526        VectorObject *vec=new VectorObject;
     527        ExtObject o(&VectorObject::par,vec);
     528        ExtObject::serialization.getref().add(o);
     529        const char* p=in+1;
     530        ExtValue tmp;
     531        while(*p)
     532                {
     533                if (*p==']') {p++;break;}
     534                ret=tmp.deserialize(p);
     535                if (ret)
     536                        {
     537                        vec->data+=new ExtValue(tmp);
     538                        p=ret;
     539                        if (*p==',') p++;
     540                        }
     541                else
     542                        {
     543                        p=NULL;
     544                        break;
     545                        }
     546                }
     547        setObject(o);
     548        return p;
     549        }
     550else if (*in=='{')
     551        {
     552        DictionaryObject *dic=new DictionaryObject;
     553        ExtObject o(&DictionaryObject::par,dic);
     554        ExtObject::serialization.getref().add(o);
     555        const char* p=in+1;
     556        ExtValue args[2]/*={value,key}*/, dummy_ret;
     557        while(*p)
     558                {
     559                if (*p=='}') {p++;break;}
     560                ret=args[1].deserialize(p);
     561                if ((!ret)||(args[1].getType()!=TString)) {p=NULL;break;}
     562                p=ret;
     563                if (*p!=':') {p=NULL;break;}
     564                p++;
     565                ret=args[0].deserialize(p);
     566                if (!ret) {p=NULL;break;}
     567                p=ret;
     568                dic->p_set(args,&dummy_ret);
     569                if (*p==',') p++;
     570                }
     571        setObject(o);
     572        return p;
     573        }
     574else if (!strncmp(in,"null",4))
     575        {
     576        setEmpty();
     577        return in+4;
     578        }
     579else if (!strncmp(in,"undefined",9))
     580        {
     581        setInvalid();
     582        return in+9;
     583        }
     584else if (*in=='<')
     585        { //unserializable object
     586        setInvalid();
     587        while(*in)
     588                if (*in=='>')
     589                        return in+1;
     590                else in++;
     591        return in;
     592        }
     593else if (*in=='^')
     594        {
     595        in++;
     596        ExtValue ref;
     597        ret=ref.parseNumber(in);
     598        if (ret && (ref.getType()==TInt))
     599                {
     600                const ExtObject* o=ExtObject::serialization.getref().get(ref.getInt());
     601                if (o)
     602                        {
     603                        setObject(*o);
     604                        return ret;
     605                        }
     606                }
     607        return NULL;
     608        }
     609else if ((ret=skipWord(in))&&(ret!=in))
     610        {
     611        SString clsname(in,ret-in);
     612        ExtValue tmp;
     613        ret=tmp.deserialize(ret);
     614        ParamInterface *cls=findDeserializableClass(clsname);
     615        if (cls && (tmp.getType()!=TUnknown) && (tmp.getType()!=TInvalid))
     616                {
     617                VectorObject *vec=VectorObject::fromObject(tmp.getObject());
     618                if (vec)
     619                        {
     620                        int m=cls->findId("newFromVector");
     621                        if (m>=0)
     622                                {
     623                                cls->call(m,&tmp,this);
     624                                ExtObject::serialization.getref().replace(tmp.getObject(),getObject());
     625                                return ret;
     626                                }
     627                        }
     628                DictionaryObject *dic=DictionaryObject::fromObject(tmp.getObject());
     629                if (dic)
     630                        {
     631                        int m=cls->findId("newFromDictionary");
     632                        if (m>=0)
     633                                {
     634                                cls->call(m,&tmp,this);
     635                                ExtObject::serialization.getref().replace(tmp.getObject(),getObject());
     636                                return ret;
     637                                }
     638                        }
     639                if (tmp.getType()==TString)
     640                        {
     641                        int m=cls->findId("newFromString");
     642                        if (m>=0)
     643                                {
     644                                cls->call(m,&tmp,this);
     645                                ExtObject::serialization.getref().replace(tmp.getObject(),getObject());
     646                                return ret;
     647                                }
     648                        }
     649                ExtObject::serialization.getref().remove(tmp.getObject());
     650                setEmpty();
     651                }
     652        FMprintf("ExtValue","deserialize",FMLV_WARN,"object of class \"%s\" could not be deserialized",(const char*)clsname);
     653        return ret;
     654        }
     655return NULL;
     656}
     657
     658const char* ExtValue::deserialize(const char* in)
     659{
     660ExtObject::serialization.getref().begin();
     661const char* ret=deserialize_inner(in);
     662ExtObject::serialization.getref().end();
     663return ret;
     664}
     665
    299666ExtObject ExtValue::getObject() const
    300667{
     
    307674if (getType()!=TObj) return ExtValue((long)getType());
    308675ExtObject& o=odata();
    309 return ExtValue(SString(o.isEmpty()?"":o.getParamInterface()->getName()));
    310 }
     676return ExtValue(SString(o.isEmpty()?"":o.interfaceName()));
     677}
Note: See TracChangeset for help on using the changeset viewer.