// This file is a part of the Framsticks GDK. // Copyright (C) 2002-2014 Maciej Komosinski and Szymon Ulatowski. See LICENSE.txt for details. // Refer to http://www.framsticks.com/ for further information. #ifndef _EXTVALUE_H_ #define _EXTVALUE_H_ #include "sstring.h" #include #include #include #define EXTVALUEUNION template struct CompileTimeMax {enum {val=A>B?A:B}; }; #define EXTVALUEUNIONSIZE CompileTimeMax::val enum ExtPType {TUnknown=0,TInt,TDouble,TString,TObj,TInvalid}; /** destructable object */ class DestrBase { public: int refcount; DestrBase():refcount(0) {} void incref() {refcount++;} void decref() {refcount--; if (refcount==0) delete this;} virtual ~DestrBase() {} }; /** object reference. */ class ExtObject { int subtype; //< 0/1=Generic/DPC Object, 0/2=Standalone/Shared Param void incref() const; void decref() const; public: union { void* object; //< generic object, will use param DestrBase *dbobject;}; //< object with refcounting, will be deleted if refcount goes to 0 union { Param* param; //< if object!=0 ParamInterface *paraminterface;}; //< if object==0 void copyFrom(const ExtObject& src) {subtype=src.subtype;object=src.object;param=src.param;} void* operator new(size_t s, void* mem) {return mem;} #ifdef _MSC_VER void operator delete(void* mem,void* t) {} #endif void* operator new(size_t s) {return malloc(sizeof(ExtObject));} void operator delete(void* mem) {free(mem);} ///@param tmp_param can be used for temporary storage, the result ParamInterface* is only valid for as long as tmp_param is valid ParamInterface *getParamInterface(Param &tmp_param) const {if(subtype&2){tmp_param.setParamTab(param->getParamTab());tmp_param.select(object);return &tmp_param;} return paraminterface;} const char* interfaceName() const {if (isEmpty()) return "Empty"; return (subtype&2)?param->getName():paraminterface->getName();} bool matchesInterfaceName(ParamInterface* pi) const {return !strcmp(interfaceName(),pi->getName());} void* getTarget() const {return (subtype&1)?dbobject:object;} void* getTarget(const char* classname, bool through_barrier=true) const; void setEmpty() {decref();subtype=0;param=NULL;object=NULL;} int isEmpty() const {return !param;} ExtObject(const ExtObject& src) {src.incref();copyFrom(src);} void operator=(const ExtObject& src) {src.incref();decref();copyFrom(src);} bool makeUnique();//< @return false if nothing has changed int operator==(const ExtObject& src) const {if (object!=src.object) return 0; return (object==0)?(!strcmp(param->getName(),src.param->getName())):1;} SString toString() const; SString serialize_inner() const; SString serialize() const; ExtObject(Param *p,void *o):subtype(2),object(o),param(p){} ExtObject(ParamInterface *p=0):subtype(0),object(0),paraminterface(p){} ExtObject(Param *p,DestrBase *o):subtype(1+2),dbobject(o),param(p){incref();} ExtObject(ParamInterface *p,DestrBase *o):subtype(1),dbobject(o),paraminterface(p){incref();} ~ExtObject(){decref();} class Serialization { std::vector refs; int level; public: Serialization():level(0) {} void begin(); void end(); int add(const ExtObject& o); void replace(const ExtObject& o,const ExtObject& other); void remove(const ExtObject& o); const ExtObject* get(int ref); }; static THREAD_LOCAL_DECL(Serialization,serialization); }; class ExtValue { public: ExtPType type; #ifdef EXTVALUEUNION long data[(EXTVALUEUNIONSIZE+sizeof(long)-1)/sizeof(long)]; long& idata() const {return (long&)data[0];}; double& ddata() const {return *(double*)data;}; ExtObject& odata() const {return *(ExtObject*)data;}; SString& sdata() const {return *(SString*)data;}; #else union { long i; double d; SString *s; ExtObject *o; }; long& idata() const {return (long&)i;}; double& ddata() const {return (double&)d;}; ExtObject& odata() const {return *o;}; SString& sdata() const {return *s;}; #endif void* operator new(size_t s, void* mem) {return mem;} void* operator new(size_t s) {return ::operator new(s);} ExtValue():type(TUnknown){} ~ExtValue() {setEmpty();} ExtValue(long v) {seti(v);} ExtValue(double v) {setd(v);} ExtValue(const SString &v) {sets(v);} ExtValue(const ExtObject &srco) {seto(srco);} long compare(const ExtValue& src) const; int operator==(const ExtValue& src) const; void operator+=(const ExtValue& src); void operator-=(const ExtValue& src); void operator*=(const ExtValue& src); void operator/=(const ExtValue& src); void operator%=(const ExtValue& src); void operator=(const ExtValue& src) {setr(src);} ExtValue(const ExtValue& src) :type(TUnknown) {set(src);} void setEmpty(); void setInvalid() {setEmpty();type=TInvalid;} bool makeUnique() {return (type==TObj) && odata().makeUnique();} //< @return false if nothing has changed ExtPType getType() {return type;} void *getObjectTarget(const char* classname) {return (type==TObj)?getObject().getTarget(classname):0;} void setInt(long v) {if (type!=TInt) setri(v); else idata()=v;} void setDouble(double v) {if (type!=TDouble) setrd(v); else ddata()=v;} void setString(const SString &v) {if (type!=TString) setrs(v); else sdata()=v;} void setObject(const ExtObject &src) {if (type!=TObj) setro(src); else odata()=src;} long getInt() const; double getDouble() const; SString getString() const; const SString* getStringPtr() const;//< @return pointer to the internal sstring object or NULL if the current type is not string SString serialize() const; ExtObject getObject() const; const char* parseNumber(const char* in); const char* deserialize(const char* in);//< @return first character after the succesfully parsed string or NULL if failed const char* deserialize_inner(const char* in); static PtrListTempl deserializable_classes; static ParamInterface *findDeserializableClass(const char* name); static void initDeserializableClasses(); static SString format(SString& fmt,const ExtValue **values,int count); ExtValue getExtType(); private: // setrx - release and set, setx - assume released void setr(const ExtValue& src){setEmpty();set(src);} void set(const ExtValue& src); void setri(long v) {setEmpty();seti(v);} void setrd(double v) {setEmpty();setd(v);} void seti(long v) {type=TInt;idata()=v;} void setd(double v) {type=TDouble;ddata()=v;} #ifdef EXTVALUEUNION void setrs(const SString &v) {setEmpty();sets(v);} void setro(const ExtObject &src) {setEmpty();seto(src);} void sets(const SString &v) {type=TString;new(data) SString(v);} void seto(const ExtObject &src) {type=TObj;new(data) ExtObject(src);} #else void setrs(const SString &v) {setEmpty();sets(v);} void setro(const ExtObject &src) {setEmpty();seto(src);} void sets(const SString &v) {type=TString;s=new SString(v);} void seto(const ExtObject &src) {type=TObj;o=new ExtObject(src);} #endif }; #endif