#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()+"%";} }; // 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()<Dump()+", "; if(vals->size()!=0) s.resize(s.length()-2); return s+")"; } // 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 { const ObjectBase* p=Find(gname); return (0==p)?0:p->Copy(); } // This function is same as Get but return pointer on constant object const ObjectBase* Find(const std::string& gname) const { const ObjectBase* p; for(auto& i: *vals) { p=0; OBType pair(i); OBType list(i); if(pair) p=pair->Find(gname); else if(list) p=list->Find(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;} ObjectList* PushFront(ObjectBase* p) {vals->push_front(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