jsonserial2  2.0
 All Classes Functions Typedefs Enumerations
jsonserial.hpp
1 
2 // JSonSerial2: C++ Object Serialization in JSON
3 // See: https://www.telecom-paris.fr/~elc/software/
4 //
5 // Copyright 2020 Eric Lecolinet (eric.lecolinet@gmail.com)
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 // http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 
19 #ifndef jsonserial_hpp
20 #define jsonserial_hpp
21 #include <cstdlib>
22 #include <cstring>
23 #include <locale>
24 #include <memory>
25 #include <string>
26 #include <type_traits>
27 #include <functional>
28 #include <typeinfo>
29 #include <typeindex>
30 #include <utility>
31 #include <iostream>
32 #include <fstream>
33 #include <sstream>
34 #include <list>
35 #include <unordered_map>
36 namespace jsonserial {
37 
38 class JSonSerial;
39 class JSonClasses;
40 using JString = std::string;
41 using JKString = const std::string;
42 
43 // true if T is a custom primitive type
44 template <class T> struct is_primitive : std::false_type {};
45 
46 // true if T is a std::array (not to be confused with C-style bracketed arrays).
47 template <class T> struct is_std_array : std::false_type {};
48 
49 // true if T is a std::list.
50 template <class T> struct is_std_list : std::false_type {};
51 
52 // true if T is a std::forward_list.
53 template <class T> struct is_std_forward_list : std::false_type {};
54 
55 // true if T is a std::map or std::unordered_map.
56 template <class T> struct is_std_map : std::false_type {};
57 
58 // true if T is a std::set or std::unordered_set.
59 template <class T> struct is_std_set : std::false_type {};
60 
61 // true if T is a std::vector or std::deque.
62 template <class T> struct is_std_vector : std::false_type {};
63 
64 // true if T is formatted as a JSON array (ie with brackets).
65 template <class T> struct has_array_format {
66  static constexpr bool value = is_std_array<T>::value
67  || is_std_list<T>::value
68  || is_std_forward_list<T>::value
69  || is_std_vector<T>::value
70  || is_std_set<T>::value;
71 };
72 
73 // true if T is a smart pointer (ie std::shared_ptr or std::unique_ptr).
74 template <class T> struct is_owning_ptr : std::false_type {};
75 template <class T> struct is_owning_ptr<std::shared_ptr<T>> : std::true_type {};
76 template <class T> struct is_owning_ptr<std::unique_ptr<T>> : std::true_type {};
77 
78 template <class T> struct is_weak_ptr : std::false_type {};
79 template <class T> struct is_weak_ptr<std::weak_ptr<T>> : std::true_type {};
80 
81 template <class T> struct is_smart_ptr {
82  static constexpr bool value = is_owning_ptr<T>::value || is_weak_ptr<T>::value;
83 };
84 
85 // true if T is a user class (needs to be declared by calling JSonClasses::add())
86 template <class T> struct is_user_class {
87  static constexpr bool value = std::is_class<T>::value
88  && !std::is_base_of<JString, T>::value
89  && !is_primitive<T>::value
90  && !is_smart_ptr<T>::value
91  && !has_array_format<T>::value
92  && !is_std_map<T>::value;
93 };
94 
95 // Type of a pointer to T (takes into account smart pointers),
96 template<class T, class Enable = void> struct makeptr {};
97 
98 template<class T> struct makeptr<T, typename std::enable_if<is_smart_ptr<T>::value>::type> {
99  typedef typename T::element_type* type;
100 };
101 
102 template<class T> struct makeptr<T, typename std::enable_if<!is_smart_ptr<T>::value>::type> {
103  typedef typename std::conditional<std::is_pointer<T>::value,T, T*>::type type;
104 };
105 
106 // Type of a pointer to a JSON array or C-array with brackets,
107 template<class X, class Enable = void> struct makearrayptr {};
108 
109 template<class X> struct makearrayptr<X, typename std::enable_if<std::is_array<X>::value>::type> {
110  typedef typename makeptr<typename std::remove_extent<X>::type>::type type;
111 };
112 
113 template<class X> struct makearrayptr<X, typename std::enable_if<has_array_format<X>::value>::type> {
114  typedef typename makeptr<typename X::value_type>::type type;
115 };
116 
117 struct JObjectPtr {void *raw_{}, *shared_{}; bool init_{};};
118 
120 class JSonError {
121 public:
122  enum Type {
123  OK, CantReadFile, CantWriteFile, NoData, PrematureEOF, InvalidCharacter,
124  ExpectingComma, ExpectingDelimiter, ExpectingBrace, ExpectingBracket,
125  ExpectingPairOrBrace, ExpectingValueOrBracket, ExpectingString,
126  UnknownClass, UnknownSuperclass, RedefinedClass, RedefinedSuperclass,
127  UnknownMember, RedefinedMember, AbstractClass, CantCreateObject, CantAddToArray,
128  InvalidValue, InvalidID, WrongKeyword, UnexpectedNull, ErrorCount
129  };
130 
132  using Handler = std::function<void(JSonError const&)>;
133 
134  JSonError(Type type, JKString& arg, JKString& fname, size_t line)
135  : type(type), arg(arg), fname(fname), line(line) {}
136 
137  // Prints an error on out.
138  void print(std::ostream& out) const {
139  out << "Error ";
140  if (line > 0) out << "at or before line " << line;
141  if (!fname.empty()) out << "in '" << fname << "'";
142  out << ": "<< getErrorMessage(type);
143  if (!arg.empty()) out << " " << arg;
144  out << std::endl;
145  }
146 
147  static const char* getErrorMessage(Type type) {
148  constexpr static const char* _errors[ErrorCount] {
149  "OK",
150  "can't read file",
151  "can't write file",
152  "no data",
153  "premature end of file",
154  "invalid character in string: ",
155  "expecting ,",
156  "expecting , or } or ]",
157  "expecting {",
158  "expecting [",
159  "expecting } or name:value pair",
160  "expecting ] or value",
161  "expecting a quoted name:",
162  "unknown class",
163  "unknown superclass",
164  "class already declared",
165  "already declared as a superclass",
166  "unknown member",
167  "class member already declared",
168  "can't instantiate abstract class",
169  "can't create object",
170  "C-style array too small",
171  "invalid value:",
172  "expecting ID after @",
173  "expecting @id or @class",
174  "internal error: unexpected null pointer"
175  };
176  if (type >= ErrorCount) return "Unknown error";
177  else return _errors[type];
178  }
179 
180  Type type;
181  JString arg, fname;
182  size_t line;
183 };
184 
185 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
186 
188 class JSonClass {
189 public:
190  struct Creator {
191  virtual void* create() = 0;
192  virtual ~Creator() = default;
193  };
194  virtual ~JSonClass() = default;
195  virtual void* create() const = 0;
196  virtual JKString& className() const = 0;
197  virtual bool readMember(JSonSerial&, void* obj, JKString& name, JKString& value) const = 0;
198  virtual void writeMembers(JSonSerial&, const void* obj) const = 0;
199  virtual void doPostRead(void* obj) const = 0;
200  virtual void doPostWrite(const void* obj) const = 0;
201 };
202 
203 struct JSonArray {
204  virtual ~JSonArray() = default;
205  virtual void add(JSonSerial&, JSonClass::Creator*, JKString& s) = 0;
206  virtual void end(JSonSerial&) {}
207 };
208 template <class T, class Enable = void> struct JSonArrayImpl : public JSonArray {};
209 
210 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
211 
213 template <class C> class JSonUserClass : public JSonClass {
214 public:
216  template <typename Super> JSonUserClass& extends();
217 
220  template <typename Var>
221  JSonUserClass& addMember(JKString& name, Var& var);
222 
225  template <typename Var, typename T>
226  JSonUserClass& addMember(JKString& name, Var T::* var);
227 
231  template <typename Set, typename Get>
232  JSonUserClass& addMember(JKString& name, void (C::*setter)(Set), Get(C::*getter)() const);
233 
238  JSonUserClass& addMember(JKString& name,
239  std::function<void(C&, JSonSerial&, JKString& value)> read,
240  std::function<void(const C&, JSonSerial&)> write);
241 
247  template <typename Var>
248  JSonUserClass& addMember(JKString& name, Var C::* var,
249  std::function<typename makeptr<Var>::type(C&)> creator);
250 
256  template <typename Var>
257  JSonUserClass& addMember(JKString& name, Var C::* var,
258  std::function<typename makearrayptr<Var>::type(C&)> element_creator);
259 
263  JSonUserClass& postRead(std::function<void(C&)> fun) {postread_ = fun; return *this;}
264 
268  JSonUserClass& postWrite(std::function<void(const C&)> fun) {postwrite_ = fun; return *this;}
269 
271  JKString& className() const override {return classname_;}
272 
273  class Member {
274  public:
275  Member(JKString& name) : name_(name) {}
276  virtual ~Member() = default;
277  JKString& name() const {return name_;}
278  virtual bool isCustom() const {return false;}
279  virtual void read(JSonSerial&, C& object, JKString& value) = 0;
280  virtual void write(JSonSerial&, const C& object) = 0;
281  protected:
282  JKString name_;
283  };
284 
285  JSonUserClass(JSonClasses& classes, JKString& classname, std::function<C*()> creator)
286  : classes_(classes), classname_(classname), creator_(creator) {}
287  virtual ~JSonUserClass() {for (auto& it : members_) delete it;}
288 
289  void* create() const override {return creator_ ? (creator_)() : nullptr;}
290  void addMember(JKString& varname, Member*);
291  Member* getMember(JKString& varname) const;
292  bool readMember(JSonSerial&, void* obj, JKString& name, JKString& val) const override;
293  void writeMembers(JSonSerial&, const void* obj) const override;
294  void doPostRead(void* obj) const override;
295  void doPostWrite(const void* obj) const override;
296 
297  struct Superclass {
298  const JSonClass* super_;
299  void* (*upcast_)(void*);
300  };
301 
302  struct Superclasses : public std::list<Superclass> {
303  template <class S> void add(const JSonClass* c) {this->push_back(Superclass{c, upcast<S>});}
304  template <class S> static void* upcast(void* obj) {return dynamic_cast<S*>(static_cast<C*>(obj));}
305  };
306 
307  JSonClasses& classes_;
308  JKString classname_;
309  Superclasses superclasses_;
310  std::function<C*()> creator_{};
311  std::list<Member*> members_;
312  std::unordered_map<std::string, Member*> membermap_;
313  std::function<void(C&)> postread_{};
314  std::function<void(const C&)> postwrite_{};
315 };
316 
317 
318 // JSonClass for maps.
319 template <class C> class JMapClass : public JSonClass {
320 public:
321  JKString& className() const override {static JString s("std::map"); return s;}
322  void* create() const override {return new C;}
323  bool readMember(JSonSerial&, void* obj, JKString& name, JKString& value) const override;
324  void writeMembers(JSonSerial&, const void* obj) const override;
325  void doPostRead(void*) const override {}
326  void doPostWrite(const void*) const override {}
327 };
328 
329 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
330 
332 class JSonClasses {
333 public:
335  JSonClasses(JSonError::Handler handler = {}) : errhandler_(handler) {}
336 
340  template <class T>
341  JSonUserClass<T>& addClass(JKString& classname) {
342  struct Helper {static T* create() {return new T;} ;};
343  return addClass<T>(classname, Helper::create);
344  }
345 
351  template <class T>
352  JSonUserClass<T>& addClass(JKString& classname, std::function<T*()> creator);
353 
355  void error(JSonError::Type type, JKString& arg, JKString& name) {
356  JSonError e(type, arg, name, 0);
357  if (errhandler_) errhandler_(e); else e.print(std::cout);
358  }
359 
361  const JSonClass* getClass(JKString& classname) const {
362  auto it = classnames_.find(classname);
363  return (it == classnames_.end()) ? nullptr : it->second;
364  }
365 
367  const JSonClass* getClass(const std::type_info& tinfo) const {
368  auto it = classindexes_.find(std::type_index(tinfo));
369  return (it == classindexes_.end()) ? nullptr : it->second;
370  }
371 
372  bool empty() const {return classnames_.empty();}
373 
374  ~JSonClasses() {
375  for (auto& it : classnames_) delete it.second;
376  }
377 
378 private:
379  JSonError::Handler errhandler_{};
380  std::unordered_map<std::type_index, JSonClass*> classindexes_;
381  std::unordered_map<std::string, JSonClass*> classnames_;
382 };
383 
384 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
385 
387 class JSonSerial {
388 public:
394  JSonSerial(JSonClasses const& classes, JSonError::Handler handler = {})
395  : classes_(&classes), errhandler_(handler) {}
396 
397  JSonSerial(JSonClasses const* classes, JSonError::Handler handler = {})
398  : classes_(classes), errhandler_(handler) {}
400 
406  template <class T>
407  bool read(T& object, JKString& filename) {
408  std::ifstream input(filename);
409  if (input) return read(object, input, filename, 1);
410  else {
411  reset(filename, 0, nullptr, nullptr, false);
412  JSonError e(JSonError::CantReadFile, "", filename, 0);
413  doError(e);
414  return false;
415  }
416  }
417 
422  template <class T>
423  bool read(T& object, std::istream& in,
424  JKString& name = "", size_t linenbr = 1) {
425  try {
426  reset(name, linenbr, &in, nullptr, false);
427  JString keyword, dump;
428  bool found1, found2;
429  readLine(keyword, dump, found1, found2, true);
430  if (found1) readValue(*this, object, keyword); else error(JSonError::NoData);
431  }
432  catch (JSonError& e) {
433  doError(e);
434  return false;
435  }
436  return true;
437  }
438 
446  template <class T>
447  bool write(const T& object, JKString& filename, bool cyclic_graph) {
448  std::ofstream output(filename);
449  if (output) return write(object, output, cyclic_graph, filename, 1);
450  else {
451  reset(filename, 0, nullptr, nullptr, false);
452  JSonError e(JSonError::CantWriteFile, "", filename, 0);
453  doError(e);
454  return false;
455  }
456  }
457 
462  template <class T>
463  bool write(const T& object, std::ostream& out, bool cyclic_graph,
464  JKString& name = "", size_t linenbr = 1) {
465  try {
466  reset(name, linenbr, nullptr, &out, cyclic_graph);
467  writeValue(object);
468  *out_ << "\n" << std::endl;
469  }
470  catch (JSonError& e) {
471  doError(e);
472  return false;
473  }
474  return true;
475  }
476 
485  enum JSyntax {
486  Strict=0, Comments=1, NoQuotes=2, NoCommas=4, Newlines=8,
487  Relaxed=(Comments|NoQuotes|NoCommas|Newlines)
488  };
489 
494  void setSyntax(unsigned int mode) {allow_ = mode;}
495  unsigned int getSyntax() const {return allow_;}
497 
501  void setIndent(char tabchar, unsigned int tabcount) {tabchar_ = tabchar; indent_ = tabcount;}
502  void getIndent(char& tabchar, unsigned int& tabcount) const {tabchar = tabchar_; tabcount = indent_;}
504 
506  template <class T>
507  void readMember(T& variable, JKString& str) {
508  readValue(*this, variable, str);
509  }
510 
512  template <class T>
513  void writeMember(const T& variable) {
514  writeTabs(); *out_ << '"' << token1_ << "\": ";
515  writeValue(variable);
516  }
517 
518  void error(JSonError::Type type, JKString& arg = "") {
519  throw JSonError(type, arg, fname_, lineno_);
520  }
521 
522  void doError(JSonError e) {
523  if (errhandler_) errhandler_(e); else e.print(std::cout);
524  }
525 
526  // throws if class not found.
527  const JSonClass* getCheckedClass(const std::type_info& tinfo) {
528  const JSonClass* cl = classes_->getClass(tinfo);
529  if (!cl) error(JSonError::UnknownClass, tinfo.name());
530  return cl;
531  }
532 
533  // writes a char, a bool or a string
534  void writeValue(char c) {*out_ << '\"' << c << '\"'; needcomma_ = true;}
535  void writeValue(bool b) {*out_ << (b ? "true" : "false"); needcomma_ = true;}
536  void writeValue(JKString& s) {writeString(s.c_str(), false);}
537  void writeValue(char* s) {writeString(s, true);}
538  void writeValue(const char* s) {writeString(s, true);}
539 
540  // writes anything except a string or a bool.
541  template <class T> void writeValue(const T& val) {writeValue2<T>(val); needcomma_ = true;}
542 
543  // writes a raw pointer (note: is_pointer differentiates from is_array).
544  template <class T>
545  void writeValue2(const typename std::enable_if<std::is_pointer<T>::value,T>::type & ptr) {
546  if (!ptr) *out_ << "null"; else writeValue(*ptr);
547  }
548 
549  // writes a smart pointer.
550  template <class T>
551  void writeValue2(const typename std::enable_if<is_owning_ptr<T>::value,T>::type & ptr) {
552  if (!ptr) *out_ << "null"; else writeValue(*ptr);
553  }
554 
555  // writes a weak pointer.
556  template <class T>
557  void writeValue2(const typename std::enable_if<is_weak_ptr<T>::value,T>::type & ptr) {
558  auto p = ptr.lock();
559  if (!p) *out_ << "null"; else writeValue(*p);
560  }
561 
562  // writes a number.
563  template <class T>
564  void writeValue2(const typename std::enable_if<std::is_arithmetic<T>::value,T>::type & number) {
565  *out_ << number;
566  }
567 
568  // writes an enum.
569  template <class T>
570  void writeValue2(const typename std::enable_if<std::is_enum<T>::value,T>::type & val) {
571  *out_ << int(val);
572  }
573 
574  // writes a custom primitive type.
575  template <class T>
576  void writeValue2(const typename std::enable_if<is_primitive<T>::value,T>::type & val) {
577  *out_ << val;
578  }
579 
580  // writes a map.
581  template <class T>
582  void writeValue2(const typename std::enable_if<is_std_map<T>::value,T>::type & obj) {
583  JMapClass<T> cl; writeObject(cl, false, &obj);
584  }
585 
586  // writes an array_style C++ container
587  template <class T>
588  void writeValue2(const typename std::enable_if<has_array_format<T>::value,T>::type & cont) {
589  if (cont.empty()) *out_ << "[]"; else writeArray(cont);
590  }
591 
592  // writes a C-array.
593  template <class T>
594  void writeValue2(const typename std::enable_if<std::is_array<T>::value,T>::type & carray) {
595  if (std::extent<T>::value == 0) *out_ << "[]"; else writeArray(carray);
596  }
597 
598  // writes a plain user object.
599  template <class T>
600  void writeValue2(const typename std::enable_if<is_user_class<T>::value,T>::type & obj) {
601  const JSonClass* cl = classes_->getClass(typeid(obj));
602  if (!cl) error(JSonError::UnknownClass, typeid(obj).name());
603  writeObject(*cl, (typeid(obj) != typeid(T)), &obj);
604  }
605 
606  // writes a user object pointee.
607  void writeObject(const JSonClass& cl, bool is_derived_class, const void* obj) {
608  if (shareobj_) {
609  auto it = object_to_id_.find(obj);
610  if (it != object_to_id_.end()) {*out_ << "\"@"<< it->second <<'"'; return;}
611  else object_to_id_[obj] = ++current_object_id_;
612  }
613  needcomma_ = false;
614  *out_ << "{\n";
615  addTab();
616  if (is_derived_class) { // polymorphism
617  writeTabs(); *out_ << "\"@class\": \"" << cl.className() << "\",\n";
618  }
619  if (shareobj_) {
620  writeTabs(); *out_ << "\"@id\": \"" << current_object_id_ << "\",\n";
621  }
622  cl.writeMembers(*this, obj);
623  removeTab();
624  *out_ << "\n"; writeTabs(); *out_ << "}";
625  needcomma_ = true;
626  cl.doPostWrite(obj); // end of the object
627  }
628 
629  // writes a C++ container or a C-array.
630  template <class T> void writeArray(const T & array) {
631  needcomma_ = false;
632  *out_ << "[\n";
633  addTab();
634  for (auto& it : array) {
635  if (needcomma_) *out_ << ",\n";
636  writeTabs();
637  needcomma_ = false;
638  writeValue(it);
639  }
640  removeTab();
641  *out_ << "\n"; writeTabs(); *out_ << "]";
642  }
643 
644  // writes a string.
645  void writeString(const char* s, bool is_cstring) {
646  if (!s) {*out_ << (is_cstring ? "null" : "\"\"");}
647  else {
648  out_->put('"');
649  for (; *s != 0; ++s) {
650  switch (*s) {
651  case '"': out_->put('\\'); out_->put('"'); break;
652  case '\\': out_->put('\\'); out_->put('\\'); break;
653  case '\b': out_->put('\\'); out_->put('b'); break;
654  case '\f': out_->put('\\'); out_->put('f'); break;
655  case '\n': out_->put('\\'); out_->put('n'); break;
656  case '\r': out_->put('\\'); out_->put('r'); break;
657  case '\t': out_->put('\\'); out_->put('t'); break;
658  default: out_->put(*s);
659  }
660  }
661  out_->put('"');
662  }
663  needcomma_ = true;
664  }
665 
666  void readLine(JString& token1, JString& token2, bool& found1, bool& found2, bool inObj) {
667  token1.clear();
668  token2.clear();
669  token1_.clear();
670  token2_.clear();
671  found1 = found2 = false;
672  enum {
673  Begin, InQuotedToken1, InUnquotedToken1, AfterToken1, AfterComa,
674  InQuotedToken2, InUnquotedToken2, AfterToken2, Comment, LineComment
675  }
676  part{Begin}, lastPart{Begin};
677  char c = 0;
678 
679  while (true) {
680  if (!in_->get(c)) {
681  if (!token1_.empty()) {token1 = token1_; checkValue(token1,inObj);}
682  return;
683  }
684 
685  if (c == '\n')
686  lineno_++;
687  else if (::iscntrl(c) && !::isspace(c))
688  goto INVALID_CHAR;
689  else if ((allow_&Comments) && part!=InQuotedToken1 && part!=InQuotedToken2) {
690  if (part != Comment && c == '/' && in_->peek() == '/') {
691  if (part != LineComment) {lastPart = part; part = LineComment;}
692  }
693  else if (part != LineComment && c == '/' && in_->peek() == '*') {
694  if (part != Comment) {in_->get(c); lastPart = part; part = Comment;}
695  }
696  }
697  switch (part) {
698  case Begin:
699  if (c == '"') {found1 = true; part = InQuotedToken1;}
700  else if (c == '{' || c == '[') {found1 = true; token1 = c; return;}
701  else if (!::isspace(c)) {found1 = true; token1_ += c; part = InUnquotedToken1;}
702  break;
703  case InQuotedToken1:
704  if (c == '"') {token1 = token1_; part = AfterToken1;}
705  else if (c == '\\') readEscape(token1_);
706  else if (::iscntrl(c) && (!(allow_&Newlines) || !::isspace(c))) goto INVALID_CHAR;
707  else token1_ += c;
708  break;
709  case InUnquotedToken1:
710  if (c == ',' || ((allow_&NoCommas) && c == '\n')) {token1 = token1_; checkValue(token1,inObj); return;}
711  else if (c == '}' || c == ']')
712  {in_->putback(c); token1 = token1_; checkValue(token1,inObj); return;}
713  else if (c == ':' && inObj) {token1 = token1_; checkValue(token1,inObj); part = AfterComa;}
714  else if (c == '\\') readEscape(token1_);
715  else token1_ += c;
716  break;
717  case AfterToken1:
718  if (c == ',' || ((allow_&NoCommas) && c == '\n')) return;
719  else if (c == '}' || c == ']') {in_->putback(c); return;}
720  else if (c == ':' && inObj) part = AfterComa;
721  else if (!::isspace(c)) {error(JSonError::ExpectingComma); return;}
722  break;
723  case AfterComa:
724  if (c == '"') {
725  found2 = true;
726  if (in_->peek() != '"') part = InQuotedToken2;
727  else {
728  in_->get(c);
729  if (in_->peek() != '"') {token2 = ""; part = AfterToken2;}
730  else {in_->get(c); part = InQuotedToken2; in_multiquotes_ = true;}
731  }
732  }
733  else if (c == '{' || c == '[') {found2 = true; token2 = c; return;}
734  else if (!::isspace(c)) {found2 = true; token2_ += c; part = InUnquotedToken2;}
735  break;
736  case InQuotedToken2:
737  if (c == '"') {
738  if (!in_multiquotes_) {token2 = token2_; part = AfterToken2;}
739  else if (in_->peek() != '"') token2_ += '"';
740  else {
741  in_->get(c);
742  if (in_->peek() != '"') token2_ += "\"\"";
743  else {
744  in_->get(c); token2 = token2_; part = AfterToken2; in_multiquotes_ = false;
745  }
746  }
747  }
748  else if (in_multiquotes_ && ::isspace(c)) token2_ += c;
749  else if (c == '\\') readEscape(token2_);
750  else if (::iscntrl(c) && (!(allow_&Newlines) || !::isspace(c))) goto INVALID_CHAR;
751  else token2_ += c;
752  break;
753  case InUnquotedToken2:
754  if (c == ',' || ((allow_&NoCommas) && c == '\n')) {token2 = token2_; checkValue(token2,false); return;}
755  else if (c == '}' || c == ']') {in_->putback(c); token2 = token2_; checkValue(token2,false); return;}
756  else if (c == '\\') readEscape(token2_);
757  else token2_ += c;
758  break;
759  case AfterToken2:
760  if (c == ',' || ((allow_&NoCommas) && c == '\n')) return;
761  else if (c == '}' || c == ']') {in_->putback(c); return;}
762  else if (!::isspace(c)) {error(JSonError::ExpectingDelimiter); return;}
763  break;
764  case LineComment:
765  if ((allow_&Comments) && c == '\n') part = lastPart;
766  break;
767  case Comment:
768  if ((allow_&Comments) && (c == '*' && in_->peek() == '/')) {in_->get(c); part = lastPart;}
769  break;
770  }
771  }
772  return;
773  INVALID_CHAR:
774  JString msg;
775  if (c=='\n') msg="newline "; else if (c=='\r') msg="CR "; else if (c=='\t') msg="tab ";
776  error(JSonError::InvalidCharacter, msg + "(code: "+std::to_string(int(c))+")");
777  }
778 
779  void readEscape(JString& token) {
780  int c = in_->get();
781  switch (c) {
782  case '"': token += '"'; break;
783  case '\\': token += '\\'; break;
784  case '/': token += '/'; break;
785  case 'b': token += '\b'; break;
786  case 'f': token += '\f'; break;
787  case 'n': token += '\n'; break;
788  case 'r': token += '\r'; break;
789  case 't': token += '\t'; break;
790  //case 'u': utf16_to_utf8(token); break; TODO
791  default: token += c; break;
792  }
793  }
794 
795  bool isNumber(JKString& token) {
796  if (token.empty()) return false;
797  bool dotfound{false}, expfound{false};
798  const char *p = token.c_str();
799  if (*p == '-') ++p;
800  for (; *p != 0; ++p)
801  if (!::isdigit(*p)) {
802  if (*p=='.') {if (dotfound) return false; else dotfound = true;}
803  else if (*p=='e' || *p=='E') {
804  if (expfound) return false; else expfound = true;
805  if (*(p+1)=='+' || *(p+1)=='-') ++p;
806  }
807  else return false;
808  }
809  return true;
810  }
811 
812  void checkValue(JString& token, bool objName) {
813  if (!token.empty()) { // trimRight
814  const char *s = token.c_str(), *end = s + token.length()-1;
815  while (end >= s && ::isspace(*end)) --end;
816  if (end >= s) token.assign(s, end-s+1);
817  }
818  if (objName) {
819  if ((allow_&NoQuotes) || token[0]=='}' || token[0]==']') return;
820  else error(JSonError::ExpectingString, token);
821  }
822  else if ((allow_&NoQuotes) || token.empty()
823  || token[0]=='}' || token[0]==']' || token=="true" || token=="false" || token=="null"
824  || isNumber(token))
825  return;
826  else error(JSonError::InvalidValue, token+" (should be quoted)");
827  }
828 
829  void reset(JKString& fname, size_t lineno,
830  std::istream *in, std::ostream *out, bool shareobj) {
831  in_ = in;
832  out_ = out;
833  if (in_) in_->imbue(locale_);
834  if (out_) out_->imbue(locale_);
835  fname_ = fname;
836  lineno_ = lineno;
837  needcomma_ = false;
838  shareobj_ = shareobj;
839  level_ = 0;
840  token1_.reserve(50);
841  token2_.reserve(50);
842  in_multiquotes_ = false;
843  tabs_.assign(40, tabchar_);
844  object_to_id_.clear();
845  id_to_object_.clear();
846  current_object_id_ = 0;
847  }
848 
849  void addTab() {if (++level_*indent_ >= tabs_.size()) tabs_.resize(tabs_.size() + 20, tabchar_);}
850  void removeTab() {if (--level_ < 0) level_ = 0;}
851  void writeTabs() {out_->write(tabs_.data(), level_*indent_);}
852 
853  JSonClasses const* classes_{};
854  //std::locale locale_{std::locale::classic()};
855  std::locale locale_{"en_US.UTF-8"};
856  std::istream *in_{};
857  std::ostream *out_{};
858  unsigned char allow_{Comments};
859  bool needcomma_{}, in_multiquotes_{}, shareobj_{};
860  size_t lineno_{0};
861  unsigned int indent_{2};
862  int level_{0};
863  char tabchar_{' '};
864  JString fname_, tabs_, token1_, token2_;
865  unsigned long current_object_id_{0};
866  std::unordered_map<const void*, unsigned long> object_to_id_;
867  std::unordered_map<unsigned long, JObjectPtr> id_to_object_;
868  JSonError::Handler errhandler_{};
869 };
870 
871 
872 inline void* readObject(JSonSerial& js,
873  const JSonClass* objclass, const JSonClass* pointerclass,
874  JObjectPtr*& jsp, JSonClass::Creator* cr, void* obj, JKString& s);
875 
876 // reads a non-object pointee pointed by a unique_ptr
877 template <class E>
878 inline void readPointee2(JSonSerial& js,
879  typename std::enable_if<!is_user_class<E>::value,std::unique_ptr<E>>::type & ptr,
880  JObjectPtr *&, JSonClass::Creator*, JKString& s) {
881  ptr.reset(new E{});
882  readValue(js, *ptr, s);
883 }
884 
885 // reads a user object pointee pointed by a unique_ptr
886 template <class E>
887 inline void readPointee2(JSonSerial& js,
888  typename std::enable_if<is_user_class<E>::value,std::unique_ptr<E>>::type & ptr,
889  JObjectPtr *& objptr, JSonClass::Creator* cr, JKString& s) {
890  ptr.reset(static_cast<E*>(readObject(js, nullptr, js.getCheckedClass(typeid(E)),
891  objptr, cr, nullptr, s)));
892 }
893 
894 // read non-object pointee pointed by shared_ptr
895 template <class E>
896 inline void readPointee2(JSonSerial& js,
897  typename std::enable_if<!is_user_class<E>::value,std::shared_ptr<E>>::type & ptr,
898  JObjectPtr *&, JSonClass::Creator*, JKString& s) {
899  ptr.reset(new E{});
900  readValue(js,*ptr, s);
901 }
902 
903 // read a user object pointee pointed by shared_ptr
904 template <class E>
905 inline void readPointee2(JSonSerial& js,
906  typename std::enable_if<is_user_class<E>::value,std::shared_ptr<E>>::type & ptr,
907  JObjectPtr *& objptr, JSonClass::Creator* cr, JKString& s) {
908  E* p = static_cast<E*>(readObject(js, nullptr, js.getCheckedClass(typeid(E)),
909  objptr, cr, nullptr, s));
910  if (!objptr) ptr.reset(p);
911  else if (objptr->shared_) { // smart_ptr already init
912  objptr->init_ = false;
913  ptr = *static_cast<std::shared_ptr<E>*>(objptr->shared_);
914  }
915  else {
916  ptr.reset(p);
917  objptr->shared_ = &ptr; // init smart_ptr
918  objptr->init_ = true;
919  }
920 }
921 
922 // reads a non-object pointee pointed by a weak_ptr
923 template <class E>
924 inline void readPointee2(JSonSerial& js,
925  typename std::enable_if<!is_user_class<E>::value,std::weak_ptr<E>>::type & ptr,
926  JObjectPtr *&, JSonClass::Creator*, JKString& s) {
927  using SHT = decltype(ptr.lock());
928  SHT* shp = new SHT(); // !!!!!
929  shp->reset(new E{});
930  readValue(js, **shp, s);
931  ptr = *shp;
932 }
933 
934 // reads a user object pointee pointed by a weak_ptr
935 template <class T>
936 inline void readPointee2(JSonSerial& js,
937  typename std::enable_if<is_user_class<T>::value,std::weak_ptr<T>>::type & ptr,
938  JObjectPtr *& objptr, JSonClass::Creator* cr, JKString& s) {
939  using SHT = decltype(ptr.lock());
940  SHT* shp = new SHT(); // !!!!!
941  T* p = static_cast<T*>(readObject(js, nullptr, js.getCheckedClass(typeid(T)),
942  objptr, cr, nullptr, s));
943  if (!objptr) shp->reset(p);
944  else if (objptr->shared_) { // smart_ptr already init
945  objptr->init_ = false;
946  *shp = *static_cast<std::shared_ptr<T>*>(objptr->shared_);
947  }
948  else {
949  shp->reset(p);
950  objptr->shared_ = &ptr; // init smart_ptr
951  objptr->init_ = true;
952  }
953  ptr = *shp;
954 }
955 
956 // reads a non-object pointed by a raw ptr
957 template <class T>
958 inline void readPointee(JSonSerial& js,
959  typename std::enable_if<!is_user_class<typename std::remove_reference<T>::type>::value,T>::type *& ptr,
960  JObjectPtr *&, JSonClass::Creator*, JKString& s) {
961  ptr = new T{};
962  readValue(js, *ptr, s);
963 }
964 
965 // reads a user object pointed by a raw ptr
966 template <class T>
967 inline void readPointee(JSonSerial& js,
968  typename std::enable_if<is_user_class<typename std::remove_reference<T>::type>::value,T>::type *& ptr,
969  JObjectPtr *& objptr, JSonClass::Creator * cr, JKString& s) {
970  ptr = static_cast<T*>(readObject(js, nullptr, js.getCheckedClass(typeid(T)),
971  objptr, cr, nullptr, s));
972 }
973 
974 // reads a pointee pointed by a smart pointer
975 template <class T>
976 inline void readPointee(JSonSerial& js,
977  typename std::enable_if<is_smart_ptr<T>::value,T>::type & ptr,
978  JObjectPtr *& objptr, JSonClass::Creator* cr, JKString& s) {
979  readPointee2<typename T::element_type>(js, ptr, objptr, cr, s);
980 }
981 
982 // reads a smart pointer.
983 template <class T>
984 inline void readValue2(JSonSerial& js,
985  typename std::enable_if<is_smart_ptr<T>::value,T>::type & ptr,
986  JKString& s) {
987  JObjectPtr* objptr{}; ptr.reset();
988  if (s != "null") readPointee<T>(js, ptr, objptr, nullptr, s);
989 }
990 
991 // reads a number of another type than int, long, etc.
992 template <class T>
993 inline void readValue2(JSonSerial& js,
994  typename std::enable_if<std::is_arithmetic<T>::value,T>::type & val,
995  JKString& s) {
996  std::istringstream ss(s);
997  ss.imbue(js.locale_);
998  ss >> val;
999 }
1000 
1001 // reads an enum.
1002 template <class T>
1003 inline void readValue2(JSonSerial& js,
1004  typename std::enable_if<std::is_enum<T>::value,T>::type & val,
1005  JKString& s) {
1006  val = T(std::stoi(s));
1007 }
1008 
1009 // reads a custom primitive type.
1010 template <class T>
1011 inline void readValue2(JSonSerial& js,
1012  typename std::enable_if<is_primitive<T>::value,T>::type & val,
1013  JKString& s) {
1014  val = s;
1015 }
1016 
1017 // reads a user object.
1018 template <class T>
1019 inline void readValue2(JSonSerial& js,
1020  typename std::enable_if<is_user_class<T>::value,T>::type & obj,
1021  JKString& s) {
1022  const JSonClass* wanted_class = js.getCheckedClass(typeid(obj));
1023  JObjectPtr* objptr{};
1024  readObject(js, wanted_class, wanted_class, objptr, nullptr, &obj, s);
1025 }
1026 
1027 // reads a std::map.
1028 template <class T>
1029 inline void readValue2(JSonSerial& js,
1030  typename std::enable_if<is_std_map<T>::value,T>::type & obj,
1031  JKString& s) {
1032  JMapClass<T> wanted_class; JObjectPtr* objptr{};
1033  readObject(js, &wanted_class, &wanted_class, objptr, nullptr, &obj, s);
1034 }
1035 
1036 // reads a C-array with brackets.
1037 template <class T>
1038 inline void readValue2(JSonSerial& js,
1039  typename std::enable_if<std::is_array<T>::value,T>::type & array,
1040  JKString& s) {
1041  JSonArrayImpl<T> a(array); readArray(js, a, nullptr, s);
1042 }
1043 
1044 // reads a JSON array container (eg std::list, std::vector).
1045 template <class T>
1046 inline void readValue2(JSonSerial& js,
1047  typename std::enable_if<has_array_format<T>::value,T>::type & array,
1048  JKString& s) {
1049  JSonArrayImpl<T> a(array); readArray(js, a, nullptr, s);
1050 }
1051 
1052 inline char* tocstr_(JKString& s) { // strdup not standard
1053  if (s == "null" || !s.c_str()) return nullptr;
1054  else return (char*)::memcpy((char*)::malloc(s.size()+1), s.c_str(), s.size()+1);
1055 }
1056 
1057 // reads a std::string, a char*, a const char*, a bool, a char or a number.
1058 inline void readValue(JSonSerial&, JString& var, JKString& s) {var = s;}
1059 inline void readValue(JSonSerial&, char*& var, JKString& s) {var = tocstr_(s);}
1060 inline void readValue(JSonSerial&, const char*& var, JKString& s) {var = tocstr_(s);}
1061 inline void readValue(JSonSerial& js, bool& var, JKString& s) {
1062  if (s == "true") var = true;
1063  else if (s == "false") var = false;
1064  else js.error(JSonError::InvalidValue, s+" should be a boolean");
1065 }
1066 inline void readValue(JSonSerial&, char& var, JKString& s) {var = s.empty() ? 0 : s[0];}
1067 inline void readValue(JSonSerial&, int& var, JKString& s) {var = std::stoi(s);}
1068 inline void readValue(JSonSerial&, long& var, JKString& s) {var = std::stol(s);}
1069 inline void readValue(JSonSerial&, long long& var, JKString& s) {var = std::stoll(s);}
1070 inline void readValue(JSonSerial&, unsigned long& var, JKString& s) {var = std::stoul(s);}
1071 inline void readValue(JSonSerial&, unsigned long long& var, JKString& s) {var = std::stoull(s);}
1072 inline void readValue(JSonSerial&, float& var, JKString& s) {var = std::stof(s);}
1073 inline void readValue(JSonSerial&, double& var, JKString& s) {var = std::stod(s);}
1074 inline void readValue(JSonSerial&, long double& var, JKString& s) {var = std::stold(s);}
1075 
1076 // reads a raw pointer.
1077 template <class T>
1078 inline void readValue(JSonSerial& js, T *& ptr, JKString& s) {
1079  ptr = {};
1080  JObjectPtr* objptr{};
1081  if (s != "null") readPointee<T>(js, ptr, objptr, nullptr, s);
1082 }
1083 
1084 // reads a value of another type.
1085 template <class T>
1086 inline void readValue(JSonSerial& js, T& value, JKString& s) {
1087  readValue2<T>(js, value, s);
1088 }
1089 
1090 /* reads a user object.
1091  * - objclass : class of the object, may be null (see below)
1092  * - pointerclass : class of the pointer, used as a default if no @type field
1093  * - obj : points to the object, if null the object is auto-created
1094  * taking into account 1) @type if defined, 2) pointerclass
1095  * - returns a pointer to the object (whether created or not)
1096  */
1097 inline void* readObject(JSonSerial& js,
1098  JSonClass const* objclass, JSonClass const* pointerclass,
1099  JObjectPtr*& jsp, JSonClass::Creator* cr, void* obj,
1100  JKString& s) {
1101  if (s.empty()) js.error(JSonError::ExpectingBrace);
1102  else if (s[0] == '@') { // shared object
1103  auto it = js.id_to_object_.find(std::strtoul(s.c_str()+1, nullptr, 0));
1104  if (it == js.id_to_object_.end()) js.error(JSonError::InvalidID);
1105  jsp = &it->second;
1106  return obj = it->second.raw_;
1107  }
1108  else if (s != "{") js.error(JSonError::ExpectingBrace);
1109 
1110  while (js.in_->good()) {
1111  JString name, value;
1112  bool found1, found2;
1113  js.readLine(name, value, found1, found2, true);
1114  if (!found1) js.error(JSonError::ExpectingPairOrBrace);
1115  else if (!found2 && name != "}") js.error(JSonError::ExpectingPairOrBrace);
1116 
1117  if (name[0]=='@' && name != "@class" && name != "@id")
1118  js.error(JSonError::WrongKeyword, value);
1119 
1120  if (!objclass) { // search class
1121  if (name != "@class") objclass = pointerclass;
1122  else { // polymorphism
1123  objclass = js.classes_->getClass(value);
1124  if (!objclass) js.error(JSonError::UnknownClass, value);
1125  }
1126  if (!obj) { // create object if it does not exist
1127  if (cr) obj = cr->create();
1128  else obj = objclass->create();
1129  }
1130  if (!obj) js.error(JSonError::AbstractClass, objclass->className());
1131  if (name == "@class") continue;
1132  }
1133 
1134  if (name == "}") {objclass->doPostRead(obj); return obj;} // end of object
1135  else if (name == "@id") { // id of object
1136  jsp = &js.id_to_object_[std::stoul(value)];
1137  jsp->raw_ = obj;
1138  continue;
1139  }
1140  else try {
1141  if (!objclass->readMember(js, obj, name, value))
1142  js.error(JSonError::UnknownMember,
1143  "'" +name + "' in class '" + objclass->className()+"'");
1144  }
1145  catch (std::invalid_argument) {
1146  js.error(JSonError::InvalidValue, value+" for member '"+name+"'");
1147  }
1148  }
1149  js.error(JSonError::PrematureEOF);
1150  return nullptr;
1151 }
1152 
1153 // reads a C++ container or a C-array.
1154 inline void readArray(JSonSerial& js, JSonArray& a, JSonClass::Creator* cr, JKString& s) {
1155  if (s != "[") js.error(JSonError::ExpectingBracket);
1156  while (js.in_->good()) {
1157  JString tok, dump;
1158  bool found1, found2;
1159  js.readLine(tok, dump, found1, found2, false);
1160  if (!found1) js.error(JSonError::ExpectingValueOrBracket);
1161  else if (tok == "]") {a.end(js); return;} // end of array
1162  //else if (tok == "null"); // null element ignored
1163  else a.add(js, cr, tok);
1164  }
1165 }
1166 
1167 // reads a smart pointer in an array/container.
1168 template <class T>
1169 inline void readArrayValue2(JSonSerial& js,
1170  typename std::enable_if<is_smart_ptr<T>::value,T>::type & e,
1171  JObjectPtr*& objptr, JSonClass::Creator* cr, JKString& s) {
1172  e.reset();
1173  if (s != "null") readPointee<T>(js, e, objptr, cr, s);
1174 }
1175 
1176 // reads anything else in an array/container.
1177 template <class T>
1178 inline void readArrayValue2(JSonSerial& js,
1179  typename std::enable_if<!is_smart_ptr<T>::value,T>::type & e,
1180  JObjectPtr*&, JSonClass::Creator*, JKString& s) {
1181  readValue(js, e, s);
1182 }
1183 
1184 // reads a char* in an array/container.
1185 inline void readArrayValue(JSonSerial& js, char* & e,
1186  JObjectPtr*&, JSonClass::Creator*, JKString& s) {
1187  e = nullptr;
1188  readValue(js, e, s);
1189 }
1190 
1191 // reads a const char* in an array/container.
1192 inline void readArrayValue(JSonSerial& js, const char* & e,
1193  JObjectPtr*&, JSonClass::Creator*, JKString& s) {
1194  e = nullptr;
1195  readValue(js, e, s);
1196 }
1197 
1198 // reads a raw pointer in an array/container.
1199 template <class T>
1200 inline void readArrayValue(JSonSerial& js, T *& e, JObjectPtr*& objptr,
1201  JSonClass::Creator* cr, JKString& s) {
1202  e = nullptr;
1203  if (s != "null") readPointee<T>(js, e, objptr, cr, s);
1204 }
1205 
1206 // reads anything in an array/container except a char* or a raw pointer.
1207 template <class T>
1208 inline void readArrayValue(JSonSerial& js, T & e, JObjectPtr*& objptr,
1209  JSonClass::Creator* cr, JKString& s) {
1210  readArrayValue2<T>(js, e, objptr, cr, s);
1211 }
1212 
1213 
1214 template <typename C, typename R>
1215 struct ObjectCreatorImpl : public JSonClass::Creator {
1216  ObjectCreatorImpl(C& obj, std::function<R(C&)> creator)
1217  : obj_(obj), creator_(creator) {}
1218  C& obj_;
1219  std::function<R(C&)> creator_;
1220  void* create() override {return (creator_)(obj_);}
1221 };
1222 
1223 template <typename T, typename Var>
1224 struct StaticMember : public JSonUserClass<T>::Member {
1225  StaticMember(JKString& name, Var& var) : JSonUserClass<T>::Member(name), variable_(var) {}
1226  void read(JSonSerial& js, T&, JKString& val) override {readValue(js, variable_, val);}
1227  void write(JSonSerial& js, const T&) override {js.writeValue(variable_);}
1228 protected:
1229  Var& variable_;
1230 };
1231 
1232 template <typename T, typename Var>
1233 struct InstanceMember : public JSonUserClass<T>::Member {
1234  InstanceMember(JKString& name, Var T::* var) : JSonUserClass<T>::Member(name), variable_(var) {}
1235  void read(JSonSerial& js, T& obj, JKString& val) override {readValue(js, obj.*variable_, val);}
1236  void write(JSonSerial& js, const T& obj) override {js.writeValue(obj.*variable_);}
1237 protected:
1238  Var T::* variable_;
1239 };
1240 
1241 template <typename T, typename Var>
1242 struct InstanceMemberWithCond : public JSonUserClass<T>::Member {
1243  InstanceMemberWithCond(JKString& name, Var T::* var, std::function<bool(const T&)> write_if)
1244  : JSonUserClass<T>::Member(name), variable_(var), write_if_(write_if) {}
1245  void read(JSonSerial& js, T& obj, JKString& val) override {readValue(js, obj.*variable_, val);}
1246  void write(JSonSerial& js, const T& obj) override {if ((write_if_)(obj)) js.writeValue(obj.*variable_);}
1247 protected:
1248  Var T::* variable_;
1249  std::function<bool(const T&)> write_if_;
1250 };
1251 
1252 template <typename T, typename Var, typename R>
1253 struct InstanceMemberWithCreator : public JSonUserClass<T>::Member {
1254  InstanceMemberWithCreator(JKString& name, Var T::* var, std::function<R(T&)> creator)
1255  : JSonUserClass<T>::Member(name), variable_(var), creator_(creator) {}
1256  void read(JSonSerial& js, T& obj, JKString& s) override {
1257  ObjectCreatorImpl<T,R> c(obj, creator_);
1258  obj.*variable_ = nullptr;
1259  JObjectPtr* jsp{nullptr};
1260  using TObj = typename std::remove_pointer<Var>::type;
1261  if (s != "null") readPointee<TObj>(js, (obj.*variable_), jsp, &c, s);
1262  }
1263  void write(JSonSerial& js, const T& obj) override {js.writeValue(obj.*variable_);}
1264 protected:
1265  Var T::* variable_;
1266  std::function<R(T&)> creator_;
1267 };
1268 
1269 template <typename T, typename Var, typename R>
1270 struct ArrayMemberWithCreator : public JSonUserClass<T>::Member {
1271  ArrayMemberWithCreator(JKString& name, Var T::* var, std::function<R(T&)> creator)
1272  : JSonUserClass<T>::Member(name), variable_(var), creator_(creator) {}
1273  void read(JSonSerial& js, T& obj, JKString& s) override {
1274  ObjectCreatorImpl<T,R> c(obj, creator_);
1275  JSonArrayImpl<Var> a(obj.*variable_);
1276  readArray(js, a, &c, s);
1277  }
1278  void write(JSonSerial& js, const T& obj) override {js.writeValue(obj.*variable_);}
1279 protected:
1280  Var T::* variable_;
1281  std::function<R(T&)> creator_;
1282 };
1283 
1284 template <typename T, typename SetVal, typename GetVal>
1285 struct InstanceMemberWithAccessor : public JSonUserClass<T>::Member {
1286  InstanceMemberWithAccessor(JKString& name, void(T::*setter)(SetVal), GetVal(T::*getter)()const)
1287  : JSonUserClass<T>::Member(name), setter_(setter), getter_(getter) {}
1288  void read(JSonSerial& js, T& obj, JKString& val) override {
1289  typename std::remove_const<typename std::remove_reference<SetVal>::type>::type var;
1290  readValue(js, var, val);
1291  (obj.*setter_)(std::move(var)); // allow move when possible
1292  }
1293  void write(JSonSerial& js, const T& obj) override {js.writeValue((obj.*getter_)());}
1294 protected:
1295  void (T::*setter_)(SetVal);
1296  GetVal (T::*getter_)() const;
1297 };
1298 
1299 template <typename T>
1300 struct InstanceCustomMember : public JSonUserClass<T>::Member {
1301  InstanceCustomMember(JKString& name,
1302  std::function<void(T&, JSonSerial&, JKString&)> readfun,
1303  std::function<void(const T&, JSonSerial&)> writefun)
1304  : JSonUserClass<T>::Member(name), readfun_(readfun), writefun_(writefun) {}
1305  bool isCustom() const override {return true;}
1306  void read(JSonSerial& js, T& obj, JKString& val) override {(readfun_)(obj,js,val);}
1307  void write(JSonSerial& js, const T& obj) override {(writefun_)(obj,js);}
1308 protected:
1309  std::function<void(T&, JSonSerial&, JKString&)> readfun_;
1310  std::function<void(const T&, JSonSerial&)> writefun_;
1311 };
1312 
1313 template <class T>
1314 template <typename Var>
1315 JSonUserClass<T>& JSonUserClass<T>::addMember(JKString& name, Var& var) {
1316  addMember(name, new StaticMember<T,Var>(name, var));
1317  return *this;
1318 }
1319 
1320 template <class T>
1321 template <typename Var, typename C>
1322 JSonUserClass<T>& JSonUserClass<T>::addMember(JKString& name, Var C::* var) {
1323  addMember(name, new InstanceMember<T,Var>(name, var));
1324  return *this;
1325 }
1326 
1327 template <class T>
1328 template <typename SetVal, typename GetVal>
1329 JSonUserClass<T>& JSonUserClass<T>::addMember(JKString& name,
1330  void (T::*setter)(SetVal), GetVal (T::*getter)() const) {
1331  addMember(name, new InstanceMemberWithAccessor<T,SetVal,GetVal>(name, setter, getter));
1332  return *this;
1333 }
1334 
1335 template <class T>
1336 template <typename Var>
1337 JSonUserClass<T>& JSonUserClass<T>::addMember(JKString& name, Var T::* var,
1338  std::function<typename makeptr<Var>::type(T&)> cr) {
1339  addMember(name, new InstanceMemberWithCreator<T,Var, typename makeptr<Var>::type>(name, var, cr));
1340  return *this;
1341 }
1342 
1343 template <class T>
1344 template <typename Var>
1345 JSonUserClass<T>& JSonUserClass<T>::addMember(JKString& name, Var T::* var,
1346  std::function<typename makearrayptr<Var>::type(T&)> cr) {
1347  addMember(name, new ArrayMemberWithCreator<T,Var, typename makearrayptr<Var>::type>(name, var, cr));
1348  return *this;
1349 }
1350 
1351 template <class T>
1352 JSonUserClass<T>& JSonUserClass<T>::addMember(JKString& name,
1353  std::function<void(T&, JSonSerial&, JKString&)> read,
1354  std::function<void(const T&, JSonSerial&)> write) {
1355  addMember(name, new InstanceCustomMember<T>(name, read, write));
1356  return *this;
1357 }
1358 
1359 template <class T>
1360 template <typename Super>
1361 JSonUserClass<T>& JSonUserClass<T>::extends() {
1362  static_assert(std::is_base_of<Super, T>::value, "extends(): Not a superclass");
1363  const JSonClass* c = classes_.getClass(typeid(Super));
1364  if (!c) classes_.error(JSonError::UnknownSuperclass,
1365  JString(": superclass ")+typeid(Super).name()+" of class "+classname_, "extends()");
1366  else {
1367  bool added{false};
1368  for (auto& it : superclasses_) {if (it.super_ == c) added = true;}
1369  if (!added) superclasses_.template add<Super>(c);
1370  else classes_.error(JSonError::RedefinedSuperclass,
1371  ": superclass "+c->className()+" of class "+classname_, "extends()");
1372  }
1373  return *this;
1374 }
1375 
1376 template <class T>
1377 void JSonUserClass<T>::addMember(JKString& name, Member* m) {
1378  if (getMember(name))
1379  classes_.error(JSonError::RedefinedMember,": member "+name+" of class "+classname_, "member()");
1380  else
1381  members_.push_back(m); membermap_[name] = m;
1382 }
1383 
1384 template <class T>
1385 typename JSonUserClass<T>::Member* JSonUserClass<T>::getMember(JKString& name) const {
1386  auto it = membermap_.find(name);
1387  return (it == membermap_.end()) ? nullptr : it->second;
1388 }
1389 
1390 template <class T>
1391 bool JSonUserClass<T>::readMember(JSonSerial& js, void* obj, JKString& name, JKString& val) const {
1392  if (!obj) js.error(JSonError::UnexpectedNull);
1393  if (auto mb = getMember(name)) { // search in subclass first
1394  mb->read(js, *static_cast<T*>(obj), val);
1395  return true;
1396  }
1397  for (auto& it : superclasses_) { // if not found, search in superclasses
1398  if (it.super_->readMember(js, (it.upcast_)(obj), name, val)) return true;
1399  }
1400  return false;
1401 }
1402 
1403 template <class T>
1404 void JSonUserClass<T>::writeMembers(JSonSerial& js, const void* obj) const {
1405  if (!obj) js.error(JSonError::UnexpectedNull);
1406  for (auto& it : superclasses_) { // print members in superclasses first
1407  it.super_->writeMembers(js, (it.upcast_)((void*)obj));
1408  }
1409  for (auto& it : members_) { // then print members (can't be shadowed!)
1410  if (js.needcomma_) *(js.out_) << ",\n"; js.needcomma_ = false;
1411  if (it->isCustom()) js.token1_ = it->name();
1412  else {js.writeTabs(); *(js.out_) << '"' << it->name() << "\": ";}
1413  it->write(js, *static_cast<const T*>(obj));
1414  }
1415 }
1416 
1417 template <class T>
1418 void JSonUserClass<T>::doPostRead(void* obj) const {
1419  if (obj && postread_) postread_(*static_cast<T*>(obj));
1420 }
1421 
1422 template <class T>
1423 void JSonUserClass<T>::doPostWrite(const void* obj) const {
1424  if (obj && postwrite_) postwrite_(*static_cast<const T*>(obj));
1425 }
1426 
1427 template <class T>
1428 bool JMapClass<T>::readMember(JSonSerial& js, void* map, JKString& key, JKString& val) const {
1429  using E = typename T::mapped_type;
1430  readValue(js, (*static_cast<T*>(map))[key] = E{}, val);
1431  return true;
1432 }
1433 
1434 template <class T>
1435 void JMapClass<T>::writeMembers(JSonSerial& js, const void* map) const {
1436  for (auto& it : *static_cast<const T*>(map)) {
1437  if (js.needcomma_) *(js.out_) << ",\n";
1438  js.needcomma_ = false;
1439  js.writeTabs(); *(js.out_) << '"' << it.first << "\": ";
1440  js.writeValue(it.second);
1441  }
1442 }
1443 
1444 template <class T>
1445 JSonUserClass<T> & JSonClasses::addClass(JKString& classname, std::function<T*()> creator) {
1446  if (getClass(classname)) error(JSonError::RedefinedClass, classname, "add()");
1447  JSonUserClass<T>* cl = new JSonUserClass<T>(*this, classname, creator);
1448  classindexes_[std::type_index(typeid(T))] = classnames_[classname] = cl;
1449  return *cl;
1450 }
1451 
1452 // add element to a C-array with brackets.
1453 template<class T>
1454 struct JSonArrayImpl<T, typename std::enable_if<std::is_array<T>::value>::type> : public JSonArray {
1455  JSonArrayImpl(T& array) : array_(array), index_(0) {}
1456  void add(JSonSerial& js, JSonClass::Creator* cr, JKString& s) override {
1457  JObjectPtr* jsp{};
1458  if (index_ >= std::extent<T>::value) js.error(JSonError::CantAddToArray);
1459  else readArrayValue(js, array_[index_++], jsp, cr, s);
1460  }
1461  T& array_;
1462  size_t index_;
1463 };
1464 
1465 }
1466 #endif