#ifndef JSON_H #define JSON_H #include #include #include #include #include #include #include #include #include #include #include std::string json_escape( const std::string &str ); #ifdef Bool #undef Bool #endif class JSON { union BackingData { BackingData( double d ) : Float( d ){} BackingData( long l ) : Int( l ){} BackingData( bool b ) : Bool( b ){} BackingData( std::string s ) : String( new std::string( s ) ){} BackingData() : Int( 0 ){} std::deque *List; std::map *Map; std::string *String; double Float; long Int; bool Bool; } Internal; public: enum class Class { Null, Object, Array, String, Floating, Integral, Boolean }; template class JSONWrapper { Container *object; public: JSONWrapper( Container *val ) : object( val ) {} JSONWrapper( std::nullptr_t ) : object( nullptr ) {} typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); } typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); } typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); } typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); } }; template class JSONConstWrapper { const Container *object; public: JSONConstWrapper( const Container *val ) : object( val ) {} JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {} typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); } typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); } }; JSON(); JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){} JSON( std::initializer_list list ); JSON( JSON&& other ); JSON( const JSON &other ); JSON& operator=( const JSON &other ); JSON& operator=( JSON&& other ); // Template T constructors template JSON( T b, typename std::enable_if::value>::type* = 0 ); template JSON( T i, typename std::enable_if::value && !std::is_same::value>::type* = 0 ); template JSON( T f, typename std::enable_if::value>::type* = 0 ); template JSON( T s, typename std::enable_if::value>::type* = 0 ); ~JSON() { switch( Type ) { case Class::Array: delete Internal.List; break; case Class::Object: delete Internal.Map; break; case Class::String: delete Internal.String; break; default:; } } static JSON Make( Class type ); static JSON Load( const std::string &, std::function ); // Appending things. template void append( T arg ) { SetType( Class::Array ); Internal.List->emplace_back( arg ); } template void append( T arg, U... args ) { append( arg ); append( args... ); } // Assignments (template T). template typename std::enable_if::value, JSON&>::type operator=( T b ) { SetType( Class::Boolean ); Internal.Bool = b; return *this; } template typename std::enable_if::value && !std::is_same::value, JSON&>::type operator=( T i ) { SetType( Class::Integral ); Internal.Int = i; return *this; } template typename std::enable_if::value, JSON&>::type operator=( T f ) { SetType( Class::Floating ); Internal.Float = f; return *this; } template typename std::enable_if::value, JSON&>::type operator=( T s ) { SetType( Class::String ); *Internal.String = std::string( s ); return *this; } // Indexing. JSON& operator[]( const std::string &key ); JSON& operator[]( unsigned index ); JSON &at( const std::string &key ); const JSON &at( const std::string &key ) const; JSON &at( unsigned index ); const JSON &at( unsigned index ) const; int length() const; int size() const; bool hasKey( const std::string &key ) const; Class JSONType() const; /// Functions for getting primitives from the JSON object. bool IsNull() const; std::string toString() const; std::string toString( bool &ok ) const; double toFloat() const; double toFloat( bool &ok ) const; long toInt() const; long toInt( bool &ok ) const; bool toBool() const; bool toBool( bool &ok ) const; JSONWrapper> ObjectRange(); JSONWrapper> ArrayRange(); JSONConstWrapper> ObjectRange() const; JSONConstWrapper> ArrayRange() const; std::string dump( int depth = 1, const std::string &tab = std::string(" ")) const; friend std::ostream& operator<<( std::ostream&, const JSON & ); private: void SetType( Class type ); private: /* beware: only call if YOU know that Internal is allocated. No checks performed here. This function should be called in a constructed JSON just before you are going to overwrite Internal... */ void ClearInternal(); private: Class Type = Class::Null; }; JSON Array(); template JSON Array( T... args ) { JSON arr = JSON::Make( JSON::Class::Array ); arr.append( args... ); return std::move( arr ); } JSON Object(); std::ostream& operator<<( std::ostream &os, const JSON &json ); #endif // JSON_H