You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
414 lines
14 KiB
414 lines
14 KiB
#ifndef COMMON_H |
|
#define COMMON_H |
|
#include <cctype> |
|
#include <cfloat> |
|
#include <deque> |
|
#include <iostream> |
|
#include <list> |
|
#include <memory> |
|
#include <set> |
|
#include <string> |
|
#include <sstream> |
|
#include <typeindex> |
|
#include <typeinfo> |
|
|
|
#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<std::string> UsedType; |
|
|
|
// We use different format for conversion of double to string |
|
template<class T> |
|
inline std::string ToString(T n) { return std::to_string(n); } |
|
template<> |
|
inline std::string ToString<double>(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>(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<Derived>(arg).Exist()) |
|
// Checking if arg is pointer on Derived: if(OBType<Derived>(arg)) |
|
// Using const ObjectBase* arg as const Derived*: OBType<Derived>(arg)->SomeCall() |
|
template<class O> |
|
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<const O*>(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<Func,Derived...>(arg).Exist()) |
|
// Checking if arg is pointer on any of Derived classes (always false if arg is zero): if(OBTypeM<Func,Derived...>(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<Derived1>(). |
|
// Full definition. Never instantiated. |
|
template<template<typename> class Func, class... O> |
|
class OBTypeM; |
|
|
|
// Recursive partial instantiation |
|
template<template<typename> class Func, class O1, class... O> |
|
class OBTypeM<Func,O1,O...>: public OBTypeM<Func,O...> |
|
{ |
|
bool right; |
|
|
|
OBTypeM() = delete; |
|
OBTypeM(OBTypeM&&) = delete; |
|
OBTypeM(OBTypeM&) = delete; |
|
protected: |
|
const ObjectBase* P() const {return OBTypeM<Func,O...>::P();} |
|
template<class Res, class... Args> |
|
Res F(Args... args) const |
|
{ |
|
if(right) return Func<O1>()(dynamic_cast<const O1*>(OBTypeM<Func,O...>::P()),args...); |
|
else return OBTypeM<Func,O...>::template F<Res,Args...>(args...); |
|
} |
|
public: |
|
OBTypeM(const ObjectBase* arg):OBTypeM<Func,O...>(arg) {if(nullptr==arg) right=false; else right=(typeid(*arg)==typeid(O1));} |
|
operator bool() const {return right || OBTypeM<Func,O...>::operator bool();} |
|
template<class Res, class... Args> |
|
bool Apply(Res& res, Args... args) const |
|
{ |
|
if(!right) return OBTypeM<Func,O...>::Apply(res,args...); |
|
res=static_cast<Res>(Func<O1>()(dynamic_cast<const O1*>(OBTypeM<Func,O...>::P()),args...)); |
|
return true; |
|
} |
|
template<class... Args> |
|
auto operator ()(Args... args) const -> decltype(Func<O1>()(dynamic_cast<const O1*>(this->P()),args...)) |
|
{ |
|
typedef decltype(Func<O1>()(dynamic_cast<const O1*>(this->P()),args...)) T; |
|
if(right) return Func<O1>()(dynamic_cast<const O1*>(OBTypeM<Func,O...>::P()),args...); |
|
else return OBTypeM<Func,O...>::template F<T,Args...>(args...); |
|
} |
|
bool Exist() const {return OBTypeM<Func,O...>::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<template<typename> class Func> |
|
class OBTypeM<Func> |
|
{ |
|
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<class Res, class... Args> |
|
bool Apply(Res& res, Args... args) const {return false;} |
|
template<class... Args> |
|
void operator ()(Args... args) const {} |
|
template<class Res, class... Args> |
|
Res F(Args... args) const {return Res();} |
|
bool Exist() const {return nullptr!=p;} |
|
}; |
|
|
|
|
|
// Error class |
|
class EXPORT ObjectError: public ObjectBase |
|
{ |
|
std::string function, reason; |
|
ObjectError() = delete; |
|
ObjectError(const ObjectError&) = delete; |
|
ObjectError(ObjectError&&) = delete; |
|
public: |
|
template<class F, class R> |
|
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)<<std::endl<<"Object type: "<<Type()<<std::endl; |
|
COUT(NORMAL)<<"Value: "<<Function()<<": "<<Reason()<<std::endl; |
|
return true; |
|
} |
|
std::string Type() const override {return "ERROR";} |
|
}; |
|
|
|
|
|
// Template for objects without specific constructor/destructor |
|
template<class T> |
|
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<const int8_t*>(&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<T>(val);} |
|
bool Print() const override |
|
{ |
|
COUT(NORMAL)<<std::endl<<"Object type: "<<Type()<<std::endl; |
|
COUT(NORMAL)<<"Value: "<<ToString(val)<<std::endl; |
|
return true; |
|
} |
|
std::string Type() const override {return type;} |
|
|
|
// Non-default overrides |
|
std::string Dump() const override |
|
{ |
|
std::stringstream s; |
|
if(std::type_index(typeid(T))==std::type_index(typeid(std::string))) |
|
s<<"\""<<val<<"\""; |
|
else |
|
s<<ToString(val); |
|
return s.str(); |
|
} |
|
|
|
// Own functions |
|
T Value() const {return val;} |
|
void SetValue(T s) {val=s;} |
|
}; |
|
|
|
// Simple objects |
|
typedef ObjectSimple<bool> ObjectBool; |
|
typedef ObjectSimple<int64_t> ObjectInt; |
|
typedef ObjectSimple<double> ObjectReal; |
|
typedef ObjectSimple<std::string> ObjectString; |
|
|
|
template<> |
|
inline const int8_t* ObjectString::Blob(size_t* size) const |
|
{ |
|
*size=val.length(); |
|
return reinterpret_cast<const int8_t*>(val.c_str()); |
|
} |
|
|
|
// Class for name-value pair |
|
class EXPORT ObjectPair: public ObjectBase |
|
{ |
|
private: |
|
std::string name; |
|
std::shared_ptr<const ObjectBase> val; |
|
|
|
public: |
|
ObjectPair() {} |
|
ObjectPair(const std::string& n, const ObjectBase* v):name(n) {val.reset(v);} |
|
ObjectPair(const std::string* n, const ObjectBase* v):name(*n) {val.reset(v);} |
|
~ObjectPair() {} |
|
// Pure virtual overrides |
|
const 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)<<std::endl<<"Object type: "<<Type()<<std::endl; |
|
COUT(NORMAL)<<"Name is: "<<Name()<<std::endl; |
|
COUT(NORMAL)<<"Value type: "<<val->Type()<<std::endl; |
|
return true; |
|
} |
|
std::string Type() const override {return "pair";} |
|
|
|
// Non-default overrides |
|
std::string Dump() const override { return Name()+"="+val->Dump(); } |
|
|
|
// Own functions |
|
bool Exist() const {return nullptr!=val.get();} |
|
const ObjectBase* Get(const std::string& gname) const |
|
{ |
|
if(gname==name) return val->Copy(); |
|
else return new ObjectError("ObjectPair Get","pair has name "+name+" not "+gname); |
|
} |
|
// This function is same as Get but return pointer on constant object |
|
const ObjectBase* Find(const std::string& gname) const |
|
{ |
|
if(gname==name) return val.get(); |
|
else return nullptr; |
|
} |
|
std::string Name() const {return name;} |
|
void SetPair(const std::string& n, const 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::deque<const ObjectBase*> ListValues; |
|
private: |
|
std::shared_ptr<ListValues> vals; |
|
|
|
public: |
|
ObjectList() {vals.reset(new ListValues, [](ListValues* p){for(auto& i: *p) delete i; delete p;});} |
|
ObjectList(const ObjectBase* o) {vals.reset(new ListValues, [](ListValues* p){for(auto& i: *p) delete i; delete p;}); PushBack(o);} |
|
~ObjectList() {} |
|
// Pure virtual overrides |
|
const ObjectBase* Copy() const override |
|
{ |
|
auto ret=new ObjectList; |
|
ret->vals=vals; |
|
return ret; |
|
} |
|
bool Print() const override |
|
{ |
|
if(!Exist()) return false; |
|
COUT(NORMAL)<<std::endl<<"Object type: "<<Type()<<std::endl; |
|
COUT(NORMAL)<<"Number of elements: "<<Size()<<std::endl; |
|
return true; |
|
} |
|
std::string Type() const override {return "list";} |
|
|
|
// Non-default overrides |
|
std::string Dump() const override |
|
{ |
|
std::string s("("); |
|
for(auto& i: *vals) s+=i->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();} |
|
const ObjectBase* Get(const std::string& gname) const |
|
{ |
|
const ObjectBase* p=Find(gname); |
|
return (nullptr==p)?new ObjectError("ObjectList Get","name "+gname+" not found in list"):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=nullptr; |
|
OBType<ObjectPair> pair(i); |
|
OBType<ObjectList> list(i); |
|
if(pair) p=pair->Find(gname); |
|
else if(list) p=list->Find(gname); |
|
if(nullptr!=p) return p; |
|
} |
|
return nullptr; |
|
} |
|
ListValues::size_type Size() const {return vals->size();} |
|
ObjectList* PushBack(const ObjectBase* p) {vals->push_back(p); return this;} |
|
ObjectList* PushFront(const ObjectBase* 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<class T> |
|
const ObjectBase* Get(const ObjectList* input) |
|
{ |
|
if(input->Size()!=2) return new ObjectError("GET","incorrect number of arguments"); |
|
OBType<T> ob(input->At(0)); |
|
OBType<ObjectString> 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<std::string> 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
|
|
|