19 #ifndef jsonserial_hpp
20 #define jsonserial_hpp
26 #include <type_traits>
35 #include <unordered_map>
36 namespace jsonserial {
40 using JString = std::string;
41 using JKString =
const std::string;
44 template <
class T>
struct is_primitive : std::false_type {};
47 template <
class T>
struct is_std_array : std::false_type {};
50 template <
class T>
struct is_std_list : std::false_type {};
53 template <
class T>
struct is_std_forward_list : std::false_type {};
56 template <
class T>
struct is_std_map : std::false_type {};
59 template <
class T>
struct is_std_set : std::false_type {};
62 template <
class T>
struct is_std_vector : std::false_type {};
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;
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 {};
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 {};
81 template <
class T>
struct is_smart_ptr {
82 static constexpr
bool value = is_owning_ptr<T>::value || is_weak_ptr<T>::value;
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;
96 template<
class T,
class Enable =
void>
struct makeptr {};
98 template<
class T>
struct makeptr<T, typename std::enable_if<is_smart_ptr<T>::value>::type> {
99 typedef typename T::element_type* type;
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;
107 template<
class X,
class Enable =
void>
struct makearrayptr {};
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;
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;
117 struct JObjectPtr {
void *raw_{}, *shared_{};
bool init_{};};
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
132 using Handler = std::function<void(JSonError const&)>;
134 JSonError(Type type, JKString& arg, JKString& fname,
size_t line)
135 : type(type), arg(arg), fname(fname), line(line) {}
138 void print(std::ostream& out)
const {
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;
147 static const char* getErrorMessage(Type type) {
148 constexpr
static const char* _errors[ErrorCount] {
153 "premature end of file",
154 "invalid character in string: ",
156 "expecting , or } or ]",
159 "expecting } or name:value pair",
160 "expecting ] or value",
161 "expecting a quoted name:",
163 "unknown superclass",
164 "class already declared",
165 "already declared as a superclass",
167 "class member already declared",
168 "can't instantiate abstract class",
169 "can't create object",
170 "C-style array too small",
172 "expecting ID after @",
173 "expecting @id or @class",
174 "internal error: unexpected null pointer"
176 if (type >= ErrorCount)
return "Unknown error";
177 else return _errors[type];
191 virtual void* create() = 0;
192 virtual ~Creator() =
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;
204 virtual ~JSonArray() =
default;
205 virtual void add(
JSonSerial&, JSonClass::Creator*, JKString& s) = 0;
208 template <
class T,
class Enable =
void>
struct JSonArrayImpl :
public JSonArray {};
220 template <
typename Var>
225 template <
typename Var,
typename T>
231 template <
typename Set,
typename Get>
239 std::function<
void(C&,
JSonSerial&, JKString& value)> read,
240 std::function<
void(
const C&,
JSonSerial&)> write);
247 template <
typename Var>
249 std::function<
typename makeptr<Var>::type(C&)> creator);
256 template <
typename Var>
258 std::function<
typename makearrayptr<Var>::type(C&)> element_creator);
271 JKString&
className()
const override {
return classname_;}
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;
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;}
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;
298 const JSonClass* super_;
299 void* (*upcast_)(
void*);
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));}
307 JSonClasses& classes_;
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_{};
319 template <
class C>
class JMapClass :
public JSonClass {
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 {}
342 struct Helper {
static T* create() {
return new T;} ;};
343 return addClass<T>(classname, Helper::create);
355 void error(JSonError::Type type, JKString& arg, JKString& name) {
357 if (errhandler_) errhandler_(e);
else e.print(std::cout);
362 auto it = classnames_.find(classname);
363 return (it == classnames_.end()) ?
nullptr : it->second;
368 auto it = classindexes_.find(std::type_index(tinfo));
369 return (it == classindexes_.end()) ?
nullptr : it->second;
372 bool empty()
const {
return classnames_.empty();}
375 for (
auto& it : classnames_)
delete it.second;
380 std::unordered_map<std::type_index, JSonClass*> classindexes_;
381 std::unordered_map<std::string, JSonClass*> classnames_;
395 : classes_(&classes), errhandler_(handler) {}
398 : classes_(classes), errhandler_(handler) {}
407 bool read(T&
object, JKString& filename) {
408 std::ifstream input(filename);
409 if (input)
return read(
object, input, filename, 1);
411 reset(filename, 0,
nullptr,
nullptr,
false);
412 JSonError e(JSonError::CantReadFile,
"", filename, 0);
423 bool read(T&
object, std::istream& in,
424 JKString& name =
"",
size_t linenbr = 1) {
426 reset(name, linenbr, &in,
nullptr,
false);
427 JString keyword, dump;
429 readLine(keyword, dump, found1, found2,
true);
430 if (found1) readValue(*
this,
object, keyword);
else error(JSonError::NoData);
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);
451 reset(filename, 0,
nullptr,
nullptr,
false);
452 JSonError e(JSonError::CantWriteFile,
"", filename, 0);
463 bool write(
const T&
object, std::ostream& out,
bool cyclic_graph,
464 JKString& name =
"",
size_t linenbr = 1) {
466 reset(name, linenbr,
nullptr, &out, cyclic_graph);
468 *out_ <<
"\n" << std::endl;
486 Strict=0, Comments=1, NoQuotes=2, NoCommas=4, Newlines=8,
487 Relaxed=(Comments|NoQuotes|NoCommas|Newlines)
495 unsigned int getSyntax()
const {
return allow_;}
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_;}
508 readValue(*
this, variable, str);
514 writeTabs(); *out_ <<
'"' << token1_ <<
"\": ";
515 writeValue(variable);
518 void error(JSonError::Type type, JKString& arg =
"") {
519 throw JSonError(type, arg, fname_, lineno_);
522 void doError(JSonError e) {
523 if (errhandler_) errhandler_(e);
else e.print(std::cout);
527 const JSonClass* getCheckedClass(
const std::type_info& tinfo) {
528 const JSonClass* cl = classes_->
getClass(tinfo);
529 if (!cl) error(JSonError::UnknownClass, tinfo.name());
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);}
541 template <
class T>
void writeValue(
const T& val) {writeValue2<T>(val); needcomma_ =
true;}
545 void writeValue2(
const typename std::enable_if<std::is_pointer<T>::value,T>::type & ptr) {
546 if (!ptr) *out_ <<
"null";
else writeValue(*ptr);
551 void writeValue2(
const typename std::enable_if<is_owning_ptr<T>::value,T>::type & ptr) {
552 if (!ptr) *out_ <<
"null";
else writeValue(*ptr);
557 void writeValue2(
const typename std::enable_if<is_weak_ptr<T>::value,T>::type & ptr) {
559 if (!p) *out_ <<
"null";
else writeValue(*p);
564 void writeValue2(
const typename std::enable_if<std::is_arithmetic<T>::value,T>::type & number) {
570 void writeValue2(
const typename std::enable_if<std::is_enum<T>::value,T>::type & val) {
576 void writeValue2(
const typename std::enable_if<is_primitive<T>::value,T>::type & val) {
582 void writeValue2(
const typename std::enable_if<is_std_map<T>::value,T>::type & obj) {
583 JMapClass<T> cl; writeObject(cl,
false, &obj);
588 void writeValue2(
const typename std::enable_if<has_array_format<T>::value,T>::type & cont) {
589 if (cont.empty()) *out_ <<
"[]";
else writeArray(cont);
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);
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);
607 void writeObject(
const JSonClass& cl,
bool is_derived_class,
const void* obj) {
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_;
616 if (is_derived_class) {
617 writeTabs(); *out_ <<
"\"@class\": \"" << cl.className() <<
"\",\n";
620 writeTabs(); *out_ <<
"\"@id\": \"" << current_object_id_ <<
"\",\n";
622 cl.writeMembers(*
this, obj);
624 *out_ <<
"\n"; writeTabs(); *out_ <<
"}";
630 template <
class T>
void writeArray(
const T & array) {
634 for (
auto& it : array) {
635 if (needcomma_) *out_ <<
",\n";
641 *out_ <<
"\n"; writeTabs(); *out_ <<
"]";
645 void writeString(
const char* s,
bool is_cstring) {
646 if (!s) {*out_ << (is_cstring ?
"null" :
"\"\"");}
649 for (; *s != 0; ++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);
666 void readLine(JString& token1, JString& token2,
bool& found1,
bool& found2,
bool inObj) {
671 found1 = found2 =
false;
673 Begin, InQuotedToken1, InUnquotedToken1, AfterToken1, AfterComa,
674 InQuotedToken2, InUnquotedToken2, AfterToken2, Comment, LineComment
676 part{Begin}, lastPart{Begin};
681 if (!token1_.empty()) {token1 = token1_; checkValue(token1,inObj);}
687 else if (::iscntrl(c) && !::isspace(c))
689 else if ((allow_&Comments) && part!=InQuotedToken1 && part!=InQuotedToken2) {
690 if (part != Comment && c ==
'/' && in_->peek() ==
'/') {
691 if (part != LineComment) {lastPart = part; part = LineComment;}
693 else if (part != LineComment && c ==
'/' && in_->peek() ==
'*') {
694 if (part != Comment) {in_->get(c); lastPart = part; part = Comment;}
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;}
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;
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_);
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;}
726 if (in_->peek() !=
'"') part = InQuotedToken2;
729 if (in_->peek() !=
'"') {token2 =
""; part = AfterToken2;}
730 else {in_->get(c); part = InQuotedToken2; in_multiquotes_ =
true;}
733 else if (c ==
'{' || c ==
'[') {found2 =
true; token2 = c;
return;}
734 else if (!::isspace(c)) {found2 =
true; token2_ += c; part = InUnquotedToken2;}
738 if (!in_multiquotes_) {token2 = token2_; part = AfterToken2;}
739 else if (in_->peek() !=
'"') token2_ +=
'"';
742 if (in_->peek() !=
'"') token2_ +=
"\"\"";
744 in_->get(c); token2 = token2_; part = AfterToken2; in_multiquotes_ =
false;
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;
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_);
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;}
765 if ((allow_&Comments) && c ==
'\n') part = lastPart;
768 if ((allow_&Comments) && (c ==
'*' && in_->peek() ==
'/')) {in_->get(c); part = lastPart;}
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))+
")");
779 void readEscape(JString& token) {
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;
791 default: token += c;
break;
795 bool isNumber(JKString& token) {
796 if (token.empty())
return false;
797 bool dotfound{
false}, expfound{
false};
798 const char *p = token.c_str();
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;
812 void checkValue(JString& token,
bool objName) {
813 if (!token.empty()) {
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);
819 if ((allow_&NoQuotes) || token[0]==
'}' || token[0]==
']')
return;
820 else error(JSonError::ExpectingString, token);
822 else if ((allow_&NoQuotes) || token.empty()
823 || token[0]==
'}' || token[0]==
']' || token==
"true" || token==
"false" || token==
"null"
826 else error(JSonError::InvalidValue, token+
" (should be quoted)");
829 void reset(JKString& fname,
size_t lineno,
830 std::istream *in, std::ostream *out,
bool shareobj) {
833 if (in_) in_->imbue(locale_);
834 if (out_) out_->imbue(locale_);
838 shareobj_ = shareobj;
842 in_multiquotes_ =
false;
843 tabs_.assign(40, tabchar_);
844 object_to_id_.clear();
845 id_to_object_.clear();
846 current_object_id_ = 0;
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_);}
853 JSonClasses
const* classes_{};
855 std::locale locale_{
"en_US.UTF-8"};
857 std::ostream *out_{};
858 unsigned char allow_{Comments};
859 bool needcomma_{}, in_multiquotes_{}, shareobj_{};
861 unsigned int indent_{2};
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_;
873 const JSonClass* objclass,
const JSonClass* pointerclass,
874 JObjectPtr*& jsp, JSonClass::Creator* cr,
void* obj, JKString& s);
879 typename std::enable_if<!is_user_class<E>::value,std::unique_ptr<E>>::type & ptr,
880 JObjectPtr *&, JSonClass::Creator*, JKString& s) {
882 readValue(js, *ptr, s);
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)));
897 typename std::enable_if<!is_user_class<E>::value,std::shared_ptr<E>>::type & ptr,
898 JObjectPtr *&, JSonClass::Creator*, JKString& s) {
900 readValue(js,*ptr, s);
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_) {
912 objptr->init_ =
false;
913 ptr = *
static_cast<std::shared_ptr<E>*
>(objptr->shared_);
917 objptr->shared_ = &ptr;
918 objptr->init_ =
true;
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();
930 readValue(js, **shp, s);
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_) {
945 objptr->init_ =
false;
946 *shp = *
static_cast<std::shared_ptr<T>*
>(objptr->shared_);
950 objptr->shared_ = &ptr;
951 objptr->init_ =
true;
959 typename std::enable_if<!is_user_class<
typename std::remove_reference<T>::type>::value,T>::type *& ptr,
960 JObjectPtr *&, JSonClass::Creator*, JKString& s) {
962 readValue(js, *ptr, s);
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));
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);
985 typename std::enable_if<is_smart_ptr<T>::value,T>::type & ptr,
987 JObjectPtr* objptr{}; ptr.reset();
988 if (s !=
"null") readPointee<T>(js, ptr, objptr,
nullptr, s);
994 typename std::enable_if<std::is_arithmetic<T>::value,T>::type & val,
996 std::istringstream ss(s);
997 ss.imbue(js.locale_);
1004 typename std::enable_if<std::is_enum<T>::value,T>::type & val,
1006 val = T(std::stoi(s));
1012 typename std::enable_if<is_primitive<T>::value,T>::type & val,
1020 typename std::enable_if<is_user_class<T>::value,T>::type & obj,
1022 const JSonClass* wanted_class = js.getCheckedClass(
typeid(obj));
1023 JObjectPtr* objptr{};
1024 readObject(js, wanted_class, wanted_class, objptr,
nullptr, &obj, s);
1030 typename std::enable_if<is_std_map<T>::value,T>::type & obj,
1032 JMapClass<T> wanted_class; JObjectPtr* objptr{};
1033 readObject(js, &wanted_class, &wanted_class, objptr,
nullptr, &obj, s);
1039 typename std::enable_if<std::is_array<T>::value,T>::type & array,
1041 JSonArrayImpl<T> a(array); readArray(js, a,
nullptr, s);
1047 typename std::enable_if<has_array_format<T>::value,T>::type & array,
1049 JSonArrayImpl<T> a(array); readArray(js, a,
nullptr, s);
1052 inline char* tocstr_(JKString& s) {
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);
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");
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);}
1078 inline void readValue(
JSonSerial& js, T *& ptr, JKString& s) {
1080 JObjectPtr* objptr{};
1081 if (s !=
"null") readPointee<T>(js, ptr, objptr,
nullptr, s);
1086 inline void readValue(
JSonSerial& js, T& value, JKString& s) {
1087 readValue2<T>(js, value, s);
1098 JSonClass
const* objclass, JSonClass
const* pointerclass,
1099 JObjectPtr*& jsp, JSonClass::Creator* cr,
void* obj,
1101 if (s.empty()) js.error(JSonError::ExpectingBrace);
1102 else if (s[0] ==
'@') {
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);
1106 return obj = it->second.raw_;
1108 else if (s !=
"{") js.error(JSonError::ExpectingBrace);
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);
1117 if (name[0]==
'@' && name !=
"@class" && name !=
"@id")
1118 js.error(JSonError::WrongKeyword, value);
1121 if (name !=
"@class") objclass = pointerclass;
1123 objclass = js.classes_->getClass(value);
1124 if (!objclass) js.error(JSonError::UnknownClass, value);
1127 if (cr) obj = cr->create();
1128 else obj = objclass->create();
1130 if (!obj) js.error(JSonError::AbstractClass, objclass->className());
1131 if (name ==
"@class")
continue;
1134 if (name ==
"}") {objclass->doPostRead(obj);
return obj;}
1135 else if (name ==
"@id") {
1136 jsp = &js.id_to_object_[std::stoul(value)];
1141 if (!objclass->readMember(js, obj, name, value))
1142 js.error(JSonError::UnknownMember,
1143 "'" +name +
"' in class '" + objclass->className()+
"'");
1145 catch (std::invalid_argument) {
1146 js.error(JSonError::InvalidValue, value+
" for member '"+name+
"'");
1149 js.error(JSonError::PrematureEOF);
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()) {
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;}
1163 else a.add(js, cr, tok);
1170 typename std::enable_if<is_smart_ptr<T>::value,T>::type & e,
1171 JObjectPtr*& objptr, JSonClass::Creator* cr, JKString& s) {
1173 if (s !=
"null") readPointee<T>(js, e, objptr, cr, s);
1179 typename std::enable_if<!is_smart_ptr<T>::value,T>::type & e,
1180 JObjectPtr*&, JSonClass::Creator*, JKString& s) {
1181 readValue(js, e, s);
1185 inline void readArrayValue(
JSonSerial& js,
char* & e,
1186 JObjectPtr*&, JSonClass::Creator*, JKString& s) {
1188 readValue(js, e, s);
1192 inline void readArrayValue(
JSonSerial& js,
const char* & e,
1193 JObjectPtr*&, JSonClass::Creator*, JKString& s) {
1195 readValue(js, e, s);
1200 inline void readArrayValue(
JSonSerial& js, T *& e, JObjectPtr*& objptr,
1201 JSonClass::Creator* cr, JKString& s) {
1203 if (s !=
"null") readPointee<T>(js, e, objptr, cr, s);
1208 inline void readArrayValue(
JSonSerial& js, T & e, JObjectPtr*& objptr,
1209 JSonClass::Creator* cr, JKString& s) {
1210 readArrayValue2<T>(js, e, objptr, cr, s);
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) {}
1219 std::function<R(C&)> creator_;
1220 void* create()
override {
return (creator_)(obj_);}
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_);}
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_);}
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_);}
1249 std::function<bool(const T&)> write_if_;
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) {}
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);
1263 void write(
JSonSerial& js,
const T& obj)
override {js.writeValue(obj.*variable_);}
1266 std::function<R(T&)> creator_;
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) {}
1274 ObjectCreatorImpl<T,R> c(obj, creator_);
1275 JSonArrayImpl<Var> a(obj.*variable_);
1276 readArray(js, a, &c, s);
1278 void write(
JSonSerial& js,
const T& obj)
override {js.writeValue(obj.*variable_);}
1281 std::function<R(T&)> creator_;
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) {}
1289 typename std::remove_const<typename std::remove_reference<SetVal>::type>::type var;
1290 readValue(js, var, val);
1291 (obj.*setter_)(std::move(var));
1293 void write(
JSonSerial& js,
const T& obj)
override {js.writeValue((obj.*getter_)());}
1295 void (T::*setter_)(SetVal);
1296 GetVal (T::*getter_)()
const;
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);}
1309 std::function<void(T&, JSonSerial&, JKString&)> readfun_;
1310 std::function<void(const T&, JSonSerial&)> writefun_;
1314 template <
typename Var>
1316 addMember(name,
new StaticMember<T,Var>(name, var));
1321 template <
typename Var,
typename C>
1323 addMember(name,
new InstanceMember<T,Var>(name, var));
1328 template <
typename SetVal,
typename GetVal>
1330 void (T::*setter)(SetVal), GetVal (T::*getter)()
const) {
1331 addMember(name,
new InstanceMemberWithAccessor<T,SetVal,GetVal>(name, setter, getter));
1336 template <
typename Var>
1338 std::function<
typename makeptr<Var>::type(T&)> cr) {
1339 addMember(name,
new InstanceMemberWithCreator<T,Var,
typename makeptr<Var>::type>(name, var, cr));
1344 template <
typename Var>
1346 std::function<
typename makearrayptr<Var>::type(T&)> cr) {
1347 addMember(name,
new ArrayMemberWithCreator<T,Var,
typename makearrayptr<Var>::type>(name, var, cr));
1355 addMember(name,
new InstanceCustomMember<T>(name,
read,
write));
1360 template <
typename Super>
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()");
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()");
1378 if (getMember(name))
1379 classes_.
error(JSonError::RedefinedMember,
": member "+name+
" of class "+classname_,
"member()");
1381 members_.push_back(m); membermap_[name] = m;
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;
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)) {
1394 mb->read(js, *static_cast<T*>(obj), val);
1397 for (
auto& it : superclasses_) {
1398 if (it.super_->readMember(js, (it.upcast_)(obj), name, val))
return true;
1404 void JSonUserClass<T>::writeMembers(
JSonSerial& js,
const void* obj)
const {
1405 if (!obj) js.error(JSonError::UnexpectedNull);
1406 for (
auto& it : superclasses_) {
1407 it.super_->writeMembers(js, (it.upcast_)((
void*)obj));
1409 for (
auto& it : members_) {
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));
1418 void JSonUserClass<T>::doPostRead(
void* obj)
const {
1419 if (obj && postread_) postread_(*static_cast<T*>(obj));
1423 void JSonUserClass<T>::doPostWrite(
const void* obj)
const {
1424 if (obj && postwrite_) postwrite_(*static_cast<const T*>(obj));
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);
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);
1446 if (getClass(classname)) error(JSonError::RedefinedClass, classname,
"add()");
1448 classindexes_[std::type_index(
typeid(T))] = classnames_[classname] = cl;
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 {
1458 if (index_ >= std::extent<T>::value) js.error(JSonError::CantAddToArray);
1459 else readArrayValue(js, array_[index_++], jsp, cr, s);