GSLAM  3.0.0
Svar.h
1 // GSLAM - A general SLAM framework and benchmark
2 // Copyright 2018 PILAB Inc. All rights reserved.
3 // https://github.com/zdzhaoyong/GSLAM
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors may be
14 // used to endorse or promote products derived from this software without
15 // specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 //
29 // Author: zd5945@126.com (Yong Zhao) 353184965@qq.com(Guochen Liu)
30 //
31 // By Using Svar, your C++ library can be called easily with different
32 // languages like C++, Java, Python and Javascript.
33 //
34 // Svar brings the following features:
35 // 1. A dynamic link library that can be used as a module in languages
36 // such as C++, Python, and Node-JS;
37 // 2. Unified C++ library interface, which can be called as a plug-in module.
38 // The released library comes with documentation, making *.h header file interface description unnecessary;
39 // 3. Dynamic features. It wraps variables, functions, and classes into Svar while maintaining efficiency;
40 // 4. Built-in Json support, parameter configuration parsing, thread-safe reading and writing,
41 // data decoupling sharing between modules, etc.
42 
43 #ifndef GSLAM_JVAR_H
44 #define GSLAM_JVAR_H
45 
46 #include <assert.h>
47 #include <string.h>
48 #include <cstdlib>
49 #include <cctype>
50 #include <iostream>
51 #include <iomanip>
52 #include <fstream>
53 #include <sstream>
54 #include <vector>
55 #include <list>
56 #include <map>
57 #include <algorithm>
58 #include <memory>
59 #include <mutex>
60 #include <thread>
61 #include <typeindex>
62 #include <functional>
63 #ifdef __GNUC__
64 #include <cxxabi.h>
65 #else
66 #define _GLIBCXX_USE_NOEXCEPT
67 #endif
68 
69 #define svar GSLAM::Svar::instance()
70 #define SVAR_VERSION 0x000100 // 0.1.0
71 #define EXPORT_SVAR_INSTANCE extern "C" SVAR_EXPORT GSLAM::Svar* svarInstance(){return &GSLAM::Svar::instance();}
72 #define REGISTER_SVAR_MODULE(MODULE_NAME) \
73  class SVAR_MODULE_##MODULE_NAME{\
74  public: SVAR_MODULE_##MODULE_NAME();\
75  }SVAR_MODULE_##MODULE_NAME##instance;\
76  SVAR_MODULE_##MODULE_NAME::SVAR_MODULE_##MODULE_NAME()
77 
78 # if defined(WIN32) || defined(_WIN32)
79 # define SVAR_EXPORT __declspec(dllexport)
80 # else
81 # define SVAR_EXPORT __attribute__ ((visibility("default")))
82 # endif
83 
84 namespace GSLAM {
85 
86 #ifndef DOXYGEN_IGNORE_INTERNAL
87 namespace detail {
88 template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type;
89 template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type;
90 template <typename T> using remove_cv_t = typename std::remove_cv<T>::type;
91 template <typename T> using remove_reference_t = typename std::remove_reference<T>::type;
92 
93 
94 /// Strip the class from a method type
95 template <typename T> struct remove_class { };
96 template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); };
97 template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...) const> { typedef R type(A...); };
98 
99 template <typename F> struct strip_function_object {
100  using type = typename remove_class<decltype(&F::operator())>::type;
101 };
102 // Extracts the function signature from a function, function pointer or lambda.
103 template <typename Function, typename F = remove_reference_t<Function>>
104 using function_signature_t = conditional_t<
105  std::is_function<F>::value,
106  F,
107  typename conditional_t<
108  std::is_pointer<F>::value || std::is_member_pointer<F>::value,
109  std::remove_pointer<F>,
110  strip_function_object<F>
111  >::type
112 >;
113 
114 # if __cplusplus >= 201402L
115 using std::index_sequence;
116 using std::make_index_sequence;
117 #else
118 template<size_t ...> struct index_sequence { };
119 template<size_t N, size_t ...S> struct make_index_sequence_impl : make_index_sequence_impl <N - 1, N - 1, S...> { };
120 template<size_t ...S> struct make_index_sequence_impl <0, S...> { typedef index_sequence<S...> type; };
121 template<size_t N> using make_index_sequence = typename make_index_sequence_impl<N>::type;
122 #endif
123 
124 typedef char yes;
125 typedef char (&no)[2];
126 
127 struct anyx {
128  template <class T>
129  anyx(const T&);
130 };
131 
132 no operator<<(const anyx&, const anyx&);
133 no operator>>(const anyx&, const anyx&);
134 
135 template <class T>
136 yes check(T const&);
137 no check(no);
138 
139 template <typename StreamType, typename T>
140 struct has_loading_support {
141  static StreamType& stream;
142  static T& x;
143  static const bool value = sizeof(check(stream >> x)) == sizeof(yes);
144 };
145 
146 template <typename StreamType, typename T>
147 struct has_saving_support {
148  static StreamType& stream;
149  static T& x;
150  static const bool value = sizeof(check(stream << x)) == sizeof(yes);
151 };
152 
153 template <typename StreamType, typename T>
154 struct has_stream_operators {
155  static const bool can_load = has_loading_support<StreamType, T>::value;
156  static const bool can_save = has_saving_support<StreamType, T>::value;
157  static const bool value = can_load && can_save;
158 };
159 
160 }
161 #endif
162 
163 class Svar;
164 class SvarValue;
165 class SvarFunction;
166 class SvarClass;
167 class SvarObject;
168 class SvarArray;
169 class SvarDict;
170 class SvarBuffer;
171 class SvarExeption;
172 template <typename T>
174 
175 /**
176 @brief The Svar class, A Tiny Modern C++ Header Brings Unified Interface for Different Languages
177 
178 By Using Svar, your C++ library can be called easily with different languages like C++, Java, Python and Javascript.
179 
180 Svar brings the following features:
181 
182 - A dynamic link library that can be used as a module in languages such as C++, Python, and Node-JS;
183 - Unified C++ library interface, which can be called as a plug-in module. The released library comes with documentation, making *.h header file interface description unnecessary;
184 - Dynamic features. It wraps variables, functions, and classes into Svar while maintaining efficiency;
185 - Built-in Json support, parameter configuration parsing, thread-safe reading and writing, data decoupling sharing between modules, etc.
186 
187 \section s_svar_json Use Svar like JSON
188 
189 Svar natually support JSON and here is some basic usage demo:
190 \code
191 Svar null=nullptr;
192 Svar b=false;
193 Svar i=1;
194 Svar d=2.1;
195 Svar s="hello world";
196 Svar v={1,2,3}
197 Svar m={"b",false,"s","hello world"}
198 
199 Svar obj;
200 obj["m"]=m;
201 obj["pi"]=3.14159;
202 
203 std::cout<<obj;
204 
205 std::stringstream sst("[2,3,4]");
206 sst>>obj;
207 std::cout<<obj;
208 
209 // use string literal
210 Svar lit="[false,3]"_svar;
211 
212 if(s.is<std::string>()) // use is to check type
213  std::cout<<"raw string is "<<s.as<std::string>(); // use as to force cast, never throw
214 
215 double d=i.castAs<double>();// use castAs, this may throw SvarException
216 
217 \endcode
218 
219 \section s_svar_arguments Use Svar for Argument Parsing
220 
221 Svar provides argument parsing functional with JSON configuration loading.
222 Here is a small demo shows how to use Svar for argument parsing:
223 
224 @code
225 #include <GSLAM/core/Svar.h>
226 
227 int main(int argc,char** argv)
228 {
229  svar.parseMain(argc,argv);
230 
231  int argInt=svar.arg<int>("i",0,"This is a demo int parameter");
232  svar.arg<bool>("b",false,"Here is the bool description");
233 
234  if(svar.get<bool>("help",false)){
235  svar.help();
236  return 0;
237  }
238  return 0;
239 }
240 
241 @endcode
242 
243 When you use "--help" or "-help", the terminal should show the below introduction:
244 @code
245 -> sample_use --help
246 Usage:
247 sample_use [--help] [-conf configure_file] [-arg_name arg_value]...
248 
249 Using Svar supported argument parsing. The following table listed several argume
250 nt introductions.
251 
252 Argument Type(default->setted) Introduction
253 --------------------------------------------------------------------------------
254 -i int(0) This is a demo int parameter
255 -b bool(false) Here is the bool description
256 -conf str("Default.cfg") The default configure file going
257  to parse.
258 -help bool(false->true) Show the help information.
259 @endcode
260 "help" and "conf" is two default parameters and users can use "conf" to load JSON file for configuration loading.
261 
262 
263 Svar supports the following parsing styles:
264 - "-arg value": two '-' such as "--arg value" is the same
265 - "-arg=value": two "--" such as "--arg=value" is the same
266 - "arg=value"
267 - "-arg" : this is the same with "arg=true", but the next argument should not be a value
268 
269 \section s_svar_cppelements Use Svar to Hold Other C++ Elements
270 
271 Svar can not only hold JSON types, but also any other c++ elements including functions, classes and objects.
272 
273 \subsection s_svar_cppelements_sample A tiny sample of Svar holding functions and classes.
274 
275 @code
276 #include <GSLAM/core/Svar.h>
277 
278 int c_func(int a,int b){return a+b;}
279 
280 class DemoClass{
281 public:
282  DemoClass(const std::string& name):_name(name){}
283  std::string getName()const{return _name;}
284  void setName(std::string name){_name=name}
285 
286  static DemoClass create(std::string name){return DemoClass(name);}
287 
288  std::string _name;
289 };
290 
291 int main(int argc,char** argv)
292 {
293  Svar add=c_func;// hold a function
294  int c=add(a,b).castAs<int>();// use the function
295 
296  Svar create(&DemoClass::create);// hold a static member function
297  DemoClass inst=create("hello svar").as<DemoClass>();// call a static member function
298 
299  Svar(&DemoClass::setName)(&inst,"I changed name");// call a member function
300 
301  Svar cls=SvarClass::instance<DemoClass>();
302  Class<DemoClass>()
303  .construct<const std::string&>()
304  .def("getName",&DemoClass::getName)
305  .def("setName",&DemoClass::setName)
306  .def_static("create",&DemoClass::create);
307 
308  Svar inst2=cls("I am another instance");// construct a instance
309  std::string name=inst2.call("getName").as<std::string>();
310  inst2.call("setName","changed name with svar");
311 }
312 @endcode
313 
314 \subsection s_svar_class Define Class Members with Svar
315 Svar does not do magic, so users need to bind functions mannually like boost or pybind11 did.
316 Fortunately, Svar provided utils to bind those functions very conveniencely.
317 
318 As used in last section, there are three types of functions: constructor,
319 member function and static member function.
320 And Svar also support lambda expression of functions so that users able to extend functions more easily.
321 @code
322  Class<DemoClass>("Demo") // change the name to Demo
323  .construct<const std::string&>() // constructor
324  .def("getName",&DemoClass::getName) // const member function
325  .def("setName",&DemoClass::setName) // member function
326  .def_static("create",&DemoClass::create)// static function
327  .def("print",[](DemoClass& self){std::cerr<<self._name;})// lambda function
328  .def_static("none",[](){});// static lambda function
329 @endcode
330 
331 @todo Svar does not support field now, maybe it's a future work.
332 
333 \subsection s_svar_operators Operators of Svar
334 
335 Svar supports to call functions with operators, such as for int,
336 we got some math operators and we want to use it directly with Svar:
337 @code
338  Svar a=4;
339  Svar b=5;
340  auto c=a+b;
341  EXPECT_TRUE(c.is<int>())
342  EXPECT_EQ(c,20)
343 @endcode
344 
345 The above operation is available because Svar builtin defined as following:
346 @code
347  SvarClass::Class<int>()
348  .def("__init__",&SvarBuiltin::int_create)
349  .def("__double__",[](int i){return (double)i;})
350  .def("__bool__",[](int i){return (bool)i;})
351  .def("__str__",[](int i){return Svar::toString(i);})
352  .def("__eq__",[](int self,int rh){return self==rh;})
353  .def("__lt__",[](int self,int rh){return self<rh;})
354  .def("__add__",[](int self,Svar rh)->Svar{
355  if(rh.is<int>()) return Svar(self+rh.as<int>());
356  if(rh.is<double>()) return Svar(self+rh.as<double>());
357  return Svar::Undefined();
358  })
359  .def("__sub__",[](int self,Svar rh)->Svar{
360  if(rh.is<int>()) return Svar(self-rh.as<int>());
361  if(rh.is<double>()) return Svar(self-rh.as<double>());
362  return Svar::Undefined();
363  })
364  .def("__mul__",[](int self,Svar rh)->Svar{
365  if(rh.is<int>()) return Svar(self*rh.as<int>());
366  if(rh.is<double>()) return Svar(self*rh.as<double>());
367  return Svar::Undefined();
368  })
369  .def("__div__",[](int self,Svar rh){
370  if(rh.is<int>()) return Svar(self/rh.as<int>());
371  if(rh.is<double>()) return Svar(self/rh.as<double>());
372  return Svar::Undefined();
373  })
374  .def("__mod__",[](int self,int rh){
375  return self%rh;
376  })
377  .def("__neg__",[](int self){return -self;})
378  .def("__xor__",[](int self,int rh){return self^rh;})
379  .def("__or__",[](int self,int rh){return self|rh;})
380  .def("__and__",[](int self,int rh){return self&rh;});
381 @endcode
382 
383 If you want your own class support these operators, you need to define you own implementations.
384 The following table listed some operators that often used.
385 
386 | Operator | Function Name |
387 | -- | -- |
388 | + | "__add__" |
389 | - | "__sub__" |
390 | * | "__mul__" |
391 | / | "__div__" |
392 | % | "__mod__" |
393 | & | "__and__" |
394 | \| | "__or__" |
395 | ^ | "__xor__" |
396 | = | "__eq__" |
397 | != | "__nq__" |
398 | < | "__lt__" |
399 | > | "__gt__" |
400 | <= | "__le__" |
401 | >= | "__ge__" |
402 | [] | "__getitem__" |
403 
404 \subsection s_svar_inherit Inherit of Classes
405 
406 @code
407 #include <GSLAM/core/Svar.h>
408 
409 using namespace GSLAM;
410 
411 class BBase{
412 public:
413  virtual bool isBBase(){return true;}
414 };
415 
416 class BaseClass: public BBase{
417 public:
418  BaseClass(int age):age_(age){}
419 
420  int getAge()const{return age_;}
421  void setAge(int a){age_=a;}
422 
423  virtual bool isBBase(){return false;}
424 
425  int age_;
426 };
427 
428 int main(int argc,char** argv)
429 {
430  Class<BBase>()
431  .def("isBBase",&BBase::isBBase);
432 
433  Class<BaseClass>()
434  .inherit<BBase,BaseClass>() // use this to inherit
435  .def_static("__init__",[](int age){return BaseClass(age);})// replace construct<int>()
436  .def("getAge",&BaseClass::getAge)
437  .def("setAge",&BaseClass::setAge);
438 
439  Svar cls=SvarClass::instance<BaseClass>();
440  Svar obj=cls(10);// ten years old?
441  assert(!obj.call("isBBase).as<bool>());
442  return 0;
443 }
444 
445 @endcode
446 
447 \section s_svar_plugin Export & Import Svar Module with C++ Shared Library
448 
449 One of the most important design target of Svar is to export a shared library that
450 can be used by different languages.
451 
452 \subsection s_svar_export Export Svar Module
453 
454 The only thing needs to do is to put what you want to the singleton of Svar: Svar::instance(),
455 which is defined as 'svar', and expose the symbol with macro EXPORT_SVAR_INSTANCE.
456 
457 @code
458 #include "GSLAM/core/Svar.h"
459 
460 using namespace GSLAM;
461 
462 int add(int a,int b){
463  return a+b;
464 }
465 
466 class ApplicationDemo{
467 public:
468  ApplicationDemo(std::string name):_name(name){
469  std::cout<<"Application Created.";
470  }
471  std::string name()const{return _name;}
472  std::string gslam_version()const{return "3.2";}
473  std::string _name;
474 };
475 
476 REGISTER_SVAR_MODULE(sample)// see, so easy, haha
477 {
478  svar["__name__"]="sample_module";
479  svar["__doc__"]="This is a demo to show how to export a module using svar.";
480  svar["add"]=add;
481 
482  Class<ApplicationDemo>()
483  .construct<std::string>()
484  .def("name",&ApplicationDemo::name)
485  .def("gslam_version",&ApplicationDemo::gslam_version);
486 
487  svar["ApplicationDemo"]=SvarClass::instance<ApplicationDemo>();
488 }
489 
490 EXPORT_SVAR_INSTANCE // export the symbol of Svar::instance
491 @endcode
492 
493 Compile this file to a shared library "libsample.so" or "sample.dll", and we are going to access this module with Svar later.
494 
495 \subsection s_svar_doc Documentation of Svar Module
496 A Svar module is designed to be self maintained, which means the module can be called without header or documentation.
497 Since SvarFunction auto generated function signatures, so that users are able to know how to call Svar functions.
498 
499 One can use the 'svar' application from https://github.com/zdzhaoyong/Svar,
500 or the "gslam" application of https://github.com/zdzhaoyong/GSLAM to access the context.
501 
502 @code
503 -> gslam doc -plugin sample
504 {
505  "ApplicationDemo" : <class at 0x15707d0>,
506  "__builtin__" : {
507  "Json" : <class at 0x156fd80>,
508  "version" : 256
509  },
510  "__doc__" : "This is a demo to show how to export a module using svar.",
511  "__name__" : "sample_module",
512  "add" : <function at 0x15706e0>
513 }
514 -> gslam doc -plugin sample -key ApplicationDemo
515 class ApplicationDemo():
516 | ApplicationDemo.__init__(...)
517 | ApplicationDemo.__init__(str)->ApplicationDemo
518 |
519 |
520 | Methods defined here:
521 | ApplicationDemo.__init__(...)
522 | ApplicationDemo.__init__(str)->ApplicationDemo
523 |
524 |
525 | ApplicationDemo.gslam_version(...)
526 | ApplicationDemo.gslam_version(ApplicationDemo const*)->str
527 |
528 |
529 | ApplicationDemo.name(...)
530 | ApplicationDemo.name(ApplicationDemo const*)->str
531 |
532 |
533 @endcode
534 
535 \subsection s_svar_usecpp Use Svar Module in C++
536 We are able to load the Svar instance exported by marco with EXPORT_SVAR_INSTANCE
537 using Registry::load().
538 
539 @code
540 #include "GSLAM/core/Svar.h"
541 #include "GSLAM/core/Registry.h"
542 
543 using namespace GSLAM;
544 
545 int main(int argc,char** argv){
546  Svar sampleModule=Registry::load("sample");
547 
548  Svar ApplicationDemo=sampleModule["ApplicationDemo"];
549 
550  Svar instance=ApplicationDemo("zhaoyong");
551  std::cout<<instance.call("gslam_version");
552 
553  std::cout<<ApplicationDemo.as<SvarClass>();
554  return 0;
555 }
556 
557 @endcode
558 
559  */
560 
561 class Svar{
562 public:
563  // Basic buildin types
564  /// Default is Undefined
565  Svar():Svar(Undefined()){}
566 
567  /// Construct from SvarValue pointer
568  Svar(SvarValue* v)
569  : _obj(std::shared_ptr<SvarValue>(v)){}
570 
571  /// Wrap any thing with template caster for user customize
572  template <typename T>
573  Svar(const T& var);
574 
575  /// Wrap an pointer use unique_ptr
576  template <typename T>
577  Svar(std::unique_ptr<T>&& v);
578 
579  /// Wrap bool to static instances
580  Svar(bool b):Svar(b?True():False()){}
581 
582  /// Wrap a int
583  Svar(int i):Svar(create(i)){}
584 
585  /// Wrap a double
586  Svar(double d):Svar(create(d)){}
587 
588  /// Wrap a string
589  Svar(const std::string& str);
590 
591  /// Construct an Array
592  Svar(const std::vector<Svar>& vec);//Array
593 
594  /// Construct an Object
595  Svar(const std::map<std::string,Svar>& m);//Object
596 
597  /// Construct a Dict
598  Svar(const std::map<Svar,Svar>& m);//Dict
599 
600  /// Construct from initializer
601  Svar(const std::initializer_list<Svar>& init);
602 
603  /// Construct a cpp_function from a vanilla function pointer
604  template <typename Return, typename... Args, typename... Extra>
605  Svar(Return (*f)(Args...), const Extra&... extra);
606 
607  /// Construct a cpp_function from a lambda function (possibly with internal state)
608  template <typename Func, typename... Extra>
609  static Svar lambda(Func &&f, const Extra&... extra);
610 
611  /// Construct a cpp_function from a class method (non-const)
612  template <typename Return, typename Class, typename... arg, typename... Extra>
613  Svar(Return (Class::*f)(arg...), const Extra&... extra);
614 
615  /// Construct a cpp_function from a class method (const)
616  template <typename Return, typename Class, typename... arg, typename... Extra>
617  Svar(Return (Class::*f)(arg...) const, const Extra&... extra);
618 
619  /// Create any other c++ type instance, T need to be a copyable type
620 #if (__GNUC__>=5)||defined(__clang__)
621  template <class T>
622  static Svar create(T & t);
623 #else
624  template <class T>
625  static Svar create(const T & t);
626 #endif
627 
628  template <class T>
629  static Svar create(T && t);
630 
631  /// Create an Object instance
632  static Svar object(const std::map<std::string,Svar>& m={}){return Svar(m);}
633 
634  /// Create an Array instance
635  static Svar array(const std::vector<Svar>& vec={}){return Svar(vec);}
636 
637  /// Create a Dict instance
638  static Svar dict(const std::map<Svar,Svar>& m={}){return Svar(m);}
639 
640  /// Create from Json String
641  static Svar json(const std::string& str){
642  return svar["__builtin__"]["Json"].call("load",str);
643  }
644 
645  /// Is holding a type T value?
646  template <typename T>
647  bool is()const;
648  bool is(const std::type_index& typeId)const;
649  bool is(const std::string& typeStr)const;
650 
651  /// Should always check type with "is<T>()" first
652  template <typename T>
653  const T& as()const;
654 
655  /// Return the value as type T, TAKE CARE when using this.
656  /// The Svar should be hold during operations of the value.
657  template <typename T>
658  T& as();
659 
660  /// Success: return a Svar holding T instance, Failed: return Undefined
661  template <typename T>
662  Svar cast()const;
663 
664  Svar cast(const std::string& typeStr)const;
665 
666  /// No cast is performed, directly return the c++ pointer, throw SvarException when failed
667  template <typename T>
668  detail::enable_if_t<std::is_pointer<T>::value,T>
669  castAs();
670 
671  /// No cast is performed, directly return the c++ reference, throw SvarException when failed
672  template <typename T>
673  detail::enable_if_t<std::is_reference<T>::value,T&>
674  castAs();
675 
676  /// Cast to c++ type T and return, throw SvarException when failed
677  template <typename T>
678  detail::enable_if_t<!std::is_reference<T>::value&&!std::is_pointer<T>::value,T>
679  castAs()const;
680 
681  bool isUndefined()const{return is<void>();}
682  bool isNull()const;
683  bool isFunction() const{return is<SvarFunction>();}
684  bool isClass() const{return is<SvarClass>();}
685  bool isException() const{return is<SvarExeption>();}
686  bool isObject() const;
687  bool isArray()const;
688  bool isDict()const;
689 
690  Svar clone(int depth=0)const;
691 
692  /// Return the value typename
693  std::string typeName()const;
694 
695  /// Return the value typeid
696  std::type_index cpptype()const;
697 
698  /// Return the class singleton, return Undefined when failed.
699  const Svar& classObject()const;
700 
701  /// Return the class singleton pointer, return nullptr when failed.
702  SvarClass* classPtr()const;
703 
704  /// Return the item numbers when it is an array, object or dict.
705  size_t length() const;
706  size_t size()const{return length();}
707 
708  /// Force to return the children as type T, cast is performed,
709  /// otherwise the old value will be droped and set to the value "def"
710  template <typename T>
711  T& get(const std::string& name,T def,bool parse_dot=false);
712 
713  Svar get(const std::string& name,Svar def,bool parse_dot=false);
714 
715  /// Set the child "name" to "create<T>(def)"
716  template <typename T>
717  void set(const std::string& name,const T& def,bool parse_dot=false);
718 
719  /// For Object: dot compute and find the member
720  /// For Array, Dict and Class, check if the item is not Undefined without dot compute
721  bool exist(const Svar& id)const;
722 
723  /// For Object: dot compute and call __delitem__
724  /// Others : directly call __delitem__
725  void erase(const Svar& id);
726 
727  /// Append item when this is an array
728  void push_back(const Svar& rh);
729 
730  /// Call function or class with name and arguments
731  template <typename... Args>
732  Svar call(const std::string function, Args... args)const;
733 
734  /// Call this as function or class
735  template <typename... Args>
736  Svar operator()(Args... args)const;
737 
738  /// Define a class or function with name
739  Svar& def(const std::string& name,Svar funcOrClass);
740 
741  /// Define a lambda function with name
742  template <typename Func>
743  Svar& def(const std::string& name,Func &&f){
744  return def(name,Svar::lambda(f));
745  }
746 
747  /// Parse the "main(int argc,char** argv)" arguments
748  std::vector<std::string> parseMain(int argc, char** argv);
749 
750  bool parseFile(const std::string& file_path);
751 
752  /// Register default required arguments
753  template <typename T>
754  T arg(const std::string& name, T def, const std::string& help);
755 
756  /// Format print version, usages and arguments as string
757  std::string helpInfo();
758 
759  /// Format print version, usages and arguments
760  int help(){std::cout<<helpInfo();return 0;}
761 
762  /// Format print strings as table
763  static std::string printTable(
764  std::vector<std::pair<int, std::string>> line);
765 
766  Svar operator -()const; //__neg__
767  Svar operator +(const Svar& rh)const;//__add__
768  Svar operator -(const Svar& rh)const;//__sub__
769  Svar operator *(const Svar& rh)const;//__mul__
770  Svar operator /(const Svar& rh)const;//__div__
771  Svar operator %(const Svar& rh)const;//__mod__
772  Svar operator ^(const Svar& rh)const;//__xor__
773  Svar operator |(const Svar& rh)const;//__or__
774  Svar operator &(const Svar& rh)const;//__and__
775 
776  bool operator ==(const Svar& rh)const;//__eq__
777  bool operator < (const Svar& rh)const;//__lt__
778  bool operator !=(const Svar& rh)const{return !((*this)==rh);}//__ne__
779  bool operator > (const Svar& rh)const{return !((*this)==rh||(*this)<rh);}//__gt__
780  bool operator <=(const Svar& rh)const{return ((*this)<rh||(*this)==rh);}//__le__
781  bool operator >=(const Svar& rh)const{return !((*this)<rh);}//__ge__
782  Svar operator [](const Svar& i) const;//__getitem__
783  Svar& operator[](const Svar& name);// This is not thread safe!
784 
785  template <typename T>
786  detail::enable_if_t<std::is_copy_assignable<T>::value,Svar&> operator =(const T& v){
787  if(is<T>()) as<T>()=v;
788  else (*this)=Svar(v);
789  return *this;
790  }
791 
792  template <typename T>
793  detail::enable_if_t<!std::is_copy_assignable<T>::value,Svar&> operator =(const T& v){
794  (*this)=Svar(v);
795  return *this;
796  }
797 
798  operator std::string(){return castAs<std::string>();}
799 
800  /// Dump this as Json style outputs
801  friend std::ostream& operator <<(std::ostream& ost,const Svar& self);
802  friend std::istream& operator >>(std::istream& ist,Svar& self);
803 
804  /// Undefined is the default value when Svar is not assigned a valid value
805  /// It corrosponding to the c++ void and means no return
806  static const Svar& Undefined();
807 
808  /// Null is corrosponding to the c++ nullptr
809  static const Svar& Null();
810  static const Svar& True();
811  static const Svar& False();
812  static Svar& instance();
813  static Svar loadFile(const std::string& file_path);
814 
815  template <typename T>
816  static std::string type_id();
817 
818  template <typename T>
819  static std::string toString(const T& v);
820 
821  template <typename T>
822  static detail::enable_if_t<detail::has_loading_support<std::istream,T>::value,T> fromString(const std::string& str,const T& def)
823  {
824  T ret;
825  std::stringstream sst(str);
826  sst>>ret;
827  return ret;
828  }
829 
830  template <typename T>
831  static detail::enable_if_t<!detail::has_loading_support<std::istream,T>::value,T> fromString(const std::string& str,const T& def)
832  {
833  return def;
834  }
835 
836  /// Return the raw holder
837  const std::shared_ptr<SvarValue>& value()const{return _obj;}
838 
839  /// This is dangerous since the returned Svar may be free by other threads, TAKE CARE!
840  Svar& getOrCreate(const std::string& name,bool parse_dot=false);// FIXME: Not thread safe
841 
842  template <typename T>
843  T Arg(const std::string& name, T def, const std::string& help){return arg<T>(name,def,help);}
844 
845  std::vector<std::string> ParseMain(int argc, char** argv){return parseMain(argc,argv);}
846  bool ParseFile(const std::string& file_path){return parseFile(file_path);}
847 
848  template <typename T>
849  T& Get(const std::string& name,T def=T()){return get<T>(name,def);}
850  Svar Get(const std::string& name,Svar def=Svar()){return get(name,def);}
851  int& GetInt(const std::string& name,int def=0){return get<int>(name,def);}
852  double& GetDouble(const std::string& name,double def=0){return get<double>(name,def);}
853  std::string& GetString(const std::string& name,std::string def=""){return get<std::string>(name,def);}
854  void*& GetPointer(const std::string& name,void* def=nullptr){return get<void*>(name,def);}
855  template <typename T>
856  void Set(const std::string& name,const T& def){return set<T>(name,def);}
857  template <typename T>
858  void Set(const std::string& name,const T& def,bool overwrite){
859  if(exist(name)&&!overwrite) return;
860  return set<T>(name,def);
861  }
862 
863  static std::string getFileName(const std::string& path) {
864  auto idx = std::string::npos;
865  if ((idx = path.find_last_of('/')) == std::string::npos)
866  idx = path.find_last_of('\\');
867  if (idx != std::string::npos)
868  return path.substr(idx + 1);
869  else
870  return path;
871  }
872  std::shared_ptr<SvarValue> _obj;
873 };
874 
875 
876 #ifndef DOXYGEN_IGNORE_INTERNAL
877 class SvarValue{
878 public:
879  SvarValue(){}
880  virtual ~SvarValue(){}
881  typedef std::type_index TypeID;
882  virtual TypeID cpptype()const{return typeid(void);}
883  virtual const void* ptr() const{return nullptr;}
884  virtual const Svar& classObject()const;
885  virtual size_t length() const {return 0;}
886  virtual std::mutex* accessMutex()const{return nullptr;}
887  virtual Svar clone(int depth=0)const{return Svar();}
888 };
889 
890 class SvarExeption: public std::exception{
891 public:
892  SvarExeption(const Svar& wt=Svar())
893  :_wt(wt){}
894 
895  virtual const char* what() const throw(){
896  if(_wt.is<std::string>())
897  return _wt.as<std::string>().c_str();
898  else
899  return "SvarException";
900  }
901 
902  Svar _wt;
903 };
904 
905 class SvarFunction: public SvarValue{
906 public:
907  SvarFunction(){}
908 
909  /// Construct a cpp_function from a vanilla function pointer
910  template <typename Return, typename... Args, typename... Extra>
911  SvarFunction(Return (*f)(Args...), const Extra&... extra) {
912  initialize(f, f, extra...);
913  }
914 
915  /// Construct a cpp_function from a lambda function (possibly with internal state)
916  template <typename Func, typename... Extra>
917  SvarFunction(Func &&f, const Extra&... extra) {
918  initialize(std::forward<Func>(f),
919  (detail::function_signature_t<Func> *) nullptr, extra...);
920  }
921 
922  /// Construct a cpp_function from a class method (non-const)
923  template <typename Return, typename Class, typename... Arg, typename... Extra>
924  SvarFunction(Return (Class::*f)(Arg...), const Extra&... extra) {
925  initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); },
926  (Return (*) (Class *, Arg...)) nullptr, extra...);
927  }
928 
929  /// Construct a cpp_function from a class method (const)
930  template <typename Return, typename Class, typename... Arg, typename... Extra>
931  SvarFunction(Return (Class::*f)(Arg...) const, const Extra&... extra) {
932  initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); },
933  (Return (*)(const Class *, Arg ...)) nullptr, extra...);
934  }
935 
936  virtual TypeID cpptype()const{return typeid(SvarFunction);}
937  virtual const void* ptr() const{return this;}
938  virtual const Svar& classObject()const;
939 
940  class ScopedStack{
941  public:
942  ScopedStack(std::list<const SvarFunction*>& stack,const SvarFunction* var)
943  :_stack(stack){
944  _stack.push_back(var);
945  }
946  ~ScopedStack(){_stack.pop_back();}
947  std::list<const SvarFunction*>& _stack;
948  };
949 
950  Svar Call(std::vector<Svar> argv)const{
951  thread_local static std::list<const SvarFunction*> stack;
952  ScopedStack scoped_stack(stack,this);
953 
954  const SvarFunction* overload=this;
955  std::vector<SvarExeption> catches;
956  for(;true;overload=&overload->next.as<SvarFunction>()){
957  if(do_argcheck&&overload->arg_types.size()!=argv.size())
958  {
959  if(!overload->next.isFunction()) {
960  overload=nullptr;break;
961  }
962  continue;
963  }
964  try{
965  return overload->_func(argv);
966  }
967  catch(SvarExeption e){
968  catches.push_back(e);
969  }
970  if(!overload->next.isFunction()) {
971  overload=nullptr;break;
972  }
973  }
974 
975  if(!overload){
976  std::stringstream stream;
977  stream<<"Failed to call method "<<getName()<<" with imput arguments: [";
978  for(auto it=argv.begin();it!=argv.end();it++)
979  {
980  stream<<(it==argv.begin()?"":",")<<it->typeName();
981  }
982  stream<<"]\n"<<"Overload candidates:\n"<<(*this)<<std::endl;
983  for(auto it:catches) stream<<it.what()<<std::endl;
984  stream<<"Stack:\n";
985  for(auto& l:stack) stream<<*l;
986  throw SvarExeption(stream.str());
987  }
988 
989  return Svar::Undefined();
990  }
991 
992  template <typename... Args>
993  Svar call(Args... args)const{
994  std::vector<Svar> argv = {
995  (Svar(std::move(args)))...
996  };
997  return Call(argv);
998  }
999 
1000  /// Special internal constructor for functors, lambda functions, methods etc.
1001  template <typename Func, typename Return, typename... Args, typename... Extra>
1002  void initialize(Func &&f, Return (*)(Args...), const Extra&... extra);
1003 
1004  template <typename Func, typename Return, typename... Args,size_t... Is>
1005  detail::enable_if_t<std::is_void<Return>::value, Svar>
1006  call_impl(Func&& f,Return (*)(Args...),std::vector<Svar>& args,detail::index_sequence<Is...>){
1007  f(args[Is].castAs<Args>()...);
1008  return Svar::Undefined();
1009  }
1010 
1011  template <typename Func, typename Return, typename... Args,size_t... Is>
1012  detail::enable_if_t<!std::is_void<Return>::value, Svar>
1013  call_impl(Func&& f,Return (*)(Args...),std::vector<Svar>& args,detail::index_sequence<Is...>){
1014  std::tuple<Args...> castedArgs(args[Is].castAs<Args>()...);
1015  return Svar(f(std::get<Is>(castedArgs)...));
1016  }
1017 
1018  friend std::ostream& operator<<(std::ostream& sst,const SvarFunction& self){
1019  sst<<self.getName()<<"(...)\n";
1020  const SvarFunction* overload=&self;
1021  while(overload){
1022  sst<<" "<<overload->getName()<<overload->signature<<std::endl;
1023  if(!overload->next.isFunction()) {
1024  return sst;
1025  }
1026  overload=&overload->next.as<SvarFunction>();
1027  }
1028  return sst;
1029  }
1030 
1031  std::string getName()const{return name.empty()?"function":name;}
1032  void initName(const std::string& nm){if(name.empty()) name=nm;}
1033 
1034  std::string name,signature;
1035  std::vector<Svar> arg_types;
1036  Svar next;
1037 
1038  std::function<Svar(std::vector<Svar>&)> _func;
1039  bool is_method,is_constructor,do_argcheck=true;
1040 };
1041 
1042 class SvarProperty{
1043 public:
1044  SvarProperty(Svar fget,Svar fset,std::string name,std::string doc)
1045  :_fget(fget),_fset(fset),_name(name),_doc(doc){}
1046 
1047  Svar _fget,_fset;
1048  std::string _name,_doc;
1049 };
1050 
1051 class SvarClass: public SvarValue{
1052 public:
1053  SvarClass(const std::string& name,std::type_index cpp_type,
1054  std::vector<Svar> parents={})
1055  : __name__(name),_cpptype(cpp_type),
1056  _methods(Svar::object()),_attr(Svar::object()),
1057  _parents(parents){}
1058 
1059  virtual TypeID cpptype()const{return typeid(SvarClass);}
1060  virtual const void* ptr() const{return this;}
1061  virtual const Svar& classObject()const{return instance<SvarClass>();}
1062 
1063  std::string name()const{return __name__;}
1064  void setName(const std::string& nm){__name__=nm;}
1065 
1066  SvarClass& def(const std::string& name,const Svar& function,bool isMethod=true)
1067  {
1068  assert(function.isFunction());
1069  Svar* dest=&_methods[name];
1070  while(dest->isFunction())
1071  {
1072  if(dest->as<SvarFunction>().signature==function.as<SvarFunction>().signature)
1073  return *this;
1074  dest=&dest->as<SvarFunction>().next;
1075  }
1076  *dest=function;
1077  dest->as<SvarFunction>().is_method=isMethod;
1078  dest->as<SvarFunction>().name=__name__+"."+name;
1079 
1080 
1081  if(__init__.is<void>()&&name=="__init__") {
1082  __init__=function;
1083  dest->as<SvarFunction>().is_constructor=true;
1084  }
1085  if(__str__.is<void>()&&name=="__str__") __str__=function;
1086  if(__getitem__.is<void>()&&name=="__getitem__") __getitem__=function;
1087  if(__setitem__.is<void>()&&name=="__setitem__") __setitem__=function;
1088  return *this;
1089  }
1090 
1091  SvarClass& def_static(const std::string& name,const Svar& function)
1092  {
1093  return def(name,function,false);
1094  }
1095 
1096  template <typename Func>
1097  SvarClass& def(const std::string& name,Func &&f){
1098  return def(name,Svar::lambda(f),true);
1099  }
1100 
1101  /// Construct a cpp_function from a lambda function (possibly with internal state)
1102  template <typename Func>
1103  SvarClass& def_static(const std::string& name,Func &&f){
1104  return def(name,Svar::lambda(f),false);
1105  }
1106 
1107  SvarClass& def_property(const std::string& name,
1108  const Svar& fget,const Svar& fset=Svar(),
1109  const std::string& doc=""){
1110  _methods[name]=SvarProperty(fget,fset,name,doc);
1111  return *this;
1112  }
1113 
1114  template <typename C, typename D>
1115  SvarClass& def_readwrite(const std::string& name, D C::*pm, const std::string& doc="") {
1116  Svar fget=SvarFunction([pm](const C &c) -> const D &{ return c.*pm; });
1117  Svar fset=SvarFunction([pm](C &c, const D &value) { c.*pm = value;});
1118  fget.as<SvarFunction>().is_method=true;
1119  fset.as<SvarFunction>().is_method=true;
1120  return def_property(name, fget, fset, doc);
1121  }
1122 
1123  template <typename C, typename D>
1124  SvarClass& def_readonly(const std::string& name, D C::*pm, const std::string& doc="") {
1125  Svar fget=SvarFunction([pm](const C &c) -> const D &{ return c.*pm; });
1126  fget.as<SvarFunction>().is_method=true;
1127  return def_property(name, fget, Svar(), doc);
1128  }
1129 
1130  template <typename Base,typename ChildType>
1131  SvarClass& inherit(){
1132  Svar base={SvarClass::instance<Base>(),
1133  Svar::lambda([](ChildType* v){
1134  return dynamic_cast<Base*>(v);
1135  })};
1136  _parents.push_back(base);
1137  return *this;
1138  }
1139 
1140  SvarClass& inherit(std::vector<Svar> parents={}){
1141  _parents=parents;
1142  return *this;
1143  }
1144 
1145  Svar& operator [](const std::string& name){
1146  Svar& c=_methods[name];
1147 // if(!c.isUndefined()) return c;
1148 // for(Svar& p:_parents)
1149 // {
1150 // c=p.as<SvarClass>()[name];
1151 // if(!c.isUndefined()) return c;
1152 // }
1153  return c;
1154  }
1155 
1156  template <typename... Args>
1157  Svar call(const Svar& inst,const std::string function, Args... args)const
1158  {
1159  Svar f=_methods[function];
1160  if(f.isFunction())
1161  {
1162  SvarFunction& func=f.as<SvarFunction>();
1163  if(func.is_method)
1164  return func.call(inst,args...);
1165  else return func.call(args...);
1166  }
1167 
1168  for(const Svar& p:_parents){
1169  try{
1170  if(p.isClass()){
1171  return p.as<SvarClass>().call(inst,function,args...);
1172  }
1173  return p[0].as<SvarClass>().call(p[1](inst),function,args...);
1174  }
1175  catch(SvarExeption e){
1176  continue;
1177  }
1178  }
1179  throw SvarExeption("Class "+__name__+" has no function "+function);
1180  return Svar::Undefined();
1181  }
1182 
1183  Svar Call(const Svar& inst,const std::string function, std::vector<Svar> args)const
1184  {
1185  Svar f=_methods[function];
1186  if(f.isFunction())
1187  {
1188  SvarFunction& func=f.as<SvarFunction>();
1189  if(func.is_method){
1190  args.insert(args.begin(),inst);
1191  return func.Call(args);
1192  }
1193  else return func.Call(args);
1194  }
1195 
1196  for(const Svar& p:_parents){
1197  try{
1198  if(p.isClass()){
1199  return p.as<SvarClass>().Call(inst,function,args);
1200  }
1201  return p[0].as<SvarClass>().Call(p[1](inst),function,args);
1202  }
1203  catch(SvarExeption e){
1204  continue;
1205  }
1206  }
1207  throw SvarExeption("Class "+__name__+" has no function "+function);
1208  return Svar::Undefined();
1209  }
1210 
1211  template <typename T>
1212  static Svar& instance();
1213 
1214  template <typename T>
1215  static SvarClass& Class(){
1216  Svar& inst=instance<T>();
1217  return inst.as<SvarClass>();
1218  }
1219 
1220  friend std::ostream& operator<<(std::ostream& ost,const SvarClass& rh);
1221 
1222  /// buildin functions
1223  Svar __init__,__str__,__getitem__,__setitem__;
1224 
1225  std::string __name__,__doc__;
1226  std::type_index _cpptype;
1227  Svar _methods,_attr;
1228  std::vector<Svar> _parents;
1229 };
1230 
1231 template <typename C>
1232 class Class
1233 {
1234 public:
1235  Class(SvarClass& cls):_cls(cls){}
1236 
1237  Class():_cls(SvarClass::Class<C>()){}
1238 
1239  Class(const std::string& name)
1240  :_cls(SvarClass::Class<C>()){
1241  _cls.setName(name);
1242  svar[name]=SvarClass::instance<C>();
1243  }
1244 
1245  Class& def(const std::string& name,const Svar& function,bool isMethod=true)
1246  {
1247  _cls.def(name,function,isMethod);
1248  return *this;
1249  }
1250 
1251  Class& def_static(const std::string& name,const Svar& function)
1252  {
1253  return def(name,function,false);
1254  }
1255 
1256  template <typename Func>
1257  Class& def(const std::string& name,Func &&f){
1258  return def(name,Svar::lambda(f),true);
1259  }
1260 
1261  /// Construct a cpp_function from a lambda function (possibly with internal state)
1262  template <typename Func>
1263  Class& def_static(const std::string& name,Func &&f){
1264  return def(name,Svar::lambda(f),false);
1265  }
1266 
1267  template <typename ChildType>
1268  Class& inherit(){
1269  _cls.inherit<C,ChildType>();
1270  return *this;
1271  }
1272 
1273  template <typename... Args>
1274  Class& construct(){
1275  return def("__init__",[](Args... args){
1276  return C(args...);
1277  });
1278  }
1279 
1280  Class& def_property(const std::string& name,
1281  const Svar& fget,const Svar& fset=Svar(),
1282  const std::string& doc=""){
1283  _cls.def_property(name,fget,fset,doc);
1284  return *this;
1285  }
1286 
1287  template <typename E, typename D>
1288  Class& def_readwrite(const std::string& name, D E::*pm, const std::string& doc="") {
1289  static_assert(std::is_base_of<E, C>::value, "def_readwrite() requires a class member (or base class member)");
1290 
1291  Svar fget=SvarFunction([pm](const C &c) -> const D &{ return c.*pm; });
1292  Svar fset=SvarFunction([pm](C &c, const D &value) { c.*pm = value;});
1293  fget.as<SvarFunction>().is_method=true;
1294  fset.as<SvarFunction>().is_method=true;
1295  return def_property(name, fget, fset, doc);
1296  }
1297 
1298  template <typename E, typename D>
1299  Class& def_readonly(const std::string& name, D E::*pm, const std::string& doc="") {
1300  static_assert(std::is_base_of<E, C>::value, "def_readonly() requires a class member (or base class member)");
1301  Svar fget=SvarFunction([pm](const C &c) -> const D &{ return c.*pm; });
1302  fget.as<SvarFunction>().is_method=true;
1303  return def_property(name, fget, Svar(), doc);
1304  }
1305 
1306  SvarClass& _cls;
1307 };
1308 
1309 
1310 template <typename T>
1311 Svar& SvarClass::instance()
1312 {
1313  static Svar cl;
1314  if(cl.isClass()) return cl;
1315 #ifdef __GNUC__
1316  int status;
1317  char* realname = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
1318  std::string result(realname);
1319  free(realname);
1320 #else
1321  std::string result(typeid(T).name());
1322 #endif
1323  cl=(SvarValue*)new SvarClass(result,typeid(T));
1324  return cl;
1325 }
1326 
1327 template <typename T>
1328 class SvarValue_: public SvarValue{
1329 public:
1330  explicit SvarValue_(const T& v):_var(v){}
1331  explicit SvarValue_(T&& v):_var(std::move(v)){}
1332 
1333  virtual TypeID cpptype()const{return typeid(T);}
1334  virtual const void* ptr() const{return &_var;}
1335  virtual const Svar& classObject()const{return SvarClass::instance<T>();}
1336  virtual Svar clone(int depth=0)const{return _var;}
1337 //protected:// FIXME: this should not accessed by outside
1338  T _var;
1339 };
1340 
1341 template <>
1342 class SvarValue_<Svar>: public SvarValue{
1343 private:
1344  SvarValue_(const Svar& v){}
1345 };
1346 
1347 template <typename T,typename H=std::shared_ptr<T> >
1348 class SvarPtrHolder: public SvarValue{
1349 public:
1350  explicit SvarPtrHolder(const H& v):_var(v){
1351  }
1352 
1353  virtual TypeID cpptype()const{return typeid(T);}
1354  virtual const void* ptr() const{return _var.get();}
1355  virtual const Svar& classObject()const{return SvarClass::instance<T>();}
1356  virtual Svar clone(int depth=0)const{return _var;}
1357 //protected:// FIXME: this should not accessed by outside
1358  H _var;
1359 };
1360 
1361 template <typename T>
1362 class SvarPtrHolder<T,std::unique_ptr<T>>: public SvarValue{
1363 public:
1364  explicit SvarPtrHolder(std::unique_ptr<T>&& v):_var(std::move(v)){
1365  }
1366 
1367  virtual TypeID cpptype()const{return typeid(T);}
1368  virtual const void* ptr() const{return _var.get();}
1369  virtual const Svar& classObject()const{return SvarClass::instance<T>();}
1370 
1371 //protected:// FIXME: this should not accessed by outside
1372  std::unique_ptr<T> _var;
1373 };
1374 
1375 class SvarObject : public SvarValue_<std::map<std::string,Svar> >{
1376 public:
1377  SvarObject(const std::map<std::string,Svar>& m)
1379  virtual TypeID cpptype()const{return typeid(SvarObject);}
1380  virtual const void* ptr() const{return this;}
1381  virtual size_t length() const {return _var.size();}
1382  virtual std::mutex* accessMutex()const{return &_mutex;}
1383  virtual const Svar& classObject()const{
1384  if(_class.isClass()) return _class;
1385  return SvarClass::instance<SvarObject>();
1386  }
1387 
1388  virtual Svar clone(int depth=0)const{
1389  std::unique_lock<std::mutex> lock(_mutex);
1390  if(!depth)
1391  return _var;
1392  std::map<std::string,Svar> var=_var;
1393  for(auto it=var.begin();it!=var.end();it++){
1394  it->second=it->second.clone(depth-1);
1395  }
1396  return var;
1397  }
1398 
1399  Svar operator[](const std::string &key)const {//get
1400  std::unique_lock<std::mutex> lock(_mutex);
1401  auto it=_var.find(key);
1402  if(it==_var.end()){
1403  return Svar::Undefined();
1404  }
1405  return it->second;
1406  }
1407 
1408  void set(const std::string &key,const Svar& value){
1409  std::unique_lock<std::mutex> lock(_mutex);
1410  _var[key]=value;
1411  }
1412 
1413  void update(Svar rh){
1414  if(!rh.isObject()) return;
1415  std::unique_lock<std::mutex> lock(_mutex);
1416  auto cp=rh.as<SvarObject>()._var;
1417  for(auto it:cp){
1418  auto old=_var.find(it.first);
1419  if(old==_var.end())
1420  _var[it.first]=it.second;
1421  else if(old->second.isObject()&&it.second.isObject())
1422  old->second.as<SvarObject>().update(it.second);
1423  else old->second=it.second;
1424  }
1425  }
1426 
1427  bool exist(const std::string& id)const{
1428  std::unique_lock<std::mutex> lock(_mutex);
1429  return _var.count(id);
1430  }
1431 
1432  void erase(const std::string& id){
1433  std::unique_lock<std::mutex> lock(_mutex);
1434  _var.erase(id);
1435  }
1436 
1437  Svar iter(){
1438  static Svar objectinteratorClass;
1439  if(!objectinteratorClass.isClass()){
1440  SvarClass* cls=new SvarClass("objectiterator",typeid(SvarObject));
1441  objectinteratorClass=(SvarValue*)cls;
1442  cls->def("next",[](Svar iter){
1443  SvarObject* obj=iter.as<SvarObject>()["object"].as<SvarObject*>();
1444  typedef std::map<std::string,Svar>::iterator Iter;
1445  Iter it=iter.as<SvarObject>()["iter"].as<Iter>();
1446  if(it!=obj->_var.end()){
1447  auto kv=*(it++);
1448  return Svar::array({kv.first,kv.second});
1449  }
1450  return Svar();
1451  });
1452  }
1453  Svar iter=Svar::object({{"object",this},{"iter",Svar::create(_var.begin())}});
1454  iter.as<SvarObject>()._class=objectinteratorClass;
1455  return iter;
1456  }
1457 
1458  friend std::ostream& operator<<(std::ostream& ost,const SvarObject& rh){
1459  std::unique_lock<std::mutex> lock(rh._mutex);
1460  if(rh._var.empty()) {
1461  ost<<"{}";return ost;
1462  }
1463  ost<<"{\n";
1464  std::stringstream context;
1465  for(auto it=rh._var.begin();it!=rh._var.end();it++)
1466  {
1467  context<<(it==rh._var.begin()?"":",\n")<<Svar(it->first)<<" : "<<it->second;
1468  }
1469  std::string line;
1470  while(std::getline(context,line)) ost<<" "<<line<<std::endl;
1471  ost<<"}";
1472  return ost;
1473  }
1474 
1475  mutable std::mutex _mutex;
1476  Svar _class;
1477 };
1478 
1479 class SvarArray : public SvarValue_<std::vector<Svar> >{
1480 public:
1481  SvarArray(const std::vector<Svar>& v)
1483  virtual TypeID cpptype()const{return typeid(SvarArray);}
1484  virtual const void* ptr() const{return this;}
1485  virtual const Svar& classObject()const{return SvarClass::instance<SvarArray>();}
1486  virtual size_t length() const {return _var.size();}
1487  virtual std::mutex* accessMutex()const{return &_mutex;}
1488  virtual const Svar& operator[](size_t i) {
1489  std::unique_lock<std::mutex> lock(_mutex);
1490  if(i<_var.size()) return _var[i];
1491  return Svar::Undefined();
1492  }
1493 
1494  virtual Svar clone(int depth=0)const{
1495  std::unique_lock<std::mutex> lock(_mutex);
1496  if(!depth)
1497  return _var;
1498  std::vector<Svar> var=_var;
1499  for(auto& it:var){
1500  it=it.clone();
1501  }
1502  return var;
1503  }
1504 
1505  friend std::ostream& operator<<(std::ostream& ost,const SvarArray& rh){
1506  std::unique_lock<std::mutex> lock(rh._mutex);
1507  if(rh._var.empty()) {
1508  ost<<"[]";return ost;
1509  }
1510  ost<<"[\n";
1511  std::stringstream context;
1512  for(size_t i=0;i<rh._var.size();++i)
1513  context<<rh._var[i]<<(i+1==rh._var.size()?"\n":",\n");
1514  std::string line;
1515  while(std::getline(context,line)) ost<<" "<<line<<std::endl;
1516  ost<<"]";
1517  return ost;
1518  }
1519 
1520  Svar operator+(Svar other){
1521  std::unique_lock<std::mutex> lock(_mutex);
1522  std::vector<Svar> ret=_var;
1523  if(other.isArray()){
1524  SvarArray& rh=other.as<SvarArray>();
1525  std::unique_lock<std::mutex> lock(rh._mutex);
1526  ret.insert(ret.end(),rh._var.begin(),rh._var.end());
1527  }
1528  else ret.push_back(other);
1529  return Svar::array(ret);
1530  }
1531 
1532  void append(Svar other){
1533  std::unique_lock<std::mutex> lock(_mutex);
1534  _var.push_back(other);
1535  }
1536 
1537  void erase(int idx){
1538  std::unique_lock<std::mutex> lock(_mutex);
1539  _var.erase(_var.begin()+idx);
1540  }
1541 
1542  mutable std::mutex _mutex;
1543 };
1544 
1545 class SvarDict : public SvarValue_<std::map<Svar,Svar> >{
1546 public:
1547  SvarDict(const std::map<Svar,Svar>& dict)
1549 
1550  }
1551  virtual size_t length() const {return _var.size();}
1552  virtual std::mutex* accessMutex()const{return &_mutex;}
1553  virtual Svar operator[](const Svar& i) {
1554  std::unique_lock<std::mutex> lock(_mutex);
1555  auto it=_var.find(i);
1556  if(it!=_var.end()) return it->second;
1557  return Svar::Undefined();
1558  }
1559  void erase(const Svar& id){
1560  std::unique_lock<std::mutex> lock(_mutex);
1561  _var.erase(id);
1562  }
1563  mutable std::mutex _mutex;
1564 };
1565 
1566 class SvarBuffer : public SvarValue
1567 {
1568 public:
1569  SvarBuffer(const void* ptr,size_t size,Svar holder=Svar())
1570  : _ptr(ptr),_size(size),_holder(holder){}
1571 
1572  SvarBuffer(size_t size):_size(size){
1573  _holder = Svar::create(std::vector<char>(size));
1574  _ptr = _holder.as<std::vector<char>>().data();
1575  }
1576 
1577  SvarBuffer(const void* ptr,size_t size,const std::vector<int>& shape,
1578  const std::string& format,Svar holder)
1579  : _ptr(ptr),_size(size)
1580  {
1581  _holder={{"holder",holder},{"format",format},{"shape",shape}};
1582  }
1583 
1584  static SvarBuffer load(std::string path){
1585  std::ifstream in(path,std::ios::in|std::ios::binary);
1586  if(in.is_open()){
1587  std::string* file = new std::string( (std::istreambuf_iterator<char>(in)) , std::istreambuf_iterator<char>() );
1588  return SvarBuffer(file->data(),file->size(),std::unique_ptr<std::string>(file));
1589  }
1590  std::cout<<"Wrong path!"<<std::endl;
1591  return SvarBuffer(nullptr,0,Svar::Null());
1592  }
1593 
1594  bool save(std::string path){
1595  std::ofstream out(path,std::ios_base::out);
1596  if(out.is_open()){
1597  out.write((const char*)_ptr,_size);
1598  out.close();
1599  return true;
1600  }
1601  return false;
1602  }
1603 
1604  /// Transformation between hex and SvarBuffer
1605  std::string hex()const{
1606  const std::string h = "0123456789ABCDEF";
1607  std::string ret;ret.resize(_size*2);
1608  for(size_t i=0;i<_size;i++){
1609  ret[i<<1]=h[((uint8_t*)_ptr)[i] >> 4];
1610  ret[(i<<1)+1]=h[((uint8_t*)_ptr)[i] & 0xf];
1611  }
1612  return ret;
1613  }
1614 
1615  static SvarBuffer fromHex(const std::string& h){
1616  size_t n = h.size()>>1;
1617  SvarBuffer ret(n);
1618  for(size_t i=0;i < n;i++){
1619  ((uint8_t*)(ret._ptr))[i]=strtol(h.substr(i<<1,2).c_str(),nullptr,16);
1620  }
1621  return ret;
1622  }
1623 
1624  /// Transformation between base64 and string
1625  std::string base64() const {
1626  const unsigned char * bytes_to_encode=(unsigned char*)_ptr;
1627  size_t in_len=_size;
1628  const std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";;
1629  std::string ret;
1630  int i = 0;
1631  int j = 0;
1632  unsigned char char_array_3[3];
1633  unsigned char char_array_4[4];
1634 
1635  while (in_len--) {
1636  char_array_3[i++] = *(bytes_to_encode++);
1637  if (i == 3) {
1638  char_array_4[0] = (unsigned char) ((char_array_3[0] & 0xfc) >> 2);
1639  char_array_4[1] = (unsigned char) ( ( ( char_array_3[0] & 0x03 ) << 4 ) + ( ( char_array_3[1] & 0xf0 ) >> 4 ) );
1640  char_array_4[2] = (unsigned char) ( ( ( char_array_3[1] & 0x0f ) << 2 ) + ( ( char_array_3[2] & 0xc0 ) >> 6 ) );
1641  char_array_4[3] = (unsigned char) ( char_array_3[2] & 0x3f );
1642 
1643  for(i = 0; (i <4) ; i++)
1644  ret += chars[char_array_4[i]];
1645  i = 0;
1646  }
1647  }
1648 
1649  if (i)
1650  {
1651  for(j = i; j < 3; j++)
1652  char_array_3[j] = '\0';
1653 
1654  char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
1655  char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
1656  char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
1657  char_array_4[3] = char_array_3[2] & 0x3f;
1658 
1659  for (j = 0; (j < i + 1); j++)
1660  ret += chars[char_array_4[j]];
1661 
1662  while((i++ < 3))
1663  ret += '=';
1664 
1665  }
1666 
1667  return ret;
1668  }
1669 
1670  static SvarBuffer fromBase64(const std::string& h){
1671  const std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";;
1672  size_t in_len = h.size();
1673  size_t i = 0;
1674  size_t j = 0;
1675  int in_ = 0;
1676  unsigned char char_array_4[4], char_array_3[3];
1677  std::string* ret = new std::string;
1678  auto is_base64=[](unsigned char c) {
1679  return (isalnum(c) || (c == '+') || (c == '/'));
1680  };
1681 
1682  while (in_len-- && ( h[in_] != '=') && is_base64(h[in_])) {
1683  char_array_4[i++] = h[in_]; in_++;
1684  if (i ==4) {
1685  for (i = 0; i <4; i++)
1686  char_array_4[i] = (unsigned char) chars.find( char_array_4[i] );
1687 
1688  char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
1689  char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
1690  char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
1691 
1692  for (i = 0; (i < 3); i++)
1693  *ret += char_array_3[i];
1694  i = 0;
1695  }
1696  }
1697 
1698  if (i) {
1699  for (j = i; j <4; j++)
1700  char_array_4[j] = 0;
1701 
1702  for (j = 0; j <4; j++)
1703  char_array_4[j] = (unsigned char) chars.find( char_array_4[j] );
1704 
1705  char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
1706  char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
1707  char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
1708 
1709  for (j = 0; (j < i - 1); j++) *ret += char_array_3[j];
1710  }
1711 
1712  return SvarBuffer(ret->data(),ret->size(),std::unique_ptr<std::string>(ret));
1713  }
1714 
1715  /// MD5 value
1716  std::string md5(){
1717  const std::string hexs = "0123456789ABCDEF";
1718  uint32_t atemp=0x67452301,btemp=0xefcdab89,
1719  ctemp=0x98badcfe,dtemp=0x10325476;
1720  const unsigned int k[]={
1721  0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
1722  0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,
1723  0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,
1724  0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,
1725  0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
1726  0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,
1727  0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,
1728  0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,
1729  0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
1730  0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,
1731  0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,
1732  0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,
1733  0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391
1734  };//64
1735  const unsigned int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7,
1736  12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
1737  4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,
1738  15,21,6,10,15,21,6,10,15,21,6,10,15,21};
1739 
1740  std::function<uint32_t(uint32_t,uint32_t)> shift = [](uint32_t x,uint32_t n){
1741  return (x<<n)|(x>>(32-n));
1742  };
1743  std::vector<std::function<uint32_t(uint32_t,uint32_t,uint32_t)> > funcs ={
1744  [](uint32_t x,uint32_t y,uint32_t z){return (x & y)| (~x & z);},
1745  [](uint32_t x,uint32_t y,uint32_t z){return (x & z)| (y & ~z);},
1746  [](uint32_t x,uint32_t y,uint32_t z){return (x ^ y ^ z);},
1747  [](uint32_t x,uint32_t y,uint32_t z){return (y ^ (x | ~z));}};
1748  std::vector<std::function<uint8_t(uint8_t)> > func_g ={
1749  [](uint8_t i){return i;},
1750  [](uint8_t i){return (5*i+1)%16;},
1751  [](uint8_t i){return (3*i+5)%16;},
1752  [](uint8_t i){return (7*i)%16;}};
1753 
1754  std::function<void(std::vector<uint32_t>&,int) > mainloop = [&](std::vector<uint32_t>& v,int step) -> void{
1755  unsigned int f,g;
1756  unsigned int a=atemp;
1757  unsigned int b=btemp;
1758  unsigned int c=ctemp;
1759  unsigned int d=dtemp;
1760  for(uint8_t i;i<64;i++){
1761  f=funcs[i>>4](b,c,d);
1762  g=func_g[i>>4](i);
1763  unsigned int tmp=d;
1764  d=c;
1765  c=b;
1766  b=b+shift((a+f+k[i]+v[step*16+g]),s[i]);
1767  a=tmp;
1768  }
1769  atemp=a+atemp;
1770  btemp=b+btemp;
1771  ctemp=c+ctemp;
1772  dtemp=d+dtemp;
1773  };
1774  std::function<std::string(int)> int2hexstr = [&](int i) -> std::string {
1775  std::string s;
1776  s.resize(8);
1777  for(int j=0;j<4;j++){
1778  uint8_t b = (i>>(j*8))%(1<<8);
1779  s[2*j] = hexs[b>>4];
1780  s[2*j+1] = hexs[b%16];
1781  }
1782  return s;
1783  };
1784 
1785 
1786  //fill data
1787  int total_groups = (_size+8)/64+1;
1788  int total_ints = total_groups*16;
1789  std::vector<uint32_t> vec(total_ints,0);
1790  for(size_t i = 0; i < _size; i++)
1791  vec[i>>2] |= (((const char*)_ptr)[i]) << ((i%4)*8);
1792  vec[_size>>2] |= 0x80 << (_size%4*8);
1793  uint64_t size = _size*8;
1794  vec[total_ints-2] = size & UINT_LEAST32_MAX;
1795  vec[total_ints-1] = size>>32;
1796 
1797  //loop calculate
1798  for(int i = 0; i < total_groups; i++){
1799  mainloop(vec,i);
1800  }
1801  return int2hexstr(atemp)\
1802  .append(int2hexstr(btemp))\
1803  .append(int2hexstr(ctemp))\
1804  .append(int2hexstr(dtemp));
1805  }
1806 
1807  friend std::ostream& operator<<(std::ostream& ost,const SvarBuffer& b){
1808  ost<<b.hex();
1809  return ost;
1810  }
1811 
1812  SvarBuffer clone(){
1813  SvarBuffer buf(_size);
1814  memcpy((void*)buf._ptr,_ptr,_size);
1815  return buf;
1816  }
1817 
1818  virtual TypeID cpptype()const{return typeid(SvarBuffer);}
1819  virtual const void* ptr() const{return this;}
1820  virtual const Svar& classObject()const{return SvarClass::instance<SvarBuffer>();}
1821  virtual size_t length() const {return _size;}
1822 
1823  const void* _ptr;
1824  size_t _size;
1825  Svar _holder;
1826 };
1827 
1828 inline const Svar& SvarValue::classObject()const{return SvarClass::instance<void>();}
1829 
1830 /// Special internal constructor for functors, lambda functions, methods etc.
1831 template <typename Func, typename Return, typename... Args, typename... Extra>
1832 void SvarFunction::initialize(Func &&f, Return (*)(Args...), const Extra&... extra)
1833 {
1834  std::vector<Svar> types={SvarClass::instance<Args>()...};
1835  std::stringstream signature;signature<<"(";
1836  for(size_t i=0;i<types.size();i++)
1837  signature<<types[i].as<SvarClass>().name()<<(i+1==types.size()?"":",");
1838  signature<<")->";
1839  signature<<Svar::type_id<Return>();
1840  this->signature=signature.str();
1841  this->arg_types=types;
1842  _func=[this,f](std::vector<Svar>& args)->Svar{
1843  using indices = detail::make_index_sequence<sizeof...(Args)>;
1844  return call_impl(f,(Return (*) (Args...)) nullptr,args,indices{});
1845  };
1846  is_constructor=false;
1847 }
1848 
1849 template <typename T>
1850 inline std::string Svar::toString(const T& def) {
1851  std::ostringstream sst;
1852  sst << def;
1853  return sst.str();
1854 }
1855 
1856 template <>
1857 inline std::string Svar::toString(const std::string& def) {
1858  return def;
1859 }
1860 
1861 template <>
1862 inline std::string Svar::toString(const double& def) {
1863  using namespace std;
1864  ostringstream ost;
1865  ost << setprecision(12) << def;
1866  return ost.str();
1867 }
1868 
1869 template <>
1870 inline std::string Svar::toString(const bool& def) {
1871  return def ? "true" : "false";
1872 }
1873 
1874 template <typename T>
1875 std::string Svar::type_id(){
1876  return SvarClass::Class<T>().name();
1877 // return typeName(typeid(T).name());
1878 }
1879 
1880 
1881 inline Svar::Svar(const std::initializer_list<Svar>& init)
1882  :Svar()
1883 {
1884  bool is_an_object = std::all_of(init.begin(), init.end(),
1885  [](const Svar& ele)
1886  {
1887  return ele.isArray() && ele.length() == 2 && ele[0].is<std::string>();
1888  });
1889 
1890  if(is_an_object){
1891  std::map<std::string,Svar> obj;
1892  for(const Svar& p:init) obj.insert(std::make_pair(p[0].as<std::string>(),p[1]));
1893  *this=Svar(obj);
1894  return;
1895  }
1896 
1897  *this=Svar(std::vector<Svar>(init));
1898 }
1899 
1900 template <typename Return, typename... Args, typename... Extra>
1901 Svar::Svar(Return (*f)(Args...), const Extra&... extra)
1902  :_obj(std::make_shared<SvarFunction>(f,extra...)){}
1903 
1904 /// Construct a cpp_function from a lambda function (possibly with internal state)
1905 template <typename Func, typename... Extra>
1906 Svar Svar::lambda(Func &&f, const Extra&... extra)
1907 {
1908  return Svar(((SvarValue*)new SvarFunction(f,extra...)));
1909 }
1910 
1911 /// Construct a cpp_function from a class method (non-const)
1912 template <typename Return, typename Class, typename... Args, typename... Extra>
1913 Svar::Svar(Return (Class::*f)(Args...), const Extra&... extra)
1914  :_obj(std::make_shared<SvarFunction>(f,extra...)){}
1915 
1916 /// Construct a cpp_function from a class method (const)
1917 template <typename Return, typename Class, typename... Args, typename... Extra>
1918 Svar::Svar(Return (Class::*f)(Args...) const, const Extra&... extra)
1919  :_obj(std::make_shared<SvarFunction>(f,extra...)){}
1920 
1921 #if (__GNUC__>=5)||defined(__clang__)
1922 template <class T>
1923 inline Svar Svar::create(T & t)
1924 {
1925  return (SvarValue*)new SvarValue_<typename std::remove_const<T>::type >(const_cast<T&>(t));
1926 }
1927 
1928 template <>
1929 inline Svar Svar::create<const Svar>(const Svar & t)
1930 {
1931  return t;
1932 }
1933 
1934 template <>
1935 inline Svar Svar::create<Svar>(Svar & t)
1936 {
1937  return t;
1938 }
1939 
1940 #else
1941 template <class T>
1942 inline Svar Svar::create(const T & t)
1943 {
1944  return (SvarValue*)new SvarValue_<T>(t);
1945 }
1946 
1947 template <>
1948 inline Svar Svar::create(const Svar & t)
1949 {
1950  return t;
1951 }
1952 #endif
1953 
1954 
1955 template <class T>
1956 inline Svar Svar::create(T && t)
1957 {
1958  return (SvarValue*)new SvarValue_<typename std::remove_reference<T>::type>(std::move(t));
1959 }
1960 
1961 template <>
1962 inline Svar Svar::create<Svar>( Svar && t)
1963 {
1964  return std::move(t);
1965 }
1966 
1967 inline Svar::Svar(const std::string& m)
1968  :_obj(std::make_shared<SvarValue_<std::string>>(m)){}
1969 
1970 inline Svar::Svar(const std::vector<Svar>& vec)
1971  :_obj(std::make_shared<SvarArray>(vec)){}
1972 
1973 inline Svar::Svar(const std::map<std::string,Svar>& m)
1974  :_obj(std::make_shared<SvarObject>(m)){}
1975 
1976 inline Svar::Svar(const std::map<Svar,Svar>& m)
1977  :_obj(std::make_shared<SvarDict>(m)){}
1978 
1979 template <typename T>
1980 Svar::Svar(std::unique_ptr<T>&& v)
1981  : _obj(std::make_shared<SvarPtrHolder<T,std::unique_ptr<T>>>(std::move(v))){}
1982 
1983 template <>
1984 inline Svar::Svar(const std::shared_ptr<SvarValue>& v)
1985  : _obj(v?v:Null().value()){}
1986 
1987 inline Svar operator"" _svar(const char* str,size_t sz){
1988  return Svar::instance()["__builtin__"]["Json"].call("load",std::string(str,sz));
1989 }
1990 
1991 template <typename T>
1992 inline bool Svar::is()const{return _obj->cpptype()==typeid(T);}
1993 inline bool Svar::is(const std::type_index& typeId)const{return _obj->cpptype()==typeId;}
1994 inline bool Svar::is(const std::string& typeStr)const{return _obj->cpptype().name()==typeStr;}
1995 
1996 template <>
1997 inline bool Svar::is<Svar>()const{return !isUndefined();}
1998 
1999 inline bool Svar::isNull()const{
2000  return Null()==(*this);
2001 }
2002 
2003 inline bool Svar::isObject() const{
2004  return std::dynamic_pointer_cast<SvarObject>(_obj)!=nullptr;
2005 }
2006 
2007 inline bool Svar::isArray()const{
2008  return std::dynamic_pointer_cast<SvarArray>(_obj)!=nullptr;
2009 }
2010 
2011 inline bool Svar::isDict()const{
2012  return std::dynamic_pointer_cast<SvarDict>(_obj)!=nullptr;
2013 }
2014 
2015 template <typename T>
2016 inline const T& Svar::as()const{
2017  assert(is<T>());
2018  return *(T*)_obj->ptr();
2019 }
2020 
2021 template <>
2022 inline const Svar& Svar::as<Svar>()const{
2023  return *this;
2024 }
2025 
2026 template <typename T>
2027 T& Svar::as(){
2028  return *(T*)_obj->ptr();
2029 }
2030 
2031 template <>
2032 inline Svar& Svar::as<Svar>(){
2033  return *this;
2034 }
2035 
2036 template <typename T>
2037 class caster{
2038 public:
2039  static Svar from(const Svar& var){
2040  if(var.is<T>()) return var;
2041 
2042  Svar cl=var.classObject();
2043  if(cl.isClass()){
2044  SvarClass& srcClass=cl.as<SvarClass>();
2045  Svar cvt=srcClass._methods["__"+Svar::type_id<T>()+"__"];
2046  if(cvt.isFunction()){
2047  Svar ret=cvt(var);
2048  if(ret.is<T>()) return ret;
2049  }
2050  }
2051 
2052  SvarClass& destClass=SvarClass::instance<T>().template as<SvarClass>();
2053  if(destClass.__init__.isFunction()){
2054  Svar ret=destClass.__init__(var);
2055  if(ret.is<T>()) return ret;
2056  }
2057 
2058  return Svar::Undefined();
2059  }
2060 
2061  static Svar to(const T& var){
2062  return Svar::create(var);
2063  }
2064 };
2065 
2066 template <typename T>
2067 Svar::Svar(const T& var):Svar(caster<T>::to(var))
2068 {}
2069 
2070 inline Svar Svar::cast(const std::string& typeStr)const
2071 {
2072  if(is(typeStr)) return (*this);
2073 
2074  Svar cl=_obj->classObject();
2075  if(cl.isClass()){
2076  SvarClass& srcClass=cl.as<SvarClass>();
2077  Svar cvt=srcClass._methods["__"+typeStr+"__"];
2078  if(cvt.isFunction()){
2079  Svar ret=cvt(*this);
2080  if(ret.is(typeStr)) return ret;
2081  }
2082  }
2083  return Undefined();
2084 }
2085 
2086 template <typename T>
2087 Svar Svar::cast()const{
2088  Svar ret=caster<T>::from(*this);
2089  if(ret.is<T>()) return ret;
2090 
2091  return Undefined();
2092 }
2093 
2094 template <typename T>
2095 detail::enable_if_t<!std::is_reference<T>::value&&!std::is_pointer<T>::value,T>
2096 Svar::castAs()const
2097 {
2098  auto ret=cast<T>();
2099  if(!ret.template is<T>())
2100  throw SvarExeption("Unable cast "+typeName()+" to "+type_id<T>());
2101  return ret.template as<T>();// let compiler happy
2102 }
2103 
2104 template <typename T>
2105 detail::enable_if_t<std::is_reference<T>::value,T&>
2106 Svar::castAs(){
2107  if(!is<typename std::remove_reference<T>::type>())
2108  throw SvarExeption("Unable cast "+typeName()+" to "+type_id<T>());
2109 
2110  return as<typename std::remove_reference<T>::type>();
2111 }
2112 
2113 template <typename T>
2114 detail::enable_if_t<std::is_pointer<T>::value,T>
2115 Svar::castAs(){
2116  // nullptr
2117  if(isNull()) return (T)nullptr;
2118  // T* -> T*
2119  if(is<T>()) return as<T>();
2120 
2121  // T* -> T const*
2122  if(is<typename std::remove_const<typename std::remove_pointer<T>::type>::type*>())
2123  return as<typename std::remove_const<typename std::remove_pointer<T>::type>::type*>();
2124 
2125  // T -> T*
2126  if(is<typename std::remove_pointer<T>::type>())
2127  return &as<typename std::remove_pointer<T>::type>();
2128 
2129  auto ret=cast<T>();
2130  if(!ret.template is<T>())
2131  throw SvarExeption("Unable cast "+typeName()+" to "+type_id<T>());
2132  return ret.template as<T>();// let compiler happy
2133 }
2134 
2135 template <>
2136 inline Svar Svar::castAs<Svar>()const{
2137  return *this;
2138 }
2139 
2140 inline Svar Svar::clone(int depth)const{return _obj->clone(depth);}
2141 
2142 inline std::string Svar::typeName()const{
2143  return classPtr()->name();
2144 }
2145 
2146 inline SvarValue::TypeID Svar::cpptype()const{
2147  return _obj->cpptype();
2148 }
2149 
2150 inline const Svar& Svar::classObject()const{
2151  return _obj->classObject();
2152 }
2153 
2154 inline SvarClass* Svar::classPtr()const
2155 {
2156  auto clsObj=classObject();
2157  if(clsObj.isClass()) return &clsObj.as<SvarClass>();
2158  return nullptr;
2159 }
2160 
2161 inline size_t Svar::length() const{
2162  return _obj->length();
2163 }
2164 
2165 inline Svar Svar::operator[](const Svar& i) const{
2166  if(isObject()) return as<SvarObject>()[i.castAs<std::string>()];
2167  if(classObject().is<void>()) return Undefined();
2168  const SvarClass& cl=classObject().as<SvarClass>();
2169  if(cl.__getitem__.isFunction()){
2170  return cl.__getitem__((*this),i);
2171  }
2172  return Undefined();
2173 }
2174 
2175 inline Svar& Svar::operator[](const Svar& name){
2176  if(isUndefined()) {
2177  *this=object();
2178  }
2179 
2180  if(isObject())
2181  return getOrCreate(name.castAs<std::string>());
2182  else if(isArray())
2183  return as<SvarArray>()._var[name.castAs<int>()];
2184  else if(isDict())
2185  return as<SvarDict>()._var[name];
2186  else if(isClass())
2187  return as<SvarClass>()[name.castAs<std::string>()];
2188  throw SvarExeption(typeName()+": Operator [] can't be used as a lvalue.");
2189  return *this;
2190 }
2191 
2192 inline Svar Svar::get(const std::string& name,Svar def,bool parse_dot)
2193 {
2194  if(parse_dot){
2195  auto idx = name.find_first_of(".");
2196  if (idx != std::string::npos) {
2197  return getOrCreate(name.substr(0, idx)).get(name.substr(idx + 1), def,parse_dot);
2198  }
2199  }
2200 
2201  Svar var;
2202 
2203  if(isUndefined())
2204  *this=object();// force to be an object
2205  else if(isObject())
2206  {
2207  var=as<SvarObject>()[name];
2208  }
2209  else throw SvarExeption("Can not get an item from "+typeName());
2210 
2211  if(var.isUndefined()){
2212  set(name,def);// value type changed
2213  return def;
2214  }
2215  else return var;
2216 }
2217 
2218 template <typename T>
2219 T& Svar::get(const std::string& name,T def,bool parse_dot){
2220  if(parse_dot){
2221  auto idx = name.find_first_of(".");
2222  if (idx != std::string::npos) {
2223  return getOrCreate(name.substr(0, idx)).get(name.substr(idx + 1), def,parse_dot);
2224  }
2225  }
2226  Svar var;
2227 
2228  if(isUndefined())
2229  *this=object();// force to be an object
2230  else if(isObject())
2231  {
2232  var=as<SvarObject>()[name];
2233  }
2234  else throw SvarExeption("Can not get an item from "+typeName());
2235 
2236  if(var.is<T>()) return var.as<T>();
2237 
2238  if(!var.isUndefined()){
2239  Svar casted=var.cast<T>();
2240  if(casted.is<T>()){
2241  var=casted;
2242  }
2243  else if(var.is<std::string>()){
2244  var=Svar::create(fromString(var.as<std::string>(),def));
2245  }
2246  else var=Svar::create(def);
2247  }
2248  else
2249  var=Svar::create(def);
2250  set(name,var);// value type changed
2251 
2252  return var.as<T>();
2253 }
2254 
2255 
2256 inline Svar& Svar::getOrCreate(const std::string& name,bool parse_dot)
2257 {
2258  if(parse_dot){
2259  auto idx = name.find_last_of('.');
2260  if (idx != std::string::npos) {
2261  return getOrCreate(name.substr(0, idx),parse_dot).getOrCreate(name.substr(idx + 1));
2262  }
2263  }
2264  if(isUndefined()) {
2265  *this=object();
2266  }
2267  if(!isObject())
2268  throw SvarExeption("Svar::Get can only be called with an object, got "+ typeName());
2269  SvarObject& obj=as<SvarObject>();
2270 
2271  {
2272  std::unique_lock<std::mutex> lock(obj._mutex);
2273  auto it=obj._var.find(name);
2274  if(it!=obj._var.end())
2275  return it->second;
2276  auto ret=obj._var.insert(std::make_pair(name,Svar()));
2277  return ret.first->second;
2278  }
2279 // return Undefined();
2280 }
2281 
2282 template <typename T>
2283 inline void Svar::set(const std::string& name,const T& def,bool parse_dot){
2284  if(parse_dot){
2285  auto idx = name.find(".");
2286  if (idx != std::string::npos) {
2287  return getOrCreate(name.substr(0, idx)).set(name.substr(idx + 1), def);
2288  }
2289  }
2290  if(isUndefined()){
2291  *this=object({{name,Svar::create(def)}});
2292  return;
2293  }
2294  assert(isObject());
2295  Svar var=as<SvarObject>()[name];
2296  if(!std::is_same<T,Svar>::value&&var.is<T>())
2297  var.as<T>()=def;
2298  else
2299  as<SvarObject>().set(name,Svar::create(def));
2300 }
2301 
2302 inline bool Svar::exist(const Svar& id)const
2303 {
2304  if(isObject())
2305  {
2306  std::string name=id.castAs<std::string>();
2307 #ifdef SVAR_PARSE_DOT
2308  auto idx = name.find('.');
2309  if (idx != std::string::npos) {
2310  Svar child=as<SvarObject>()[name.substr(0, idx)];
2311  return child.exist(name.substr(idx + 1));
2312  }
2313 #endif
2314  return as<SvarObject>().exist(name);
2315  }
2316  return !(*this)[id].isUndefined();
2317 }
2318 
2319 inline void Svar::erase(const Svar& id)
2320 {
2321  if(isObject())
2322  {
2323  std::string name=id.castAs<std::string>();
2324 #ifdef SVAR_PARSE_DOT
2325  auto idx = name.find('.');
2326  if (idx != std::string::npos) {
2327  Svar child=as<SvarObject>()[name.substr(0, idx)];
2328  return child.erase(name.substr(idx + 1));
2329  }
2330 #endif
2331  return as<SvarObject>().erase(name);
2332  }
2333  call("__delitem__",id);
2334 }
2335 
2336 inline void Svar::push_back(const Svar& rh)
2337 {
2338  assert(isArray());
2339  as<SvarArray>().append(rh);
2340 }
2341 
2342 template <typename... Args>
2343 Svar Svar::call(const std::string function, Args... args)const
2344 {
2345  // call as static methods without check
2346  if(isClass()) return as<SvarClass>().call(Svar(),function,args...);
2347  // call when func member available
2348 // Svar func=(*this)[function];
2349 // if(func.isFunction()) return func(args...);
2350  // call as member methods with check
2351  auto clsPtr=classPtr();
2352  if(!clsPtr) throw SvarExeption("Unable to call "+typeName()+"."+function);
2353  return clsPtr->call(*this,function,args...);
2354 }
2355 
2356 template <typename... Args>
2357 Svar Svar::operator()(Args... args)const{
2358  if(isFunction())
2359  return as<SvarFunction>().call(args...);
2360  else if(isClass()){
2361  const SvarClass& cls=as<SvarClass>();
2362  if(!cls.__init__.isFunction())
2363  throw SvarExeption("Class "+cls.__name__+" does not have __init__ function.");
2364  return cls.__init__(args...);
2365  }
2366  throw SvarExeption(typeName()+" can't be called as a function or constructor.");
2367  return Undefined();
2368 }
2369 
2370 inline Svar& Svar::def(const std::string& name,Svar funcOrClass)
2371 {
2372  if(funcOrClass.isFunction()){
2373  funcOrClass.as<SvarFunction>().initName(name);
2374  Svar old=(*this)[name];
2375  if(!old.isFunction()){
2376  set(name,funcOrClass);
2377  }else{
2378  SvarFunction& oldF=old.as<SvarFunction>();
2379  if(oldF.signature!=funcOrClass.as<SvarFunction>().signature)
2380  oldF.next=funcOrClass;
2381  }
2382  }
2383  else if(funcOrClass.isClass()){
2384  set(name,funcOrClass);
2385  }
2386  else throw SvarExeption("Svar::def can only define a function or class.");
2387  return *this;
2388 }
2389 
2390 inline std::vector<std::string> Svar::parseMain(int argc, char** argv) {
2391  using namespace std;
2392  // save main cmd things
2393  GetInt("argc") = argc;
2394  set("argv",argv);
2395  set("ProgramName",getFileName(argv[0]));
2396  auto setvar=[this](std::string s)->bool{
2397  // Execution failed. Maybe its an assignment.
2398  std::string::size_type n = s.find("=");
2399  bool shouldOverwrite = true;
2400 
2401  if (n != std::string::npos) {
2402  std::string var = s.substr(0, n);
2403  std::string val = s.substr(n + 1);
2404 
2405  // Strip whitespace from around var;
2406  std::string::size_type s = 0, e = var.length() - 1;
2407  if ('?' == var[e]) {
2408  e--;
2409  shouldOverwrite = false;
2410  }
2411  for (; std::isspace(var[s]) && s < var.length(); s++) {
2412  }
2413  if (s == var.length()) // All whitespace before the `='?
2414  return false;
2415  for (; std::isspace(var[e]); e--) {
2416  }
2417  if (e >= s) {
2418  var = var.substr(s, e - s + 1);
2419 
2420  // Strip whitespace from around val;
2421  s = 0, e = val.length() - 1;
2422  for (; std::isspace(val[s]) && s < val.length(); s++) {
2423  }
2424  if (s < val.length()) {
2425  for (; std::isspace(val[e]); e--) {
2426  }
2427  val = val.substr(s, e - s + 1);
2428  } else
2429  val = "";
2430 
2431  set(var, val);
2432  return true;
2433  }
2434  }
2435  return false;
2436  };
2437 
2438  // parse main cmd
2439  std::vector<std::string> unParsed;
2440  int beginIdx = 1;
2441  for (int i = beginIdx; i < argc; i++) {
2442  string str = argv[i];
2443  bool foundPrefix = false;
2444  size_t j = 0;
2445  for (; j < 2 && j < str.size() && str.at(j) == '-'; j++) foundPrefix = true;
2446 
2447  if (!foundPrefix) {
2448  if (!setvar(str)) unParsed.push_back(str);
2449  continue;
2450  }
2451 
2452  str = str.substr(j);
2453  if (str.find('=') != string::npos) {
2454  setvar(str);
2455  continue;
2456  }
2457 
2458  if (i + 1 >= argc) {
2459  set(str, true);
2460  continue;
2461  }
2462  string str2 = argv[i + 1];
2463  if (str2.front() == '-') {
2464  set(str, true);
2465  continue;
2466  }
2467 
2468  i++;
2469  set<std::string>(str, argv[i]);
2470  continue;
2471  }
2472 
2473  // parse default config file
2474  string argv0 = argv[0];
2475  std::vector<std::string> tries={argv0+".json",
2476  argv0+".yaml",
2477  argv0+".xml",
2478  "Default.json",
2479  "Default.yaml",
2480  "Default.xml",
2481  argv0+".cfg",
2482  "Default.cfg"};
2483  auto fileExists=[](const std::string& filename)
2484  {
2485  std::ifstream f(filename.c_str());
2486  return f.good();
2487  };
2488  if(exist("conf")){
2489  parseFile(Get<std::string>("conf"));
2490  }
2491  else
2492  for(auto& it:tries)
2493  if(fileExists(it)){
2494  parseFile(it);
2495  break;
2496  }
2497  return unParsed;
2498 }
2499 
2500 
2501 inline bool Svar::parseFile(const std::string& file_path)
2502 {
2503  Svar var=loadFile(file_path);
2504  if(var.isUndefined()) return false;
2505  if(isUndefined()) {*this=var;return true;}
2506  call("update",var);
2507  return true;
2508 }
2509 
2510 template <typename T>
2511 T Svar::arg(const std::string& name, T def, const std::string& help) {
2512  Svar argInfo=array({name,Svar::create(def),help});
2513  Svar& args=(*this)["__builtin__"]["args"];
2514  if(!args.isArray()) args=array();
2515  args.push_back(argInfo);
2516  return get(name,def);
2517 }
2518 
2519 inline std::string Svar::helpInfo()
2520 {
2521  Svar args=(*this)["__builtin__"]["args"];
2522  if(get("complete_function_request",false))
2523  {
2524  std::string str;
2525  for (int i=0;i<(int)args.length();i++) {
2526  str+=" -"+args[i][0].castAs<std::string>();
2527  }
2528  str+=" -help -conf";
2529  return str;
2530  }
2531  std::stringstream sst;
2532  int width = get("help_colums", 80, true);
2533  int namePartWidth = width / 5 - 1;
2534  int statusPartWidth = width * 2 / 5 - 1;
2535  int introPartWidth = width * 2 / 5;
2536  std::string usage = get<std::string>("__usage__", "");
2537  if (usage.empty()) {
2538  usage = "Usage:\n" + get<std::string>("__name__", "exe") +
2539  " [--help] [-conf configure_file]"
2540  " [-arg_name arg_value]...\n";
2541  }
2542  sst << usage << std::endl;
2543 
2544  std::string desc;
2545  if (exist("__version__"))
2546  desc += "Version: " + get<std::string>("__version__","1.0") + ", ";
2547  desc +=
2548  "Using Svar supported argument parsing. The following table listed "
2549  "several argument introductions.\n";
2550  sst << printTable({{width, desc}});
2551 
2552  arg<std::string>("conf", "Default.cfg",
2553  "The default configure file going to parse.");
2554  arg<bool>("help", false, "Show the help information.");
2555  if(!args.isArray()) return "";
2556 
2557  sst << printTable({{namePartWidth, "Argument"},
2558  {statusPartWidth, "Type(default->setted)"},
2559  {introPartWidth, "Introduction"}});
2560  for (int i = 0; i < width; i++) sst << "-";
2561  sst << std::endl;
2562 
2563  for (int i=0;i<(int)args.length();i++) {
2564  Svar info=args[i];
2565  std::stringstream defset;
2566  Svar def = info[1];
2567  std::string name=info[0].castAs<std::string>();
2568  Svar setted = get(name,Svar::Undefined());
2569  if(setted.isUndefined()||def==setted) defset<<def;
2570  else defset<<def<<"->"<<setted;
2571  std::string status = def.typeName() + "(" + defset.str() + ")";
2572  std::string intro = info[2].castAs<std::string>();
2573  sst << printTable({{namePartWidth, "-" +name},
2574  {statusPartWidth, status},
2575  {introPartWidth, intro}});
2576  }
2577  return sst.str();
2578 }
2579 
2580 inline std::string Svar::printTable(
2581  std::vector<std::pair<int, std::string>> line) {
2582  std::stringstream sst;
2583  while (true) {
2584  size_t emptyCount = 0;
2585  for (auto& it : line) {
2586  size_t width = it.first;
2587  std::string& str = it.second;
2588  if (str.size() <= width) {
2589  sst << std::setw(width) << std::setiosflags(std::ios::left) << str
2590  << " ";
2591  str.clear();
2592  emptyCount++;
2593  } else {
2594  sst << str.substr(0, width) << " ";
2595  str = str.substr(width);
2596  }
2597  }
2598  sst << std::endl;
2599  if (emptyCount == line.size()) break;
2600  }
2601  return sst.str();
2602 }
2603 
2604 inline Svar Svar::operator -()const
2605 {
2606  return classPtr()->call(*this,"__neg__");
2607 }
2608 
2609 #define DEF_SVAR_OPERATOR_IMPL(SNAME)\
2610 {\
2611  auto cls=classPtr();\
2612  if(!cls) throw SvarExeption(typeName()+" has not class to operator "#SNAME".");\
2613  Svar ret=cls->call(*this,#SNAME,rh);\
2614  if(ret.isUndefined()) throw SvarExeption(cls->__name__+" operator "#SNAME" with rh: "+rh.typeName()+"returned Undefined.");\
2615  return ret;\
2616 }
2617 
2618 inline Svar Svar::operator +(const Svar& rh)const
2619 DEF_SVAR_OPERATOR_IMPL(__add__)
2620 
2621 inline Svar Svar::operator -(const Svar& rh)const
2622 DEF_SVAR_OPERATOR_IMPL(__sub__)
2623 
2624 inline Svar Svar::operator *(const Svar& rh)const
2625 DEF_SVAR_OPERATOR_IMPL(__mul__)
2626 
2627 inline Svar Svar::operator /(const Svar& rh)const
2628 DEF_SVAR_OPERATOR_IMPL(__div__)
2629 
2630 inline Svar Svar::operator %(const Svar& rh)const
2631 DEF_SVAR_OPERATOR_IMPL(__mod__)
2632 
2633 inline Svar Svar::operator ^(const Svar& rh)const
2634 DEF_SVAR_OPERATOR_IMPL(__xor__)
2635 
2636 inline Svar Svar::operator |(const Svar& rh)const
2637 DEF_SVAR_OPERATOR_IMPL(__or__)
2638 
2639 inline Svar Svar::operator &(const Svar& rh)const
2640 DEF_SVAR_OPERATOR_IMPL(__and__)
2641 
2642 inline bool Svar::operator ==(const Svar& rh)const{
2643  Svar clsobj=classObject();
2644  if(!clsobj.isClass()) return _obj->ptr()==rh.value()->ptr();
2645  Svar eq_func=clsobj.as<SvarClass>()["__eq__"];
2646  if(!eq_func.isFunction()) return _obj->ptr()==rh.value()->ptr();
2647  Svar ret=eq_func(*this,rh);
2648  assert(ret.is<bool>());
2649  return ret.as<bool>();
2650 }
2651 
2652 inline bool Svar::operator <(const Svar& rh)const{
2653  Svar clsobj=classObject();
2654  if(!clsobj.isClass()) return _obj->ptr()<rh.value()->ptr();
2655  Svar lt_func=clsobj.as<SvarClass>()["__lt__"];
2656  if(!lt_func.isFunction()) return _obj->ptr()<rh.value()->ptr();
2657  Svar ret=lt_func(*this,rh);
2658  assert(ret.is<bool>());
2659  return ret.as<bool>();
2660 }
2661 
2662 inline std::ostream& operator <<(std::ostream& ost,const Svar& self)
2663 {
2664  if(self.isUndefined()) {
2665  ost<<"Undefined";
2666  return ost;
2667  }
2668  if(self.isNull()){
2669  ost<<"Null";
2670  return ost;
2671  }
2672  auto cls=self.classPtr();
2673  if(cls&&cls->__str__.isFunction()){
2674  Svar a = cls->__str__(self);
2675  ost<<a.as<std::string>();
2676  return ost;
2677  }
2678  ost<<"<"<<self.typeName()<<" at "<<self.value()->ptr()<<">";
2679  return ost;
2680 }
2681 
2682 inline const Svar& Svar::True(){
2683  static Svar v((SvarValue*)new SvarValue_<bool>(true));
2684  return v;
2685 }
2686 
2687 inline const Svar& Svar::False(){
2688  static Svar v((SvarValue*)new SvarValue_<bool>(false));
2689  return v;
2690 }
2691 
2692 inline const Svar& Svar::Undefined(){
2693  static Svar v(new SvarValue());
2694  return v;
2695 }
2696 
2697 inline const Svar& Svar::Null()
2698 {
2699  static Svar v=create<void*>(nullptr);
2700  return v;
2701 }
2702 
2703 inline Svar& Svar::instance(){
2704  static Svar v=Svar::object();
2705  return v;
2706 }
2707 
2708 inline Svar Svar::loadFile(const std::string& file_path)
2709 {
2710  std::ifstream ifs(file_path);
2711  if(!ifs.is_open()) return Svar();
2712 
2713  auto getExtension=[](const std::string& filename)->std::string{
2714  auto idx = filename.find_last_of('.');
2715  if (idx == std::string::npos)
2716  return "";
2717  else
2718  return filename.substr(idx+1);
2719  };
2720  std::string ext=getExtension(file_path);
2721  Svar ext2cls=Svar::object({{"json","Json"},
2722  {"xml","Xml"},
2723  {"yaml","Yaml"},
2724  {"yml","Yaml"},
2725  {"cfg","Cfg"}});
2726  Svar cls=Svar::instance()["__builtin__"][ext2cls[ext]];
2727  if(!cls.isClass()){
2728  std::cerr<<"Svar::loadFile don't support format "<<ext<<".\n";
2729  return Svar();
2730  }
2731 
2732  try{
2733  if(cls.exist("loadFile"))
2734  return cls.call("loadFile",file_path);
2735  std::stringstream sst;
2736  std::string line;
2737  while(std::getline(ifs,line)) sst<<line<<std::endl;
2738  return cls.call("load",sst.str());
2739  }
2740  catch(SvarExeption e){
2741  std::cerr<<e.what();
2742  }
2743  return Svar::Undefined();
2744 }
2745 
2746 inline const Svar& SvarFunction::classObject()const{return SvarClass::instance<SvarFunction>();}
2747 
2748 inline std::ostream& operator<<(std::ostream& ost,const SvarClass& rh){
2749  ost<<"class "<<rh.__name__<<"():\n";
2750  std::stringstream content;
2751  if(rh.__init__.isFunction()) content<<rh.__init__.as<SvarFunction>()<<std::endl<<std::endl;
2752  if(!rh.__doc__.empty()) content<<rh.__doc__<<std::endl;
2753  if(rh._methods.isObject()&&rh._methods.length()){
2754  content<<"Methods defined here:\n";
2755  const SvarObject& methods=rh._methods.as<SvarObject>();
2756  auto varCopy=methods._var;
2757  for(std::pair<std::string,Svar> it:varCopy){
2758  content<<it.second.as<SvarFunction>()<<std::endl<<std::endl;
2759  }
2760  }
2761  std::string line;
2762  while(std::getline(content,line)){ost<<"| "<<line<<std::endl;}
2763  return ost;
2764 }
2765 
2766 template <typename T>
2767 class caster<std::vector<T> >{
2768 public:
2769  static Svar from(const Svar& var){
2770  if(var.is<std::vector<T>>()) return var;
2771 
2772  if(!var.isArray()) return Svar::Undefined();
2773 
2774  std::vector<T> ret;
2775  ret.reserve(var.length());
2776  for(const Svar& v:var.as<SvarArray>()._var)
2777  {
2778  ret.push_back(v.castAs<T>());
2779  }
2780 
2781  return Svar::create(ret);
2782  }
2783 
2784  static Svar to(const std::vector<T>& var){
2785  return Svar::create(var);
2786  }
2787 };
2788 
2789 
2790 template <typename T>
2791 class caster<std::map<std::string,T> >{
2792 public:
2793  static Svar from(const Svar& var){
2794  if(var.is<std::map<std::string,T> >()) return var;
2795 
2796  if(!var.isObject()) return Svar::Undefined();
2797 
2798  std::map<std::string,T> ret;
2799  for(const std::pair<std::string,Svar>& v:var.as<SvarObject>()._var)
2800  {
2801  ret.insert(std::make_pair(v.first,v.second.castAs<T>()));
2802  }
2803 
2804  return Svar::create(ret);
2805  }
2806 
2807  static Svar to(const std::map<std::string,T>& var){
2808  return Svar::object(std::map<std::string,Svar>(var.begin(),var.end()));
2809  }
2810 };
2811 
2812 template <typename K,typename T>
2813 class caster<std::map<K,T> >{
2814 public:
2815  static Svar from(const Svar& var){
2816  if(var.is<std::map<K,T> >()) return var;
2817 
2818  if(!var.isDict()) return Svar::Undefined();
2819 
2820  std::map<K,T> ret;
2821  for(const std::pair<Svar,Svar>& v:var.as<SvarObject>()._var)
2822  {
2823  ret.insert(std::make_pair(v.first.castAs<K>(),v.second.castAs<T>()));
2824  }
2825 
2826  return Svar::create(ret);
2827  }
2828 
2829  static Svar to(const std::map<K,T>& var){
2830  return Svar::dict(std::map<Svar,Svar>(var.begin(),var.end()));
2831  }
2832 };
2833 
2834 
2835 template <typename T>
2836 class caster<std::shared_ptr<T> >{
2837  using H=std::shared_ptr<T>;
2838 public:
2839  static Svar from(const Svar& var){
2840  if(var.is<H>()) return var;
2841  if(var.isNull()) return Svar::create(H());
2842 
2843  auto h=dynamic_cast<SvarPtrHolder<T,H>*>(var.value().get());
2844  if(!h) return Svar::Undefined();
2845  return Svar::create(h->_var);
2846  }
2847 
2848  static Svar to(const std::shared_ptr<T>& var){
2849  if(!var) return Svar::Null();
2850  return Svar((SvarValue*)new SvarPtrHolder<T,std::shared_ptr<T>>(var));
2851  }
2852 };
2853 
2854 template <>
2855 class caster<std::nullptr_t >{
2856 public:
2857  static Svar from(const Svar& var){
2858  return var;
2859  }
2860 
2861  static Svar to(std::nullptr_t v){
2862  return Svar::Null();
2863  }
2864 };
2865 
2866 template <int sz>
2867 class caster<char[sz]>{
2868 public:
2869  static Svar to(const char* v){
2870  return Svar(std::string(v));
2871  }
2872 };
2873 
2874 inline std::istream& operator >>(std::istream& ist,Svar& self)
2875 {
2876  Svar json=svar["__builtin__"]["Json"];
2877  self=json.call("load",std::string( (std::istreambuf_iterator<char>(ist)) , std::istreambuf_iterator<char>() ));
2878  return ist;
2879 }
2880 
2881 #if !defined(__SVAR_NOBUILTIN__)
2882 
2883 /// Json save and load class
2884 class Json final {
2885 public:
2886  enum JsonParse {
2887  STANDARD, COMMENTS
2888  };
2889 
2890  static Svar load(const std::string& in){
2891  Json parser(in,COMMENTS);
2892  Svar result = parser.parse_json(0);
2893  // Check for any trailing garbage
2894  parser.consume_garbage();
2895  if (parser.failed){
2896  return Svar();
2897  }
2898  if (parser.i != in.size())
2899  return parser.fail("unexpected trailing " + esc(in[parser.i]));
2900 
2901  return result;
2902  }
2903 
2904  static std::string dump(Svar var){
2905  std::stringstream sst;
2906  sst<<var;
2907  return sst.str();
2908  }
2909 
2910 private:
2911  Json(const std::string& str_input, JsonParse parse_strategy=STANDARD)
2912  :str(str_input),i(0),failed(false),strategy(parse_strategy){}
2913 
2914  std::string str;
2915  size_t i;
2916  std::string err;
2917  bool failed;
2918  const JsonParse strategy;
2919  const int max_depth = 200;
2920 
2921  /// fail(msg, err_ret = Json())
2922  Svar fail(std::string &&msg) {
2923  if (!failed)
2924  err = std::move(msg);
2925  failed = true;
2926  throw SvarExeption(msg);
2927  return Svar();
2928  }
2929 
2930  template <typename T>
2931  T fail(std::string &&msg, const T err_ret) {
2932  if (!failed)
2933  err = std::move(msg);
2934  failed = true;
2935 
2936  return err_ret;
2937  }
2938 
2939  /// Advance until the current character is non-whitespace.
2940  void consume_whitespace() {
2941  while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t')
2942  i++;
2943  }
2944 
2945  /// Advance comments (c-style inline and multiline).
2946  bool consume_comment() {
2947  bool comment_found = false;
2948  if (str[i] == '/') {
2949  i++;
2950  if (i == str.size())
2951  return fail("unexpected end of input after start of comment", false);
2952  if (str[i] == '/') { // inline comment
2953  i++;
2954  // advance until next line, or end of input
2955  while (i < str.size() && str[i] != '\n') {
2956  i++;
2957  }
2958  comment_found = true;
2959  }
2960  else if (str[i] == '*') { // multiline comment
2961  i++;
2962  if (i > str.size()-2)
2963  return fail("unexpected end of input inside multi-line comment", false);
2964  // advance until closing tokens
2965  while (!(str[i] == '*' && str[i+1] == '/')) {
2966  i++;
2967  if (i > str.size()-2)
2968  return fail(
2969  "unexpected end of input inside multi-line comment", false);
2970  }
2971  i += 2;
2972  comment_found = true;
2973  }
2974  else
2975  return fail("malformed comment", false);
2976  }
2977  return comment_found;
2978  }
2979 
2980  /// Advance until the current character is non-whitespace and non-comment.
2981  void consume_garbage() {
2982  consume_whitespace();
2983  if(strategy == JsonParse::COMMENTS) {
2984  bool comment_found = false;
2985  do {
2986  comment_found = consume_comment();
2987  if (failed) return;
2988  consume_whitespace();
2989  }
2990  while(comment_found);
2991  }
2992  }
2993 
2994  /// Return the next non-whitespace character. If the end of the input is reached,
2995  /// flag an error and return 0.
2996  char get_next_token() {
2997  consume_garbage();
2998  if (failed) return (char)0;
2999  if (i == str.size())
3000  return fail("unexpected end of input", (char)0);
3001 
3002  return str[i++];
3003  }
3004 
3005  /// Encode pt as UTF-8 and add it to out.
3006  void encode_utf8(long pt, std::string & out) {
3007  if (pt < 0)
3008  return;
3009 
3010  if (pt < 0x80) {
3011  out += static_cast<char>(pt);
3012  } else if (pt < 0x800) {
3013  out += static_cast<char>((pt >> 6) | 0xC0);
3014  out += static_cast<char>((pt & 0x3F) | 0x80);
3015  } else if (pt < 0x10000) {
3016  out += static_cast<char>((pt >> 12) | 0xE0);
3017  out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
3018  out += static_cast<char>((pt & 0x3F) | 0x80);
3019  } else {
3020  out += static_cast<char>((pt >> 18) | 0xF0);
3021  out += static_cast<char>(((pt >> 12) & 0x3F) | 0x80);
3022  out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
3023  out += static_cast<char>((pt & 0x3F) | 0x80);
3024  }
3025  }
3026 
3027  /// Format char c suitable for printing in an error message.
3028  static inline std::string esc(char c) {
3029  char buf[12];
3030  if (static_cast<uint8_t>(c) >= 0x20 && static_cast<uint8_t>(c) <= 0x7f) {
3031  snprintf(buf, sizeof buf, "'%c' (%d)", c, c);
3032  } else {
3033  snprintf(buf, sizeof buf, "(%d)", c);
3034  }
3035  return std::string(buf);
3036  }
3037 
3038  static inline bool in_range(long x, long lower, long upper) {
3039  return (x >= lower && x <= upper);
3040  }
3041 
3042  /// Parse a string, starting at the current position.
3043  std::string parse_string() {
3044  std::string out;
3045  long last_escaped_codepoint = -1;
3046  while (true) {
3047  if (i == str.size())
3048  return fail("unexpected end of input in string", "");
3049 
3050  char ch = str[i++];
3051 
3052  if (ch == '"') {
3053  encode_utf8(last_escaped_codepoint, out);
3054  return out;
3055  }
3056 
3057  if (in_range(ch, 0, 0x1f))
3058  return fail("unescaped " + esc(ch) + " in string", "");
3059 
3060  // The usual case: non-escaped characters
3061  if (ch != '\\') {
3062  encode_utf8(last_escaped_codepoint, out);
3063  last_escaped_codepoint = -1;
3064  out += ch;
3065  continue;
3066  }
3067 
3068  // Handle escapes
3069  if (i == str.size())
3070  return fail("unexpected end of input in string", "");
3071 
3072  ch = str[i++];
3073 
3074  if (ch == 'u') {
3075  // Extract 4-byte escape sequence
3076  std::string esc = str.substr(i, 4);
3077  // Explicitly check length of the substring. The following loop
3078  // relies on std::string returning the terminating NUL when
3079  // accessing str[length]. Checking here reduces brittleness.
3080  if (esc.length() < 4) {
3081  return fail("bad \\u escape: " + esc, "");
3082  }
3083  for (size_t j = 0; j < 4; j++) {
3084  if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
3085  && !in_range(esc[j], '0', '9'))
3086  return fail("bad \\u escape: " + esc, "");
3087  }
3088 
3089  long codepoint = strtol(esc.data(), nullptr, 16);
3090 
3091  // JSON specifies that characters outside the BMP shall be encoded as a pair
3092  // of 4-hex-digit \u escapes encoding their surrogate pair components. Check
3093  // whether we're in the middle of such a beast: the previous codepoint was an
3094  // escaped lead (high) surrogate, and this is a trail (low) surrogate.
3095  if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF)
3096  && in_range(codepoint, 0xDC00, 0xDFFF)) {
3097  // Reassemble the two surrogate pairs into one astral-plane character, per
3098  // the UTF-16 algorithm.
3099  encode_utf8((((last_escaped_codepoint - 0xD800) << 10)
3100  | (codepoint - 0xDC00)) + 0x10000, out);
3101  last_escaped_codepoint = -1;
3102  } else {
3103  encode_utf8(last_escaped_codepoint, out);
3104  last_escaped_codepoint = codepoint;
3105  }
3106 
3107  i += 4;
3108  continue;
3109  }
3110 
3111  encode_utf8(last_escaped_codepoint, out);
3112  last_escaped_codepoint = -1;
3113 
3114  if (ch == 'b') {
3115  out += '\b';
3116  } else if (ch == 'f') {
3117  out += '\f';
3118  } else if (ch == 'n') {
3119  out += '\n';
3120  } else if (ch == 'r') {
3121  out += '\r';
3122  } else if (ch == 't') {
3123  out += '\t';
3124  } else if (ch == '"' || ch == '\\' || ch == '/') {
3125  out += ch;
3126  } else {
3127  return fail("invalid escape character " + esc(ch), "");
3128  }
3129  }
3130  }
3131 
3132  /// Parse a double.
3133  Svar parse_number() {
3134  size_t start_pos = i;
3135 
3136  if (str[i] == '-')
3137  i++;
3138 
3139  // Integer part
3140  if (str[i] == '0') {
3141  i++;
3142  if (in_range(str[i], '0', '9'))
3143  return fail("leading 0s not permitted in numbers");
3144  } else if (in_range(str[i], '1', '9')) {
3145  i++;
3146  while (in_range(str[i], '0', '9'))
3147  i++;
3148  } else {
3149  return fail("invalid " + esc(str[i]) + " in number");
3150  }
3151 
3152  if (str[i] != '.' && str[i] != 'e' && str[i] != 'E'
3153  && (i - start_pos) <= static_cast<size_t>(std::numeric_limits<int>::digits10)) {
3154  return std::atoi(str.c_str() + start_pos);
3155  }
3156 
3157  // Decimal part
3158  if (str[i] == '.') {
3159  i++;
3160  if (!in_range(str[i], '0', '9'))
3161  return fail("at least one digit required in fractional part");
3162 
3163  while (in_range(str[i], '0', '9'))
3164  i++;
3165  }
3166 
3167  // Exponent part
3168  if (str[i] == 'e' || str[i] == 'E') {
3169  i++;
3170 
3171  if (str[i] == '+' || str[i] == '-')
3172  i++;
3173 
3174  if (!in_range(str[i], '0', '9'))
3175  return fail("at least one digit required in exponent");
3176 
3177  while (in_range(str[i], '0', '9'))
3178  i++;
3179  }
3180 
3181  return std::strtod(str.c_str() + start_pos, nullptr);
3182  }
3183 
3184  /// Expect that 'str' starts at the character that was just read. If it does, advance
3185  /// the input and return res. If not, flag an error.
3186  Svar expect(const std::string &expected, Svar res) {
3187  assert(i != 0);
3188  i--;
3189  if (str.compare(i, expected.length(), expected) == 0) {
3190  i += expected.length();
3191  return res;
3192  } else {
3193  return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
3194  }
3195  }
3196 
3197  /// Parse a JSON object.
3198  Svar parse_json(int depth) {
3199  if (depth > max_depth) {
3200  return fail("exceeded maximum nesting depth");
3201  }
3202 
3203  char ch = get_next_token();
3204  if (failed)
3205  return Svar();
3206 
3207  if (ch == '-' || (ch >= '0' && ch <= '9')) {
3208  i--;
3209  return parse_number();
3210  }
3211 
3212  if (ch == 't')
3213  return expect("true", true);
3214 
3215  if (ch == 'f')
3216  return expect("false", false);
3217 
3218  if (ch == 'n')
3219  return expect("null", Svar());
3220 
3221  if (ch == '"')
3222  return parse_string();
3223 
3224  if (ch == '{') {
3225  std::map<std::string, Svar> data;
3226  ch = get_next_token();
3227  if (ch == '}')
3228  return data;
3229 
3230  while (1) {
3231  if (ch != '"')
3232  return fail("expected '\"' in object, got " + esc(ch));
3233 
3234  std::string key = parse_string();
3235  if (failed)
3236  return Svar();
3237 
3238  ch = get_next_token();
3239  if (ch != ':')
3240  return fail("expected ':' in object, got " + esc(ch));
3241 
3242  data[std::move(key)] = parse_json(depth + 1);
3243  if (failed)
3244  return Svar();
3245 
3246  ch = get_next_token();
3247  if (ch == '}')
3248  break;
3249  if (ch != ',')
3250  return fail("expected ',' in object, got " + esc(ch));
3251 
3252  ch = get_next_token();
3253  }
3254  return data;
3255  }
3256 
3257  if (ch == '[') {
3258  std::vector<Svar> data;
3259  ch = get_next_token();
3260  if (ch == ']')
3261  return data;
3262 
3263  while (1) {
3264  i--;
3265  data.push_back(parse_json(depth + 1));
3266  if (failed)
3267  return Svar();
3268 
3269  ch = get_next_token();
3270  if (ch == ']')
3271  break;
3272  if (ch != ',')
3273  return fail("expected ',' in list, got " + esc(ch));
3274 
3275  ch = get_next_token();
3276  (void)ch;
3277  }
3278  return data;
3279  }
3280 
3281  if (ch == '<'){
3282  while (1) {
3283  ch = get_next_token();
3284  if (ch == '>')
3285  break;
3286  }
3287  return Svar();
3288  }
3289 
3290  return fail("expected value, got " + esc(ch));
3291  }
3292 };
3293 
3294 class SvarBuiltin{
3295 public:
3296  SvarBuiltin(){
3297  SvarClass::Class<int32_t>().setName("int");
3298  SvarClass::Class<int64_t>().setName("int64_t");
3299  SvarClass::Class<uint32_t>().setName("uint32_t");
3300  SvarClass::Class<uint64_t>().setName("uint64_t");
3301  SvarClass::Class<unsigned char>().setName("uchar");
3302  SvarClass::Class<char>().setName("char");
3303  SvarClass::Class<float>().setName("float");
3304  SvarClass::Class<double>().setName("double");
3305  SvarClass::Class<std::string>().setName("str");
3306  SvarClass::Class<bool>().setName("bool");
3307  SvarClass::Class<SvarDict>().setName("dict");
3308  SvarClass::Class<SvarObject>().setName("object");
3309  SvarClass::Class<SvarArray>().setName("array");
3310  SvarClass::Class<SvarFunction>().setName("function");
3311  SvarClass::Class<SvarClass>().setName("class");
3312  SvarClass::Class<Svar>().setName("svar");
3313 
3314  SvarClass::Class<void>()
3315  .def("__str__",[](Svar){return "Undefined";})
3316  .setName("void");
3317 
3318  SvarClass::Class<int>()
3319  .def("__init__",&SvarBuiltin::int_create)
3320  .def("__double__",[](int i){return (double)i;})
3321  .def("__bool__",[](int i){return (bool)i;})
3322  .def("__str__",[](int i){return Svar::toString(i);})
3323  .def("__eq__",[](int self,int rh){return self==rh;})
3324  .def("__lt__",[](int self,int rh){return self<rh;})
3325  .def("__add__",[](int self,Svar rh)->Svar{
3326  if(rh.is<int>()) return Svar(self+rh.as<int>());
3327  if(rh.is<double>()) return Svar(self+rh.as<double>());
3328  return Svar::Undefined();
3329  })
3330  .def("__sub__",[](int self,Svar rh)->Svar{
3331  if(rh.is<int>()) return Svar(self-rh.as<int>());
3332  if(rh.is<double>()) return Svar(self-rh.as<double>());
3333  return Svar::Undefined();
3334  })
3335  .def("__mul__",[](int self,Svar rh)->Svar{
3336  if(rh.is<int>()) return Svar(self*rh.as<int>());
3337  if(rh.is<double>()) return Svar(self*rh.as<double>());
3338  return Svar::Undefined();
3339  })
3340  .def("__div__",[](int self,Svar rh){
3341  if(rh.is<int>()) return Svar(self/rh.as<int>());
3342  if(rh.is<double>()) return Svar(self/rh.as<double>());
3343  return Svar::Undefined();
3344  })
3345  .def("__mod__",[](int self,int rh){
3346  return self%rh;
3347  })
3348  .def("__neg__",[](int self){return -self;})
3349  .def("__xor__",[](int self,int rh){return self^rh;})
3350  .def("__or__",[](int self,int rh){return self|rh;})
3351  .def("__and__",[](int self,int rh){return self&rh;});
3352 
3353  SvarClass::Class<bool>()
3354  .def("__int__",[](bool b){return (int)b;})
3355  .def("__double__",[](bool b){return (double)b;})
3356  .def("__str__",[](bool b){return Svar::toString(b);})
3357  .def("__eq__",[](bool self,bool rh){return self==rh;});
3358 
3359  SvarClass::Class<double>()
3360  .def("__int__",[](double d){return (int)d;})
3361  .def("__bool__",[](double d){return (bool)d;})
3362  .def("__str__",[](double d){return Svar::toString(d);})
3363  .def("__eq__",[](double self,double rh){return self==rh;})
3364  .def("__lt__",[](double self,double rh){return self<rh;})
3365  .def("__neg__",[](double self){return -self;})
3366  .def("__add__",[](double self,double rh){return self+rh;})
3367  .def("__sub__",[](double self,double rh){return self-rh;})
3368  .def("__mul__",[](double self,double rh){return self*rh;})
3369  .def("__div__",[](double self,double rh){return self/rh;})
3370  .def("__invert__",[](double self){return 1./self;});
3371 
3372  SvarClass::Class<std::string>()
3373  .def("__len__",[](const Svar& self){return self.as<std::string>().size();})
3374  .def("__str__",[](Svar self){
3375  std::string out;
3376  dump(self.as<std::string>(),out);
3377  return out;
3378  })
3379  .def("__add__",[](const std::string& self,std::string rh){
3380  std::cerr<<"added "<<self<<rh;
3381  return self+rh;
3382  })
3383  .def("__eq__",[](const std::string& self,std::string rh){return self==rh;})
3384  .def("__lt__",[](const std::string& self,std::string rh){return self<rh;});
3385 
3386  SvarClass::Class<char const*>()
3387  .def("__str__",[](char const* str){
3388  return std::string(str);
3389  });
3390 
3391  SvarClass::Class<SvarArray>()
3392  .def("__getitem__",[](Svar self,int i){
3393  SvarArray& array=self.as<SvarArray>();
3394  return array[i];
3395  })
3396  .def("__delitem__",&SvarArray::erase)
3397  .def("__str__",[](Svar self){return Svar::toString(self.as<SvarArray>());})
3398  .def("__iter__",[](Svar self)->Svar{
3399  static Svar arrayinteratorClass;
3400  if(!arrayinteratorClass.isClass()){
3401  SvarClass* cls=new SvarClass("arrayiterator",typeid(SvarObject));
3402  arrayinteratorClass=(SvarValue*)cls;
3403  cls->def("next",[](Svar iter){
3404  Svar arrObj=iter["array"];
3405  SvarArray& array=arrObj.as<SvarArray>();
3406  int& index=iter.get<int>("index",0);
3407  if(index<(int)array.length()){
3408  return array[index++];
3409  }
3410  return Svar();
3411  });
3412  }
3413  Svar iter=Svar::object({{"array",self},
3414  {"index",0}});
3415  iter.as<SvarObject>()._class=arrayinteratorClass;
3416  return iter;
3417  })
3418  .def("__add__",[](Svar self,Svar other){
3419  return self.as<SvarArray>()+other;
3420  })
3421  .def("append",&SvarArray::append);
3422 
3423  SvarClass::Class<SvarDict>()
3424  .def("__getitem__",&SvarDict::operator [])
3425  .def("__delitem__",&SvarDict::erase);
3426 
3427 
3428  SvarClass::Class<SvarObject>()
3429  .def("__getitem__",&SvarObject::operator [])
3430  .def("__delitem__",&SvarObject::erase)
3431  .def("__str__",[](Svar self){return Svar::toString(self.as<SvarObject>());})
3432  .def("__iter__",&SvarObject::iter)
3433  .def("update",&SvarObject::update);
3434 
3435  SvarClass::Class<SvarFunction>()
3436  .def("__doc__",[](Svar self){return Svar::toString(self.as<SvarFunction>());});
3437 
3438  SvarClass::Class<SvarClass>()
3439  .def("__getitem__",[](SvarClass& self,const std::string& i)->Svar{return self[i];})
3440  .def("doc",[](Svar self){return Svar::toString(self.as<SvarClass>());});
3441 
3442  SvarClass::Class<Json>()
3443  .def_static("load",&Json::load)
3444  .def_static("dump",&Json::dump);
3445 
3446  Svar::instance()["__builtin__"]["Json"]=SvarClass::instance<Json>();
3447  Svar::instance()["__builtin__"]["version"]=SVAR_VERSION;
3448  }
3449 
3450  static Svar int_create(Svar rh){
3451  if(rh.is<int>()) return rh;
3452  if(rh.is<std::string>()) return (Svar)std::atoi(rh.as<std::string>().c_str());
3453  if(rh.is<double>()) return (Svar)(int)rh.as<double>();
3454  if(rh.is<bool>()) return (Svar)(int)rh.as<bool>();
3455 
3456  throw SvarExeption("Can't construct int from "+rh.typeName()+".");
3457  return Svar::Undefined();
3458  }
3459  static void dump(const std::string &value, std::string &out) {
3460  out += '"';
3461  for (size_t i = 0; i < value.length(); i++) {
3462  const char ch = value[i];
3463  if (ch == '\\') {
3464  out += "\\\\";
3465  } else if (ch == '"') {
3466  out += "\\\"";
3467  } else if (ch == '\b') {
3468  out += "\\b";
3469  } else if (ch == '\f') {
3470  out += "\\f";
3471  } else if (ch == '\n') {
3472  out += "\\n";
3473  } else if (ch == '\r') {
3474  out += "\\r";
3475  } else if (ch == '\t') {
3476  out += "\\t";
3477  } else if (static_cast<uint8_t>(ch) <= 0x1f) {
3478  char buf[8];
3479  snprintf(buf, sizeof buf, "\\u%04x", ch);
3480  out += buf;
3481  } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
3482  && static_cast<uint8_t>(value[i+2]) == 0xa8) {
3483  out += "\\u2028";
3484  i += 2;
3485  } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
3486  && static_cast<uint8_t>(value[i+2]) == 0xa9) {
3487  out += "\\u2029";
3488  i += 2;
3489  } else {
3490  out += ch;
3491  }
3492  }
3493  out += '"';
3494  }
3495 
3496 };
3497 
3498 static SvarBuiltin SvarBuiltinInitializerinstance;
3499 #endif
3500 #endif
3501 
3502 }
3503 #endif
SvarClass * classPtr() const
Return the class singleton pointer, return nullptr when failed.
Svar & def(const std::string &name, Func &&f)
Define a lambda function with name.
Definition: Svar.h:743
void push_back(const Svar &rh)
Append item when this is an array.
static Svar object(const std::map< std::string, Svar > &m={})
Create an Object instance.
Definition: Svar.h:632
const Svar & classObject() const
Return the class singleton, return Undefined when failed.
Definition: Svar.h:173
detail::enable_if_t< std::is_pointer< T >::value, T > castAs()
No cast is performed, directly return the c++ pointer, throw SvarException when failed.
Svar()
Default is Undefined.
Definition: Svar.h:565
Svar & def(const std::string &name, Svar funcOrClass)
Define a class or function with name.
const T & as() const
Should always check type with "is<T>()" first.
static Svar create(const T &t)
Create any other c++ type instance, T need to be a copyable type.
static Svar dict(const std::map< Svar, Svar > &m={})
Create a Dict instance.
Definition: Svar.h:638
T arg(const std::string &name, T def, const std::string &help)
Register default required arguments.
void set(const std::string &name, const T &def, bool parse_dot=false)
Set the child "name" to "create<T>(def)".
Svar & getOrCreate(const std::string &name, bool parse_dot=false)
This is dangerous since the returned Svar may be free by other threads, TAKE CARE! ...
Svar operator()(Args...args) const
Call this as function or class.
static Svar lambda(Func &&f, const Extra &...extra)
Construct a cpp_function from a lambda function (possibly with internal state)
bool is() const
Is holding a type T value?
Svar(bool b)
Wrap bool to static instances.
Definition: Svar.h:580
Svar cast() const
Success: return a Svar holding T instance, Failed: return Undefined.
std::vector< std::string > parseMain(int argc, char **argv)
Parse the "main(int argc,char** argv)" arguments.
Svar call(const std::string function, Args...args) const
Call function or class with name and arguments.
static Svar json(const std::string &str)
Create from Json String.
Definition: Svar.h:641
Definition: Camera.h:45
size_t length() const
Return the item numbers when it is an array, object or dict.
std::string typeName() const
Return the value typename.
int help()
Format print version, usages and arguments.
Definition: Svar.h:760
void erase(const Svar &id)
For Object: dot compute and call delitem Others : directly call delitem
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 Undef...
static const Svar & Null()
Null is corrosponding to the c++ nullptr.
The Svar class, A Tiny Modern C++ Header Brings Unified Interface for Different Languages.
Definition: Svar.h:561
const std::shared_ptr< SvarValue > & value() const
Return the raw holder.
Definition: Svar.h:837
Svar(int i)
Wrap a int.
Definition: Svar.h:583
std::type_index cpptype() const
Return the value typeid.
static std::string printTable(std::vector< std::pair< int, std::string >> line)
Format print strings as table.
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...
static Svar array(const std::vector< Svar > &vec={})
Create an Array instance.
Definition: Svar.h:635
Svar(double d)
Wrap a double.
Definition: Svar.h:586
static const Svar & Undefined()
Undefined is the default value when Svar is not assigned a valid value It corrosponding to the c++ vo...
std::string helpInfo()
Format print version, usages and arguments as string.
Svar(SvarValue *v)
Construct from SvarValue pointer.
Definition: Svar.h:568