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.

396 lines
13 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;}
};
typedef std::shared_ptr<const ObjectBase> ObjPtr;
// 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;}
};
// 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;
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)<<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
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);
}
std::string Name() const {return name;}
const ObjectBase* Value() const {return val.get();}
};
// Class for objects list
class EXPORT ObjectList: public ObjectBase
{
public:
typedef std::deque<ObjPtr> ListValues;
private:
std::shared_ptr<ListValues> vals;
ObjectList(const ObjectList* l):vals(l->vals) {}
public:
ObjectList(): vals(std::make_shared<ListValues>()) {};
ObjectList(const ObjectBase* o): vals(std::make_shared<ListValues>()) {vals->push_back(ObjPtr(o));}
// Pure virtual overrides
const ObjectBase* Copy() const override {return new ObjectList(this);}
bool Print() const override
{
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].get();}
const ObjectBase* Get(const std::string& gname) const
{
const ObjectBase* p;
for(const auto& i: *vals)
{
p=nullptr;
OBType<ObjectPair> pair(i.get());
OBType<ObjectList> 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<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