GSLAM  3.0.0
Public Member Functions | Static Public Member Functions | Public Attributes | Friends | List of all members
Svar Class Reference

The Svar class, A Tiny Modern C++ Header Brings Unified Interface for Different Languages. More...

Public Member Functions

 Svar ()
 Default is Undefined.
 
 Svar (SvarValue *v)
 Construct from SvarValue pointer.
 
template<typename T >
 Svar (const T &var)
 Wrap any thing with template caster for user customize.
 
template<typename T >
 Svar (std::unique_ptr< T > &&v)
 Wrap an pointer use unique_ptr.
 
 Svar (bool b)
 Wrap bool to static instances.
 
 Svar (int i)
 Wrap a int.
 
 Svar (double d)
 Wrap a double.
 
 Svar (const std::string &str)
 Wrap a string.
 
 Svar (const std::vector< Svar > &vec)
 Construct an Array.
 
 Svar (const std::map< std::string, Svar > &m)
 Construct an Object.
 
 Svar (const std::map< Svar, Svar > &m)
 Construct a Dict.
 
 Svar (const std::initializer_list< Svar > &init)
 Construct from initializer.
 
template<typename Return , typename... Args, typename... Extra>
 Svar (Return(*f)(Args...), const Extra &...extra)
 Construct a cpp_function from a vanilla function pointer.
 
template<typename Return , typename Class , typename... arg, typename... Extra>
 Svar (Return(Class::*f)(arg...), const Extra &...extra)
 Construct a cpp_function from a class method (non-const)
 
template<typename Return , typename Class , typename... arg, typename... Extra>
 Svar (Return(Class::*f)(arg...) const, const Extra &...extra)
 Construct a cpp_function from a class method (const)
 
template<typename T >
bool is () const
 Is holding a type T value?
 
bool is (const std::type_index &typeId) const
 
bool is (const std::string &typeStr) const
 
template<typename T >
const T & as () const
 Should always check type with "is<T>()" first.
 
template<typename T >
T & as ()
 Return the value as type T, TAKE CARE when using this. The Svar should be hold during operations of the value.
 
template<typename T >
Svar cast () const
 Success: return a Svar holding T instance, Failed: return Undefined.
 
Svar cast (const std::string &typeStr) const
 
template<typename T >
detail::enable_if_t< std::is_pointer< T >::value, T > castAs ()
 No cast is performed, directly return the c++ pointer, throw SvarException when failed.
 
template<typename T >
detail::enable_if_t< std::is_reference< T >::value, T & > castAs ()
 No cast is performed, directly return the c++ reference, throw SvarException when failed.
 
template<typename T >
detail::enable_if_t<!std::is_reference< T >::value &&!std::is_pointer< T >::value, T > castAs () const
 Cast to c++ type T and return, throw SvarException when failed.
 
bool isUndefined () const
 
bool isNull () const
 
bool isFunction () const
 
bool isClass () const
 
bool isException () const
 
bool isObject () const
 
bool isArray () const
 
bool isDict () const
 
Svar clone (int depth=0) const
 
std::string typeName () const
 Return the value typename.
 
std::type_index cpptype () const
 Return the value typeid.
 
const SvarclassObject () const
 Return the class singleton, return Undefined when failed.
 
SvarClass * classPtr () const
 Return the class singleton pointer, return nullptr when failed.
 
size_t length () const
 Return the item numbers when it is an array, object or dict.
 
size_t size () const
 
template<typename T >
T & get (const std::string &name, T def, bool parse_dot=false)
 Force to return the children as type T, cast is performed, otherwise the old value will be droped and set to the value "def".
 
Svar get (const std::string &name, Svar def, bool parse_dot=false)
 
template<typename T >
void set (const std::string &name, const T &def, bool parse_dot=false)
 Set the child "name" to "create<T>(def)".
 
bool exist (const Svar &id) const
 For Object: dot compute and find the member For Array, Dict and Class, check if the item is not Undefined without dot compute.
 
void erase (const Svar &id)
 For Object: dot compute and call delitem Others : directly call delitem
 
void push_back (const Svar &rh)
 Append item when this is an array.
 
template<typename... Args>
Svar call (const std::string function, Args...args) const
 Call function or class with name and arguments.
 
template<typename... Args>
Svar operator() (Args...args) const
 Call this as function or class.
 
Svardef (const std::string &name, Svar funcOrClass)
 Define a class or function with name.
 
template<typename Func >
Svardef (const std::string &name, Func &&f)
 Define a lambda function with name.
 
std::vector< std::string > parseMain (int argc, char **argv)
 Parse the "main(int argc,char** argv)" arguments.
 
bool parseFile (const std::string &file_path)
 
template<typename T >
arg (const std::string &name, T def, const std::string &help)
 Register default required arguments.
 
std::string helpInfo ()
 Format print version, usages and arguments as string.
 
int help ()
 Format print version, usages and arguments.
 
Svar operator- () const
 
Svar operator+ (const Svar &rh) const
 
Svar operator- (const Svar &rh) const
 
Svar operator* (const Svar &rh) const
 
Svar operator/ (const Svar &rh) const
 
Svar operator% (const Svar &rh) const
 
Svar operator^ (const Svar &rh) const
 
Svar operator| (const Svar &rh) const
 
Svar operator& (const Svar &rh) const
 
bool operator== (const Svar &rh) const
 
bool operator< (const Svar &rh) const
 
bool operator!= (const Svar &rh) const
 
bool operator> (const Svar &rh) const
 
bool operator<= (const Svar &rh) const
 
bool operator>= (const Svar &rh) const
 
Svar operator[] (const Svar &i) const
 
Svaroperator[] (const Svar &name)
 
template<typename T >
detail::enable_if_t< std::is_copy_assignable< T >::value, Svar & > operator= (const T &v)
 
template<typename T >
detail::enable_if_t<!std::is_copy_assignable< T >::value, Svar & > operator= (const T &v)
 
 operator std::string ()
 
const std::shared_ptr< SvarValue > & value () const
 Return the raw holder.
 
SvargetOrCreate (const std::string &name, bool parse_dot=false)
 This is dangerous since the returned Svar may be free by other threads, TAKE CARE!
 
template<typename T >
Arg (const std::string &name, T def, const std::string &help)
 
std::vector< std::string > ParseMain (int argc, char **argv)
 
bool ParseFile (const std::string &file_path)
 
template<typename T >
T & Get (const std::string &name, T def=T())
 
Svar Get (const std::string &name, Svar def=Svar())
 
int & GetInt (const std::string &name, int def=0)
 
double & GetDouble (const std::string &name, double def=0)
 
std::string & GetString (const std::string &name, std::string def="")
 
void *& GetPointer (const std::string &name, void *def=nullptr)
 
template<typename T >
void Set (const std::string &name, const T &def)
 
template<typename T >
void Set (const std::string &name, const T &def, bool overwrite)
 

Static Public Member Functions

template<typename Func , typename... Extra>
static Svar lambda (Func &&f, const Extra &...extra)
 Construct a cpp_function from a lambda function (possibly with internal state)
 
template<class T >
static Svar create (const T &t)
 Create any other c++ type instance, T need to be a copyable type.
 
template<class T >
static Svar create (T &&t)
 
static Svar object (const std::map< std::string, Svar > &m={})
 Create an Object instance.
 
static Svar array (const std::vector< Svar > &vec={})
 Create an Array instance.
 
static Svar dict (const std::map< Svar, Svar > &m={})
 Create a Dict instance.
 
static Svar json (const std::string &str)
 Create from Json String.
 
static std::string printTable (std::vector< std::pair< int, std::string >> line)
 Format print strings as table.
 
static const SvarUndefined ()
 Undefined is the default value when Svar is not assigned a valid value It corrosponding to the c++ void and means no return.
 
static const SvarNull ()
 Null is corrosponding to the c++ nullptr.
 
static const SvarTrue ()
 
static const SvarFalse ()
 
static Svarinstance ()
 
static Svar loadFile (const std::string &file_path)
 
template<typename T >
static std::string type_id ()
 
template<typename T >
static std::string toString (const T &v)
 
template<typename T >
static detail::enable_if_t< detail::has_loading_support< std::istream, T >::value, T > fromString (const std::string &str, const T &def)
 
template<typename T >
static detail::enable_if_t<!detail::has_loading_support< std::istream, T >::value, T > fromString (const std::string &str, const T &def)
 
static std::string getFileName (const std::string &path)
 

Public Attributes

std::shared_ptr< SvarValue > _obj
 

Friends

std::ostream & operator<< (std::ostream &ost, const Svar &self)
 Dump this as Json style outputs.
 
std::istream & operator>> (std::istream &ist, Svar &self)
 

Detailed Description

The Svar class, A Tiny Modern C++ Header Brings Unified Interface for Different Languages.

By Using Svar, your C++ library can be called easily with different languages like C++, Java, Python and Javascript.

Svar brings the following features:

Use Svar like JSON

Svar natually support JSON and here is some basic usage demo:

Svar null=nullptr;
Svar b=false;
Svar i=1;
Svar d=2.1;
Svar s="hello world";
Svar v={1,2,3}
Svar m={"b",false,"s","hello world"}
Svar obj;
obj["m"]=m;
obj["pi"]=3.14159;
std::cout<<obj;
std::stringstream sst("[2,3,4]");
sst>>obj;
std::cout<<obj;
// use string literal
Svar lit="[false,3]"_svar;
if(s.is<std::string>()) // use is to check type
std::cout<<"raw string is "<<s.as<std::string>(); // use as to force cast, never throw
double d=i.castAs<double>();// use castAs, this may throw SvarException

Use Svar for Argument Parsing

Svar provides argument parsing functional with JSON configuration loading. Here is a small demo shows how to use Svar for argument parsing:

#include <GSLAM/core/Svar.h>
int main(int argc,char** argv)
{
svar.parseMain(argc,argv);
int argInt=svar.arg<int>("i",0,"This is a demo int parameter");
svar.arg<bool>("b",false,"Here is the bool description");
if(svar.get<bool>("help",false)){
svar.help();
return 0;
}
return 0;
}

When you use "--help" or "-help", the terminal should show the below introduction:

-> sample_use --help
Usage:
sample_use [--help] [-conf configure_file] [-arg_name arg_value]...
Using Svar supported argument parsing. The following table listed several argume
nt introductions.
Argument Type(default->setted) Introduction
--------------------------------------------------------------------------------
-i int(0) This is a demo int parameter
-b bool(false) Here is the bool description
-conf str("Default.cfg") The default configure file going
to parse.
-help bool(false->true) Show the help information.

"help" and "conf" is two default parameters and users can use "conf" to load JSON file for configuration loading.

Svar supports the following parsing styles:

Use Svar to Hold Other C++ Elements

Svar can not only hold JSON types, but also any other c++ elements including functions, classes and objects.

A tiny sample of Svar holding functions and classes.

#include <GSLAM/core/Svar.h>
int c_func(int a,int b){return a+b;}
class DemoClass{
public:
DemoClass(const std::string& name):_name(name){}
std::string getName()const{return _name;}
void setName(std::string name){_name=name}
static DemoClass create(std::string name){return DemoClass(name);}
std::string _name;
};
int main(int argc,char** argv)
{
Svar add=c_func;// hold a function
int c=add(a,b).castAs<int>();// use the function
Svar create(&DemoClass::create);// hold a static member function
DemoClass inst=create("hello svar").as<DemoClass>();// call a static member function
Svar(&DemoClass::setName)(&inst,"I changed name");// call a member function
Svar cls=SvarClass::instance<DemoClass>();
Class<DemoClass>()
.construct<const std::string&>()
.def("getName",&DemoClass::getName)
.def("setName",&DemoClass::setName)
.def_static("create",&DemoClass::create);
Svar inst2=cls("I am another instance");// construct a instance
std::string name=inst2.call("getName").as<std::string>();
inst2.call("setName","changed name with svar");
}

Define Class Members with Svar

Svar does not do magic, so users need to bind functions mannually like boost or pybind11 did. Fortunately, Svar provided utils to bind those functions very conveniencely.

As used in last section, there are three types of functions: constructor, member function and static member function. And Svar also support lambda expression of functions so that users able to extend functions more easily.

Class<DemoClass>("Demo") // change the name to Demo
.construct<const std::string&>() // constructor
.def("getName",&DemoClass::getName) // const member function
.def("setName",&DemoClass::setName) // member function
.def_static("create",&DemoClass::create)// static function
.def("print",[](DemoClass& self){std::cerr<<self._name;})// lambda function
.def_static("none",[](){});// static lambda function
Todo:
Svar does not support field now, maybe it's a future work.

Operators of Svar

Svar supports to call functions with operators, such as for int, we got some math operators and we want to use it directly with Svar:

Svar a=4;
Svar b=5;
auto c=a+b;
EXPECT_TRUE(c.is<int>())
EXPECT_EQ(c,20)

The above operation is available because Svar builtin defined as following:

SvarClass::Class<int>()
.def("__init__",&SvarBuiltin::int_create)
.def("__double__",[](int i){return (double)i;})
.def("__bool__",[](int i){return (bool)i;})
.def("__str__",[](int i){return Svar::toString(i);})
.def("__eq__",[](int self,int rh){return self==rh;})
.def("__lt__",[](int self,int rh){return self<rh;})
.def("__add__",[](int self,Svar rh)->Svar{
if(rh.is<int>()) return Svar(self+rh.as<int>());
if(rh.is<double>()) return Svar(self+rh.as<double>());
return Svar::Undefined();
})
.def("__sub__",[](int self,Svar rh)->Svar{
if(rh.is<int>()) return Svar(self-rh.as<int>());
if(rh.is<double>()) return Svar(self-rh.as<double>());
return Svar::Undefined();
})
.def("__mul__",[](int self,Svar rh)->Svar{
if(rh.is<int>()) return Svar(self*rh.as<int>());
if(rh.is<double>()) return Svar(self*rh.as<double>());
return Svar::Undefined();
})
.def("__div__",[](int self,Svar rh){
if(rh.is<int>()) return Svar(self/rh.as<int>());
if(rh.is<double>()) return Svar(self/rh.as<double>());
return Svar::Undefined();
})
.def("__mod__",[](int self,int rh){
return self%rh;
})
.def("__neg__",[](int self){return -self;})
.def("__xor__",[](int self,int rh){return self^rh;})
.def("__or__",[](int self,int rh){return self|rh;})
.def("__and__",[](int self,int rh){return self&rh;});

If you want your own class support these operators, you need to define you own implementations. The following table listed some operators that often used.

Operator Function Name
+ "__add__"
- "__sub__"
* "__mul__"
/ "__div__"
% "__mod__"
& "__and__"
| "__or__"
^ "__xor__"
= "__eq__"
!= "__nq__"
< "__lt__"
> "__gt__"
<= "__le__"
>= "__ge__"
[] "__getitem__"

Inherit of Classes

#include <GSLAM/core/Svar.h>
using namespace GSLAM;
class BBase{
public:
virtual bool isBBase(){return true;}
};
class BaseClass: public BBase{
public:
BaseClass(int age):age_(age){}
int getAge()const{return age_;}
void setAge(int a){age_=a;}
virtual bool isBBase(){return false;}
int age_;
};
int main(int argc,char** argv)
{
Class<BBase>()
.def("isBBase",&BBase::isBBase);
Class<BaseClass>()
.inherit<BBase,BaseClass>() // use this to inherit
.def_static("__init__",[](int age){return BaseClass(age);})// replace construct<int>()
.def("getAge",&BaseClass::getAge)
.def("setAge",&BaseClass::setAge);
Svar cls=SvarClass::instance<BaseClass>();
Svar obj=cls(10);// ten years old?
assert(!obj.call("isBBase).as<bool>());
return 0;
}

Export & Import Svar Module with C++ Shared Library

One of the most important design target of Svar is to export a shared library that can be used by different languages.

Export Svar Module

The only thing needs to do is to put what you want to the singleton of Svar: Svar::instance(), which is defined as 'svar', and expose the symbol with macro EXPORT_SVAR_INSTANCE.

#include "GSLAM/core/Svar.h"
using namespace GSLAM;
int add(int a,int b){
return a+b;
}
class ApplicationDemo{
public:
ApplicationDemo(std::string name):_name(name){
std::cout<<"Application Created.";
}
std::string name()const{return _name;}
std::string gslam_version()const{return "3.2";}
std::string _name;
};
REGISTER_SVAR_MODULE(sample)// see, so easy, haha
{
svar["__name__"]="sample_module";
svar["__doc__"]="This is a demo to show how to export a module using svar.";
svar["add"]=add;
Class<ApplicationDemo>()
.construct<std::string>()
.def("name",&ApplicationDemo::name)
.def("gslam_version",&ApplicationDemo::gslam_version);
svar["ApplicationDemo"]=SvarClass::instance<ApplicationDemo>();
}
EXPORT_SVAR_INSTANCE // export the symbol of Svar::instance

Compile this file to a shared library "libsample.so" or "sample.dll", and we are going to access this module with Svar later.

Documentation of Svar Module

A Svar module is designed to be self maintained, which means the module can be called without header or documentation. Since SvarFunction auto generated function signatures, so that users are able to know how to call Svar functions.

One can use the 'svar' application from https://github.com/zdzhaoyong/Svar, or the "gslam" application of https://github.com/zdzhaoyong/GSLAM to access the context.

-> gslam doc -plugin sample
{
"ApplicationDemo" : <class at 0x15707d0>,
"__builtin__" : {
"Json" : <class at 0x156fd80>,
"version" : 256
},
"__doc__" : "This is a demo to show how to export a module using svar.",
"__name__" : "sample_module",
"add" : <function at 0x15706e0>
}
-> gslam doc -plugin sample -key ApplicationDemo
class ApplicationDemo():
| ApplicationDemo.__init__(...)
| ApplicationDemo.__init__(str)->ApplicationDemo
|
|
| Methods defined here:
| ApplicationDemo.__init__(...)
| ApplicationDemo.__init__(str)->ApplicationDemo
|
|
| ApplicationDemo.gslam_version(...)
| ApplicationDemo.gslam_version(ApplicationDemo const*)->str
|
|
| ApplicationDemo.name(...)
| ApplicationDemo.name(ApplicationDemo const*)->str
|
|

Use Svar Module in C++

We are able to load the Svar instance exported by marco with EXPORT_SVAR_INSTANCE using Registry::load().

#include "GSLAM/core/Svar.h"
#include "GSLAM/core/Registry.h"
using namespace GSLAM;
int main(int argc,char** argv){
Svar sampleModule=Registry::load("sample");
Svar ApplicationDemo=sampleModule["ApplicationDemo"];
Svar instance=ApplicationDemo("zhaoyong");
std::cout<<instance.call("gslam_version");
std::cout<<ApplicationDemo.as<SvarClass>();
return 0;
}