#ifndef COMMON_H #define COMMON_H #include #include #include #include #include #include #include #include #include #include #include #define EXPORT __attribute__ ((visibility ("default"))) enum debug_level {INTERNALREQUEST,MOREDEBUG,DEBUG,INFO,NORMAL,WARNING,ERROR}; EXPORT std::ostream& COUT(debug_level dl); typedef std::set UsedType; // We use different format for conversion of double to string template inline std::string ToString(T n) { return std::to_string(n); } template<> inline std::string ToString(double n) { char buffer[32]; int i; i=snprintf(buffer,32,"%.*G",DBL_DIG,n); return std::string(buffer,i); } template<> inline std::string ToString(std::string s) {return s;} // Base class for all objects class EXPORT ObjectBase { protected: // No save by default virtual const int8_t* Blob(size_t* size) const { *size=0; return 0; } virtual void DeallocBlob(const int8_t* ptr) const {}; public: ObjectBase() = default; ObjectBase(const ObjectBase&) = delete; bool Save(const char* fname) const; // Pure virtual api virtual ~ObjectBase(){} virtual ObjectBase* Copy() const=0; virtual bool Print() const=0; virtual std::string Type() const=0; // Virtual api with default functions. Modules types must not override them. virtual std::string Dump() const {return "%"+Type()+"%";} virtual ObjectBase* Evaluate(bool* err) {*err=false; return 0;} virtual ObjectBase* ReplaceVar(const std::string& vname, ObjectBase* ob) {return 0;} virtual void UsedFuncs(UsedType& funcs) const {} virtual void UsedIdents(UsedType& ids) const {} }; // Template for checking and using ObjectBase derivative classes // Checking if arg is non-zero: if(OBType(arg).Exist()) // Checking if arg is pointer on Derived: if(OBType(arg)) // Using const ObjectBase* arg as const Derived*: OBType(arg)->SomeCall() template class OBType { const O* p; bool iszero; public: OBType() = delete; OBType(OBType&&) = delete; OBType(OBType&) = delete; OBType(const ObjectBase* arg):iszero(0==arg) {if(0==arg) p=0; else if(typeid(*arg)==typeid(O)) p=dynamic_cast(arg); else p=0;} const O* operator->() const {return p;} operator bool() const {return 0!=p;} operator const O*() const {return p;} bool Exist() const {return !iszero;} }; // Template for checking and using several ObjectBase derivative classes // Func is template of class-function template argument of which can be any of Derived classes. // It must have at least one argument - pointer to constant object of Derived class and return non-void. // Checking if arg is non-zero: if(OBTypeM(arg).Exist()) // Checking if arg is pointer on any of Derived classes (always false if arg is zero): if(OBTypeM(arg)) // Applying Func can be done by two ways: // 1) Function bool Apply(Res& res, args...). Here res is result of calling Func with arguments args. Result of Func is statically casted to type Res. // If arg is zero or not a pointer on any of Derived classes, Apply() return false and res is not changed. // 2) Overloaded operator ()(args). It returns result of calling Func with arguments args. Type of returning value is type of Func(). // Full definition. Never instantiated. template class Func, class... O> class OBTypeM; // Recursive partial instantiation template class Func, class O1, class... O> class OBTypeM: public OBTypeM { bool right; OBTypeM() = delete; OBTypeM(OBTypeM&&) = delete; OBTypeM(OBTypeM&) = delete; protected: const ObjectBase* P() const {return OBTypeM::P();} template Res F(Args... args) const { if(right) return Func()(dynamic_cast(OBTypeM::P()),args...); else return OBTypeM::template F(args...); } public: OBTypeM(const ObjectBase* arg):OBTypeM(arg) {if(0==arg) right=false; else right=(typeid(*arg)==typeid(O1));} operator bool() const {return right || OBTypeM::operator bool();} template bool Apply(Res& res, Args... args) const { if(!right) return OBTypeM::Apply(res,args...); res=static_cast(Func()(dynamic_cast(OBTypeM::P()),args...)); return true; } template auto operator ()(Args... args) const -> decltype(Func()(dynamic_cast(this->P()),args...)) { typedef decltype(Func()(dynamic_cast(this->P()),args...)) T; if(right) return Func()(dynamic_cast(OBTypeM::P()),args...); else return OBTypeM::template F(args...); } bool Exist() const {return OBTypeM::Exist();} }; // Partial instantiation of the bottom of recursion template class Func> class OBTypeM { const ObjectBase* p; // We save pointer on bottom OBTypeM() = delete; OBTypeM(OBTypeM&&) = delete; OBTypeM(OBTypeM&) = delete; protected: // Only protected functions because such objects must never exists in the wild. OBTypeM(const ObjectBase* arg):p(arg) {} operator bool() const {return false;} // If we go down to this place, p is not an pointer on appropriate type const ObjectBase* P() const {return p;} template bool Apply(Res& res, Args... args) const {return false;} template void operator ()(Args... args) const {} template Res F(Args... args) const {return Res();} bool Exist() const {return 0!=p;} }; // Template for objects without specific constructor/destructor template class EXPORT ObjectSimple: public ObjectBase { private: T val; static std::string type; const int8_t* Blob(size_t* size) const override {*size=sizeof(T); return reinterpret_cast(&val);} public: ObjectSimple(T t):val(t) {} ObjectSimple(const T* t):val(*t) {} ~ObjectSimple() {} // Pure virtual overrides ObjectBase* Copy() const override {return new ObjectSimple(val);} bool Print() const override { COUT(NORMAL)< ObjectBool; typedef ObjectSimple ObjectInt; typedef ObjectSimple ObjectReal; typedef ObjectSimple ObjectString; template<> inline const int8_t* ObjectString::Blob(size_t* size) const { *size=val.length(); return reinterpret_cast(val.c_str()); } // Class for name-value pair class EXPORT ObjectPair: public ObjectBase { private: std::string name; std::shared_ptr val; public: ObjectPair() {} ObjectPair(const std::string& n, ObjectBase* v):name(n) {val.reset(v);} ObjectPair(const std::string* n, ObjectBase* v):name(*n) {val.reset(v);} ~ObjectPair() {} // Pure virtual overrides ObjectBase* Copy() const override { auto ret=new ObjectPair; ret->name=name; ret->val=val; return ret; } bool Print() const override { if(!Exist()) return false; COUT(NORMAL)<Type()<ReplaceVar(vname,ob); if(0!=p) val.reset(p); return 0; } void UsedFuncs(UsedType& funcs) const override {return val->UsedFuncs(funcs);} void UsedIdents(UsedType& ids) const override {return val->UsedIdents(ids);} // Own functions bool Exist() const {return 0!=val.get();} ObjectBase* Get(const std::string& gname) const { if(gname==name) return val->Copy(); else return 0; } std::string Name() const {return name;} void SetPair(const std::string& n, ObjectBase* v) {if(!Exist()) {name=n; val.reset(v);}} const ObjectBase* Value() const {return val.get();} }; // Class for objects list class EXPORT ObjectList: public ObjectBase { public: typedef std::vector ListValues; private: std::shared_ptr vals; public: ObjectList() {vals.reset(new ListValues, [](ListValues* p){for(auto& i: *p) delete i; delete p;});} ObjectList(ObjectBase* o) {vals.reset(new ListValues, [](ListValues* p){for(auto& i: *p) delete i; delete p;}); PushBack(o);} ~ObjectList() {} // Pure virtual overrides ObjectBase* Copy() const override { auto ret=new ObjectList; ret->vals=vals; return ret; } bool Print() const override { if(!Exist()) return false; COUT(NORMAL)<Dump()+", "; if(vals->size()!=0) s.resize(s.length()-2); return s+")"; } ObjectBase* Evaluate(bool* err) override { ObjectBase* p; for(auto& i: *vals) { p=i->Evaluate(err); if(*err) { COUT(ERROR)<<" in list member "<Dump()<ReplaceVar(vname,ob); if(0!=p) { delete i; i=p; } } return 0; } void UsedFuncs(UsedType& funcs) const override {for(auto& i: *vals) i->UsedFuncs(funcs);} void UsedIdents(UsedType& ids) const override {for(auto& i: *vals) i->UsedIdents(ids);} // Own functions const ObjectBase* At(ListValues::size_type i) const {return (*vals)[i];} bool Exist() const {return 0!=vals->size();} ObjectBase* Get(const std::string& gname) const { ObjectBase* p; for(auto& i: *vals) { p=0; OBType pair(i); OBType list(i); if(pair) p=pair->Get(gname); else if(list) p=list->Get(gname); if(0!=p) return p; } return 0; } ListValues::size_type Size() const {return vals->size();} ObjectList* PushBack(ObjectBase* p) {vals->push_back(p); return this;} }; typedef ObjectBase* (*Func)(const ObjectList*); typedef int (*ModuleInitFunc)(const void*); extern "C" { EXPORT void RegisterFunction(const std::string& name, Func func); EXPORT int LoadModule(const std::string& name, const void* p, const std::string& modname=""); } template ObjectBase* Get(const ObjectList* input) { if(input->Size()!=2) return 0; OBType ob(input->At(0)); OBType name(input->At(1)); if(!(ob && name)) return 0; return ob->Get(name->Value()); } // Simple conversion functions inline bool str2double(const char* str, double* res) { char* pos; *res=strtod(str,&pos); if('\0'!=*pos) return false; else return true; } inline bool str2int(const char* str, int64_t* res) { char* pos; *res=strtoll(str,&pos,0); if('\0'!=*pos) return false; else return true; } inline bool str2uint(const char* str, uint64_t* res) { char* pos; *res=strtoull(str,&pos,0); if('\0'!=*pos) return false; else return true; } inline bool str2double(const std::string& str, double* res) {return str2double(str.c_str(),res);} inline bool str2int(const std::string& str, int64_t* res) {return str2int(str.c_str(),res);} inline bool str2uint(const std::string& str, uint64_t* res) {return str2uint(str.c_str(),res);} inline void tolower(std::string& str) {for(auto& p: str) p=tolower(p);} inline void tolower(std::string* str) {for(auto& p:*str) p=tolower(p);} inline void tolower(char* str) {for(*str=tolower(*str);'\0'!=*str++;*str=tolower(*str));} typedef std::list WordList; EXPORT WordList Split(const std::string& str, const std::string& delims, bool allowempty); inline WordList Split(const std::string& str) {return Split(str,std::string(" \t",3),false);} inline WordList Split(const char* str) {return Split(std::string(str),std::string(" \t",3),false);} inline WordList Split(const std::string& str, bool allowempty) {return Split(str,std::string(" \t",3),allowempty);} inline WordList Split(const char* str, bool allowempty) {return Split(std::string(str),std::string(" \t",3),allowempty);} inline WordList Split(const std::string& str, const std::string& delims) {return Split(str,delims,false);} inline WordList Split(const char* str, const std::string& delims) {return Split(std::string(str),delims,false);} inline WordList Split(const std::string& str, const char* delims) {return Split(str,std::string(delims),false);} inline WordList Split(const char* str, const char* delims) {return Split(std::string(str),std::string(delims),false);} #endif