10 #include <type_traits>
11 #include <initializer_list>
21 using std::initializer_list;
23 using std::is_convertible;
24 using std::is_integral;
25 using std::is_floating_point;
28 string json_escape( const string &str ) {
30 for( unsigned i = 0; i < str.length(); ++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;
41 return std::move( output );
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 ){}
55 map<string,JSON> *Map;
73 template <typename Container>
78 JSONWrapper( Container *val ) : object( val ) {}
79 JSONWrapper( std::nullptr_t ) : object( nullptr ) {}
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(); }
87 template <typename Container>
88 class JSONConstWrapper {
89 const Container *object;
92 JSONConstWrapper( const Container *val ) : object( val ) {}
93 JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {}
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(); }
99 JSON() : Internal(), Type( Class::Null ){}
101 JSON( initializer_list<JSON> list )
104 SetType( Class::Object );
105 for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i )
106 operator[]( i->ToString() ) = *std::next( i );
110 : Internal( other.Internal )
112 { other.Type = Class::Null; other.Internal.Map = nullptr; }
114 JSON& operator=( JSON&& other ) {
116 Internal = other.Internal;
118 other.Internal.Map = nullptr;
119 other.Type = Class::Null;
123 JSON( const JSON &other ) {
124 switch( other.Type ) {
127 new map<string,JSON>( other.Internal.Map->begin(),
128 other.Internal.Map->end() );
132 new deque<JSON>( other.Internal.List->begin(),
133 other.Internal.List->end() );
137 new string( *other.Internal.String );
140 Internal = other.Internal;
145 JSON& operator=( const JSON &other ) {
147 switch( other.Type ) {
150 new map<string,JSON>( other.Internal.Map->begin(),
151 other.Internal.Map->end() );
155 new deque<JSON>( other.Internal.List->begin(),
156 other.Internal.List->end() );
160 new string( *other.Internal.String );
163 Internal = other.Internal;
172 delete Internal.List;
178 delete Internal.String;
184 template <typename T>
185 JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){}
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 ){}
190 template <typename T>
191 JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = 0 ) : Internal( (double)f ), Type( Class::Floating ){}
193 template <typename T>
194 JSON( T s, typename enable_if<is_convertible<T,string>::value>::type* = 0 ) : Internal( string( s ) ), Type( Class::String ){}
196 JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){}
198 static JSON Make( Class type ) {
199 JSON ret; ret.SetType( type );
203 static JSON Load( const string & );
204 static JSON Load( const string &, bool & );
206 template <typename T>
207 void append( T arg ) {
208 SetType( Class::Array ); Internal.List->emplace_back( arg );
211 template <typename T, typename... U>
212 void append( T arg, U... args ) {
213 append( arg ); append( args... );
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;
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;
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;
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;
236 JSON& operator[]( const string &key ) {
237 SetType( Class::Object ); return Internal.Map->operator[]( key );
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 );
246 JSON &at( const string &key ) {
247 return operator[]( key );
250 const JSON &at( const string &key ) const {
251 return Internal.Map->at( key );
254 JSON &at( unsigned index ) {
255 return operator[]( index );
258 const JSON &at( unsigned index ) const {
259 return Internal.List->at( index );
263 if( Type == Class::Array )
264 return Internal.List->size();
269 bool hasKey( const string &key ) const {
270 if( Type == Class::Object )
271 return Internal.Map->find( key ) != Internal.Map->end();
276 if( Type == Class::Object )
277 return Internal.Map->size();
278 else if( Type == Class::Array )
279 return Internal.List->size();
284 Class JSONType() const { return Type; }
286 /// Functions for getting primitives from the JSON object.
287 bool IsNull() const { return Type == Class::Null; }
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("");
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;
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;
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;
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 );
319 JSONWrapper<deque<JSON>> ArrayRange() {
320 if( Type == Class::Array )
321 return JSONWrapper<deque<JSON>>( Internal.List );
322 return JSONWrapper<deque<JSON>>( nullptr );
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 );
332 JSONConstWrapper<deque<JSON>> ArrayRange() const {
333 if( Type == Class::Array )
334 return JSONConstWrapper<deque<JSON>>( Internal.List );
335 return JSONConstWrapper<deque<JSON>>( nullptr );
338 string dump( int depth = 1, string tab = " ") const {
340 for( int i = 0; i < depth; ++i, pad += tab );
345 case Class::Object: {
348 for( auto &p : *Internal.Map ) {
349 if( !skip ) s += ",\n";
350 s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
353 s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
359 for( auto &p : *Internal.List ) {
360 if( !skip ) s += ", ";
361 s += p.dump( depth + 1, tab );
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 );
374 return Internal.m_Bool ? "true" : "false";
381 friend std::ostream& operator<<( std::ostream&, const JSON & );
384 void SetType( Class 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;
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...
408 void ClearInternal() {
410 case Class::Object: delete Internal.Map; break;
411 case Class::Array: delete Internal.List; break;
412 case Class::String: delete Internal.String; break;
419 Class Type = Class::Null;
422 inline JSON Array() {
423 return std::move( JSON::Make( JSON::Class::Array ) );
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 );
433 inline JSON Object() {
434 return std::move( JSON::Make( JSON::Class::Object ) );
437 inline std::ostream& operator<<( std::ostream &os, const JSON &json ) {
443 JSON parse_next( const string &, size_t &, bool & );
445 void consume_ws( const string &str, size_t &offset ) {
446 while( isspace( str[offset] ) ) ++offset;
449 JSON parse_object( const string &str, size_t &offset, bool& rc ) {
450 JSON Object = JSON::Make( JSON::Class::Object );
453 consume_ws( str, offset );
454 if( str[offset] == '}' ) {
455 ++offset; return std::move( Object );
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";
466 consume_ws( str, ++offset );
467 JSON Value = parse_next( str, offset, rc );
468 Object[Key.ToString()] = Value;
470 consume_ws( str, offset );
471 if( str[offset] == ',' ) {
474 else if( str[offset] == '}' ) {
478 //std::cerr << "ERROR: Object: Expected comma, found '" << str[offset] << "'\n";
484 return std::move( Object );
487 JSON parse_array( const string &str, size_t &offset, bool& rc ) {
488 JSON Array = JSON::Make( JSON::Class::Array );
492 consume_ws( str, offset );
493 if( str[offset] == ']' ) {
494 ++offset; return std::move( Array );
498 Array[index++] = parse_next( str, offset, rc );
499 consume_ws( str, offset );
501 if( str[offset] == ',' ) {
504 else if( str[offset] == ']' ) {
508 //std::cerr << "ERROR: Array: Expected ',' or ']', found '" << str[offset] << "'\n";
510 return std::move( JSON::Make( JSON::Class::Array ) );
514 return std::move( Array );
517 JSON parse_string( const string &str, size_t &offset, bool& rc ) {
520 for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
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;
533 for( unsigned i = 1; i <= 4; ++i ) {
535 if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )
538 //std::cerr << "ERROR: String: Expected hex character in unicode escape, found '" << c << "'\n";
540 return std::move( JSON::Make( JSON::Class::String ) );
545 default : val += '\\'; break;
553 return std::move( String );
556 JSON parse_number( const string &str, size_t &offset, bool& rc ) {
560 bool isDouble = false;
564 if( (c == '-') || (c >= '0' && c <= '9') )
566 else if( c == '.' ) {
573 if( c == 'E' || c == 'e' ) {
575 if( c == '-' ){ ++offset; exp_str += '-';}
578 if( c >= '0' && c <= '9' )
580 else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
581 //std::cerr << "ERROR: Number: Expected a number for exponent, found '" << c << "'\n";
583 return std::move( JSON::Make( JSON::Class::Null ) );
588 exp = std::stol( exp_str );
590 else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
591 //std::cerr << "ERROR: Number: unexpected character '" << c << "'\n";
593 return std::move( JSON::Make( JSON::Class::Null ) );
598 Number = std::stod( val ) * std::pow( 10, exp );
600 if( !exp_str.empty() )
601 Number = std::stol( val ) * std::pow( 10, exp );
603 Number = std::stol( val );
605 return std::move( Number );
608 JSON parse_bool( const string &str, size_t &offset, bool& rc ) {
610 if( str.substr( offset, 4 ) == "true" )
612 else if( str.substr( offset, 5 ) == "false" )
615 //std::cerr << "ERROR: Bool: Expected 'true' or 'false', found '" << str.substr( offset, 5 ) << "'\n";
617 return std::move( JSON::Make( JSON::Class::Null ) );
619 offset += (m_Bool.ToBool() ? 4 : 5);
620 return std::move( m_Bool );
623 JSON parse_null( const string &str, size_t &offset, bool& rc ) {
625 if( str.substr( offset, 4 ) != "null" ) {
626 //std::cerr << "ERROR: Null: Expected 'null', found '" << str.substr( offset, 4 ) << "'\n";
628 return std::move( JSON::Make( JSON::Class::Null ) );
631 return std::move( Null );
634 JSON parse_next( const string &str, size_t &offset, bool& rc ) {
636 consume_ws( str, offset );
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 ) );
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 ) );
648 //std::cerr << "ERROR: Parse: Unknown starting character '" << value << "'\n";
654 inline JSON JSON::Load( const string &str, bool& rc ) {
657 return std::move( parse_next( str, offset, rc ) );
660 inline JSON JSON::Load( const string &str ) {
663 return std::move( parse_next( str, offset, rc ) );
666 } // End Namespace json