#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: bool err; // No save by default virtual const int8_t* Blob(size_t* size) const { *size=0; return nullptr; } virtual void DeallocBlob(const int8_t* ptr) const {}; ObjectBase():err(false) {} public: ObjectBase(const ObjectBase&) = delete; bool Save(const char* fname) const; bool isError() const {return err;} // Pure virtual api virtual ~ObjectBase(){} virtual const 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()+"%";} }; enum class OBTypeErr {OK,NULLPTR,TYPEMISMATCH}; // 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(nullptr==arg) {if(nullptr==arg) p=nullptr; else if(typeid(*arg)==typeid(O)) p=dynamic_cast(arg); else p=nullptr;} const O* operator->() const {return p;} operator bool() const {return nullptr!=p;} operator const O*() const {return p;} bool Exist() const {return !iszero;} OBTypeErr Error() const {if(iszero) return OBTypeErr::NULLPTR; else if(nullptr==p) return OBTypeErr::TYPEMISMATCH; else return OBTypeErr::OK;} }; // 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(nullptr==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();} OBTypeErr Error() const {if(!Exist()) return OBTypeErr::NULLPTR; else if(!operator bool()) return OBTypeErr::TYPEMISMATCH; else return OBTypeErr::OK;} }; // 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 nullptr!=p;} }; typedef std::shared_ptr ObjPtr; // Error class class EXPORT ObjectError: public ObjectBase { std::string function, reason; ObjectError() = delete; ObjectError(const ObjectError&) = delete; ObjectError(ObjectError&&) = delete; public: template ObjectError(F f, R r):function(f),reason(r) {ObjectBase::err=true;} const std::string& Function() const {return function;} const std::string& Reason() const {return reason;} // Pure virtual overrides const ObjectBase* Copy() const override {return new ObjectError(function,reason);} bool Print() const override { COUT(NORMAL)< 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 const 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; ObjPtr val; ObjectPair(const ObjectPair* p):name(p->name),val(p->val) {} public: ObjectPair() = delete; ObjectPair(const std::string& n, const ObjectBase* v):name(n) {val.reset(v);} ObjectPair(std::string&& n, const ObjectBase* v):name(std::move(n)) {val.reset(v);} ObjectPair(const std::string* n, const ObjectBase* v):name(*n) {val.reset(v);} ObjectPair(const std::string& n, const ObjPtr& v):name(n),val(v) {} // Pure virtual overrides const ObjectBase* Copy() const override { return new ObjectPair(this); } bool Print() const override { COUT(NORMAL)<Type()< ListValues; private: std::shared_ptr vals; ObjectList(const ObjectList* l):vals(l->vals) {} public: ObjectList(): vals(std::make_shared()) {}; ObjectList(const ObjectBase* o): vals(std::make_shared()) {vals->push_back(ObjPtr(o));} // Pure virtual overrides const ObjectBase* Copy() const override {return new ObjectList(this);} bool Print() const override { COUT(NORMAL)<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].get();} const ObjectBase* Get(const std::string& gname) const { const ObjectBase* p; for(const auto& i: *vals) { p=nullptr; OBType pair(i.get()); OBType list(i.get()); if(pair) p=pair->Get(gname); else if(list) p=list->Get(gname); if(nullptr!=p) return p; } return nullptr; } ListValues::size_type Size() const {return vals->size();} ObjectList* PushBack(const ObjectBase* p) {vals->push_back(ObjPtr(p)); return this;} ObjectList* PushBack(const ObjPtr& p) {vals->push_back(p); return this;} ObjectList* PushFront(const ObjectBase* p) {vals->push_front(ObjPtr(p)); return this;} ObjectList* PushFront(const ObjPtr& p) {vals->push_front(p); return this;} }; typedef const 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 const ObjectBase* Get(const ObjectList* input) { if(input->Size()!=2) return new ObjectError("GET","incorrect number of arguments"); OBType ob(input->At(0)); OBType name(input->At(1)); if(!name) return new ObjectError("GET","second argument is not ObjectString"); if(!ob) return new ObjectError("GET","incorrect type of first argument"); 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