Use 4 jobs to build nanox
[fltk_mvc_template.git] / _template / include / json.h
1 #ifndef JSON_H
2 #define JSON_H
3
4 #include <cstdint>
5 #include <cmath>
6 #include <cctype>
7 #include <string>
8 #include <deque>
9 #include <map>
10 #include <type_traits>
11 #include <initializer_list>
12 #include <ostream>
13 #include <iostream>
14
15 namespace json {
16
17 using std::map;
18 using std::deque;
19 using std::string;
20 using std::enable_if;
21 using std::initializer_list;
22 using std::is_same;
23 using std::is_convertible;
24 using std::is_integral;
25 using std::is_floating_point;
26
27 namespace {
28     string json_escape( const string &str ) {
29         string output;
30         for( unsigned i = 0; i < str.length(); ++i )
31             switch( str[i] ) {
32                 case '\"': output += "\\\""; break;
33                 case '\\': output += "\\\\"; break;
34                 case '\b': output += "\\b";  break;
35                 case '\f': output += "\\f";  break;
36                 case '\n': output += "\\n";  break;
37                 case '\r': output += "\\r";  break;
38                 case '\t': output += "\\t";  break;
39                 default  : output += str[i]; break;
40             }
41         return std::move( output );
42     }
43 }
44
45 class JSON
46 {
47     union BackingData {
48         BackingData( double d ) : Float( d ){}
49         BackingData( long   l ) : Int( l ){}
50         BackingData( bool   b ) : m_Bool( b ){}
51         BackingData( string s ) : String( new string( s ) ){}
52         BackingData()           : Int( 0 ){}
53
54         deque<JSON>        *List;
55         map<string,JSON>   *Map;
56         string             *String;
57         double              Float;
58         long                Int;
59         bool                m_Bool;
60     } Internal;
61
62     public:
63         enum class Class {
64             Null,
65             Object,
66             Array,
67             String,
68             Floating,
69             Integral,
70             Boolean
71         };
72
73         template <typename Container>
74         class JSONWrapper {
75             Container *object;
76
77             public:
78                 JSONWrapper( Container *val ) : object( val ) {}
79                 JSONWrapper( std::nullptr_t )  : object( nullptr ) {}
80
81                 typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
82                 typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
83                 typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
84                 typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
85         };
86
87         template <typename Container>
88         class JSONConstWrapper {
89             const Container *object;
90
91             public:
92                 JSONConstWrapper( const Container *val ) : object( val ) {}
93                 JSONConstWrapper( std::nullptr_t )  : object( nullptr ) {}
94
95                 typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); }
96                 typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); }
97         };
98
99         JSON() : Internal(), Type( Class::Null ){}
100
101         JSON( initializer_list<JSON> list ) 
102             : JSON() 
103         {
104             SetType( Class::Object );
105             for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i )
106                 operator[]( i->ToString() ) = *std::next( i );
107         }
108
109         JSON( JSON&& other )
110             : Internal( other.Internal )
111             , Type( other.Type )
112         { other.Type = Class::Null; other.Internal.Map = nullptr; }
113
114         JSON& operator=( JSON&& other ) {
115             ClearInternal();
116             Internal = other.Internal;
117             Type = other.Type;
118             other.Internal.Map = nullptr;
119             other.Type = Class::Null;
120             return *this;
121         }
122
123         JSON( const JSON &other ) {
124             switch( other.Type ) {
125             case Class::Object:
126                 Internal.Map = 
127                     new map<string,JSON>( other.Internal.Map->begin(),
128                                           other.Internal.Map->end() );
129                 break;
130             case Class::Array:
131                 Internal.List = 
132                     new deque<JSON>( other.Internal.List->begin(),
133                                       other.Internal.List->end() );
134                 break;
135             case Class::String:
136                 Internal.String = 
137                     new string( *other.Internal.String );
138                 break;
139             default:
140                 Internal = other.Internal;
141             }
142             Type = other.Type;
143         }
144
145         JSON& operator=( const JSON &other ) {
146             ClearInternal();
147             switch( other.Type ) {
148             case Class::Object:
149                 Internal.Map = 
150                     new map<string,JSON>( other.Internal.Map->begin(),
151                                           other.Internal.Map->end() );
152                 break;
153             case Class::Array:
154                 Internal.List = 
155                     new deque<JSON>( other.Internal.List->begin(),
156                                       other.Internal.List->end() );
157                 break;
158             case Class::String:
159                 Internal.String = 
160                     new string( *other.Internal.String );
161                 break;
162             default:
163                 Internal = other.Internal;
164             }
165             Type = other.Type;
166             return *this;
167         }
168
169         ~JSON() {
170             switch( Type ) {
171             case Class::Array:
172                 delete Internal.List;
173                 break;
174             case Class::Object:
175                 delete Internal.Map;
176                 break;
177             case Class::String:
178                 delete Internal.String;
179                 break;
180             default:;
181             }
182         }
183
184         template <typename T>
185         JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){}
186
187         template <typename T>
188         JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = 0 ) : Internal( (long)i ), Type( Class::Integral ){}
189
190         template <typename T>
191         JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = 0 ) : Internal( (double)f ), Type( Class::Floating ){}
192
193         template <typename T>
194         JSON( T s, typename enable_if<is_convertible<T,string>::value>::type* = 0 ) : Internal( string( s ) ), Type( Class::String ){}
195
196         JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){}
197
198         static JSON Make( Class type ) {
199             JSON ret; ret.SetType( type );
200             return ret;
201         }
202
203         static JSON Load( const string & );
204         static JSON Load( const string &, bool & );
205
206         template <typename T>
207         void append( T arg ) {
208             SetType( Class::Array ); Internal.List->emplace_back( arg );
209         }
210
211         template <typename T, typename... U>
212         void append( T arg, U... args ) {
213             append( arg ); append( args... );
214         }
215
216         template <typename T>
217             typename enable_if<is_same<T,bool>::value, JSON&>::type operator=( T b ) {
218                 SetType( Class::Boolean ); Internal.m_Bool = b; return *this;
219             }
220
221         template <typename T>
222             typename enable_if<is_integral<T>::value && !is_same<T,bool>::value, JSON&>::type operator=( T i ) {
223                 SetType( Class::Integral ); Internal.Int = i; return *this;
224             }
225
226         template <typename T>
227             typename enable_if<is_floating_point<T>::value, JSON&>::type operator=( T f ) {
228                 SetType( Class::Floating ); Internal.Float = f; return *this;
229             }
230
231         template <typename T>
232             typename enable_if<is_convertible<T,string>::value, JSON&>::type operator=( T s ) {
233                 SetType( Class::String ); *Internal.String = string( s ); return *this;
234             }
235
236         JSON& operator[]( const string &key ) {
237             SetType( Class::Object ); return Internal.Map->operator[]( key );
238         }
239
240         JSON& operator[]( unsigned index ) {
241             SetType( Class::Array );
242             if( index >= Internal.List->size() ) Internal.List->resize( index + 1 );
243             return Internal.List->operator[]( index );
244         }
245
246         JSON &at( const string &key ) {
247             return operator[]( key );
248         }
249
250         const JSON &at( const string &key ) const {
251             return Internal.Map->at( key );
252         }
253
254         JSON &at( unsigned index ) {
255             return operator[]( index );
256         }
257
258         const JSON &at( unsigned index ) const {
259             return Internal.List->at( index );
260         }
261
262         int length() const {
263             if( Type == Class::Array )
264                 return Internal.List->size();
265             else
266                 return -1;
267         }
268
269         bool hasKey( const string &key ) const {
270             if( Type == Class::Object )
271                 return Internal.Map->find( key ) != Internal.Map->end();
272             return false;
273         }
274
275         int size() const {
276             if( Type == Class::Object )
277                 return Internal.Map->size();
278             else if( Type == Class::Array )
279                 return Internal.List->size();
280             else
281                 return -1;
282         }
283
284         Class JSONType() const { return Type; }
285
286         /// Functions for getting primitives from the JSON object.
287         bool IsNull() const { return Type == Class::Null; }
288
289         string ToString() const { bool b; return std::move( ToString( b ) ); }
290         string ToString( bool &ok ) const {
291             ok = (Type == Class::String);
292             return ok ? std::move( json_escape( *Internal.String ) ): string("");
293         }
294
295         double ToFloat() const { bool b; return ToFloat( b ); }
296         double ToFloat( bool &ok ) const {
297             ok = (Type == Class::Floating);
298             return ok ? Internal.Float : 0.0;
299         }
300
301         long ToInt() const { bool b; return ToInt( b ); }
302         long ToInt( bool &ok ) const {
303             ok = (Type == Class::Integral);
304             return ok ? Internal.Int : 0;
305         }
306
307         bool ToBool() const { bool b; return ToBool( b ); }
308         bool ToBool( bool &ok ) const {
309             ok = (Type == Class::Boolean);
310             return ok ? Internal.m_Bool : false;
311         }
312
313         JSONWrapper<map<string,JSON>> ObjectRange() {
314             if( Type == Class::Object )
315                 return JSONWrapper<map<string,JSON>>( Internal.Map );
316             return JSONWrapper<map<string,JSON>>( nullptr );
317         }
318
319         JSONWrapper<deque<JSON>> ArrayRange() {
320             if( Type == Class::Array )
321                 return JSONWrapper<deque<JSON>>( Internal.List );
322             return JSONWrapper<deque<JSON>>( nullptr );
323         }
324
325         JSONConstWrapper<map<string,JSON>> ObjectRange() const {
326             if( Type == Class::Object )
327                 return JSONConstWrapper<map<string,JSON>>( Internal.Map );
328             return JSONConstWrapper<map<string,JSON>>( nullptr );
329         }
330
331
332         JSONConstWrapper<deque<JSON>> ArrayRange() const { 
333             if( Type == Class::Array )
334                 return JSONConstWrapper<deque<JSON>>( Internal.List );
335             return JSONConstWrapper<deque<JSON>>( nullptr );
336         }
337
338         string dump( int depth = 1, string tab = "  ") const {
339             string pad = "";
340             for( int i = 0; i < depth; ++i, pad += tab );
341
342             switch( Type ) {
343                 case Class::Null:
344                     return "null";
345                 case Class::Object: {
346                     string s = "{\n";
347                     bool skip = true;
348                     for( auto &p : *Internal.Map ) {
349                         if( !skip ) s += ",\n";
350                         s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
351                         skip = false;
352                     }
353                     s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
354                     return s;
355                 }
356                 case Class::Array: {
357                     string s = "[";
358                     bool skip = true;
359                     for( auto &p : *Internal.List ) {
360                         if( !skip ) s += ", ";
361                         s += p.dump( depth + 1, tab );
362                         skip = false;
363                     }
364                     s += "]";
365                     return s;
366                 }
367                 case Class::String:
368                     return "\"" + json_escape( *Internal.String ) + "\"";
369                 case Class::Floating:
370                     return std::to_string( Internal.Float );
371                 case Class::Integral:
372                     return std::to_string( Internal.Int );
373                 case Class::Boolean:
374                     return Internal.m_Bool ? "true" : "false";
375                 default:
376                     return "";
377             }
378             return "";
379         }
380
381         friend std::ostream& operator<<( std::ostream&, const JSON & );
382
383     private:
384         void SetType( Class type ) {
385             if( type == Type )
386                 return;
387
388             ClearInternal();
389           
390             switch( type ) {
391             case Class::Null:      Internal.Map    = nullptr;                break;
392             case Class::Object:    Internal.Map    = new map<string,JSON>(); break;
393             case Class::Array:     Internal.List   = new deque<JSON>();     break;
394             case Class::String:    Internal.String = new string();           break;
395             case Class::Floating:  Internal.Float  = 0.0;                    break;
396             case Class::Integral:  Internal.Int    = 0;                      break;
397             case Class::Boolean:   Internal.m_Bool   = false;                  break;
398             }
399
400             Type = type;
401         }
402
403     private:
404       /* beware: only call if YOU know that Internal is allocated. No checks performed here. 
405          This function should be called in a constructed JSON just before you are going to 
406         overwrite Internal... 
407       */
408       void ClearInternal() {
409         switch( Type ) {
410           case Class::Object: delete Internal.Map;    break;
411           case Class::Array:  delete Internal.List;   break;
412           case Class::String: delete Internal.String; break;
413           default:;
414         }
415       }
416
417     private:
418
419         Class Type = Class::Null;
420 };
421
422 inline JSON Array() {
423     return std::move( JSON::Make( JSON::Class::Array ) );
424 }
425
426 template <typename... T>
427 JSON Array( T... args ) {
428     JSON arr = JSON::Make( JSON::Class::Array );
429     arr.append( args... );
430     return std::move( arr );
431 }
432
433 inline JSON Object() {
434     return std::move( JSON::Make( JSON::Class::Object ) );
435 }
436
437 inline std::ostream& operator<<( std::ostream &os, const JSON &json ) {
438     os << json.dump();
439     return os;
440 }
441
442 namespace {
443     JSON parse_next( const string &, size_t &, bool & );
444
445     void consume_ws( const string &str, size_t &offset ) {
446         while( isspace( str[offset] ) ) ++offset;
447     }
448
449     JSON parse_object( const string &str, size_t &offset, bool& rc ) {
450         JSON Object = JSON::Make( JSON::Class::Object );
451
452         ++offset;
453         consume_ws( str, offset );
454         if( str[offset] == '}' ) {
455             ++offset; return std::move( Object );
456         }
457
458         while( true ) {
459             JSON Key = parse_next( str, offset, rc );
460             consume_ws( str, offset );
461             if( str[offset] != ':' ) {
462                 //std::cerr << "Error: Object: Expected colon, found '" << str[offset] << "'\n";
463                 rc = false;
464                 break;
465             }
466             consume_ws( str, ++offset );
467             JSON Value = parse_next( str, offset, rc );
468             Object[Key.ToString()] = Value;
469             
470             consume_ws( str, offset );
471             if( str[offset] == ',' ) {
472                 ++offset; continue;
473             }
474             else if( str[offset] == '}' ) {
475                 ++offset; break;
476             }
477             else {
478                 //std::cerr << "ERROR: Object: Expected comma, found '" << str[offset] << "'\n";
479                 rc = false;
480                 break;
481             }
482         }
483
484         return std::move( Object );
485     }
486
487     JSON parse_array( const string &str, size_t &offset, bool& rc ) {
488         JSON Array = JSON::Make( JSON::Class::Array );
489         unsigned index = 0;
490         
491         ++offset;
492         consume_ws( str, offset );
493         if( str[offset] == ']' ) {
494             ++offset; return std::move( Array );
495         }
496
497         while( true ) {
498             Array[index++] = parse_next( str, offset, rc );
499             consume_ws( str, offset );
500
501             if( str[offset] == ',' ) {
502                 ++offset; continue;
503             }
504             else if( str[offset] == ']' ) {
505                 ++offset; break;
506             }
507             else {
508                 //std::cerr << "ERROR: Array: Expected ',' or ']', found '" << str[offset] << "'\n";
509                 rc = false;
510                 return std::move( JSON::Make( JSON::Class::Array ) );
511             }
512         }
513
514         return std::move( Array );
515     }
516
517     JSON parse_string( const string &str, size_t &offset, bool& rc ) {
518         JSON String;
519         string val;
520         for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
521             if( c == '\\' ) {
522                 switch( str[ ++offset ] ) {
523                 case '\"': val += '\"'; break;
524                 case '\\': val += '\\'; break;
525                 case '/' : val += '/' ; break;
526                 case 'b' : val += '\b'; break;
527                 case 'f' : val += '\f'; break;
528                 case 'n' : val += '\n'; break;
529                 case 'r' : val += '\r'; break;
530                 case 't' : val += '\t'; break;
531                 case 'u' : {
532                     val += "\\u" ;
533                     for( unsigned i = 1; i <= 4; ++i ) {
534                         c = str[offset+i];
535                         if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
536                             val += c;
537                         else {
538                             //std::cerr << "ERROR: String: Expected hex character in unicode escape, found '" << c << "'\n";
539                             rc = false;
540                             return std::move( JSON::Make( JSON::Class::String ) );
541                         }
542                     }
543                     offset += 4;
544                 } break;
545                 default  : val += '\\'; break;
546                 }
547             }
548             else
549                 val += c;
550         }
551         ++offset;
552         String = val;
553         return std::move( String );
554     }
555
556     JSON parse_number( const string &str, size_t &offset, bool& rc ) {
557         JSON Number;
558         string val, exp_str;
559         char c;
560         bool isDouble = false;
561         long exp = 0;
562         while( true ) {
563             c = str[offset++];
564             if( (c == '-') || (c >= '0' && c <= '9') )
565                 val += c;
566             else if( c == '.' ) {
567                 val += c; 
568                 isDouble = true;
569             }
570             else
571                 break;
572         }
573         if( c == 'E' || c == 'e' ) {
574             c = str[ offset++ ];
575             if( c == '-' ){ ++offset; exp_str += '-';}
576             while( true ) {
577                 c = str[ offset++ ];
578                 if( c >= '0' && c <= '9' )
579                     exp_str += c;
580                 else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
581                     //std::cerr << "ERROR: Number: Expected a number for exponent, found '" << c << "'\n";
582                     rc = false;
583                     return std::move( JSON::Make( JSON::Class::Null ) );
584                 }
585                 else
586                     break;
587             }
588             exp = std::stol( exp_str );
589         }
590         else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
591             //std::cerr << "ERROR: Number: unexpected character '" << c << "'\n";
592             rc = false;
593             return std::move( JSON::Make( JSON::Class::Null ) );
594         }
595         --offset;
596         
597         if( isDouble )
598             Number = std::stod( val ) * std::pow( 10, exp );
599         else {
600             if( !exp_str.empty() )
601                 Number = std::stol( val ) * std::pow( 10, exp );
602             else
603                 Number = std::stol( val );
604         }
605         return std::move( Number );
606     }
607
608     JSON parse_bool( const string &str, size_t &offset, bool& rc ) {
609         JSON m_Bool;
610         if( str.substr( offset, 4 ) == "true" )
611             m_Bool = true;
612         else if( str.substr( offset, 5 ) == "false" )
613             m_Bool = false;
614         else {
615             //std::cerr << "ERROR: Bool: Expected 'true' or 'false', found '" << str.substr( offset, 5 ) << "'\n";
616             rc = false;
617             return std::move( JSON::Make( JSON::Class::Null ) );
618         }
619         offset += (m_Bool.ToBool() ? 4 : 5);
620         return std::move( m_Bool );
621     }
622
623     JSON parse_null( const string &str, size_t &offset, bool& rc ) {
624         JSON Null;
625         if( str.substr( offset, 4 ) != "null" ) {
626             //std::cerr << "ERROR: Null: Expected 'null', found '" << str.substr( offset, 4 ) << "'\n";
627             rc = false;
628             return std::move( JSON::Make( JSON::Class::Null ) );
629         }
630         offset += 4;
631         return std::move( Null );
632     }
633
634     JSON parse_next( const string &str, size_t &offset, bool& rc ) {
635         char value;
636         consume_ws( str, offset );
637         value = str[offset];
638         switch( value ) {
639             case '[' : return std::move( parse_array( str, offset, rc ) );
640             case '{' : return std::move( parse_object( str, offset, rc ) );
641             case '\"': return std::move( parse_string( str, offset, rc ) );
642             case 't' :
643             case 'f' : return std::move( parse_bool( str, offset, rc ) );
644             case 'n' : return std::move( parse_null( str, offset, rc ) );
645             default  : if( ( value <= '9' && value >= '0' ) || value == '-' )
646                            return std::move( parse_number( str, offset, rc ) );
647         }
648         //std::cerr << "ERROR: Parse: Unknown starting character '" << value << "'\n";
649         rc = false;
650         return JSON();
651     }
652 }
653
654 inline JSON JSON::Load( const string &str, bool& rc ) {
655     size_t offset = 0;
656     rc = true;
657     return std::move( parse_next( str, offset, rc ) );
658 }
659
660 inline JSON JSON::Load( const string &str ) {
661     size_t offset = 0;
662     bool rc = true;
663     return std::move( parse_next( str, offset, rc ) );
664 }
665
666 } // End Namespace json
667 #endif // JSON_H