From dc8aa372c10c784ec133e1a42014bc91a0d3afa0 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 16 Mar 2016 19:39:10 -0600 Subject: [PATCH] Less manual managing of JSON internal state --- include/chaiscript/utility/json.hpp | 188 ++++++++++++++++------------ 1 file changed, 109 insertions(+), 79 deletions(-) diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index 1cbaa6c..502209e 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -35,6 +35,18 @@ using std::is_floating_point; class JSON { + public: + enum class Class { + Null, + Object, + Array, + String, + Floating, + Integral, + Boolean + }; + + private: struct Internal { template auto clone(const std::unique_ptr &ptr) { @@ -45,11 +57,15 @@ class JSON } } - Internal( double d ) : Float( d ){} - Internal( long l ) : Int( l ){} - Internal( bool b ) : Bool( b ){} - Internal( std::string s ) : String(std::make_unique(std::move(s))) {} - Internal() : Int( 0 ){} + Internal( double d ) : Float( d ), Type(Class::Floating) {} + Internal( long l ) : Int( l ), Type(Class::Integral) {} + Internal( bool b ) : Bool( b ), Type(Class::Boolean) {} + Internal( std::string s ) : String(std::make_unique(std::move(s))), Type(Class::String) {} + Internal() : Type(Class::Null) {} + + Internal(Class t_type) { + set_type(t_type); + } Internal(const Internal &other) : List(clone(other.List)), @@ -57,7 +73,8 @@ class JSON String(clone(other.String)), Float(other.Float), Int(other.Int), - Bool(other.Bool) + Bool(other.Bool), + Type(other.Type) { } @@ -69,32 +86,48 @@ class JSON Float = other.Float; Int = other.Int; Bool = other.Bool; + Type = other.Type; return *this; } + void set_type( Class type ) { + if( type == Type ) { + return; + } + + Map.reset(); + List.reset(); + String.reset(); + + switch( type ) { + case Class::Object: Map = std::make_unique>(); break; + case Class::Array: List = std::make_unique>(); break; + case Class::String: String = std::make_unique(); break; + case Class::Floating: Float = 0.0; break; + case Class::Integral: Int = 0; break; + case Class::Boolean: Bool = false; break; + case Class::Null: break; + } + + Type = type; + } + Internal(Internal &&) = default; Internal &operator=(Internal &&) = default; std::unique_ptr> List; std::unique_ptr> Map; std::unique_ptr String; - double Float; - long Int; - bool Bool; + double Float = 0; + long Int = 0; + bool Bool = false; + + Class Type = Class::Null; }; Internal internal; public: - enum class Class { - Null, - Object, - Array, - String, - Floating, - Integral, - Boolean - }; template class JSONWrapper { @@ -126,30 +159,29 @@ class JSON JSON( std::nullptr_t ) {} explicit JSON(Class type) - : internal(), Type(Class::Null) + : internal(type) { - set_type( type ); } JSON( initializer_list list ) - : internal(), Type(Class::Null) + : internal(Class::Object) { - set_type( Class::Object ); - for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) + for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) { operator[]( i->to_string() ) = *std::next( i ); + } } template - JSON( T b, typename enable_if::value>::type* = nullptr ) : internal( b ), Type( Class::Boolean ){} + JSON( T b, typename enable_if::value>::type* = nullptr ) : internal( static_cast(b) ) {} template - JSON( T i, typename enable_if::value && !is_same::value>::type* = nullptr ) : internal( long(i) ), Type( Class::Integral ){} + JSON( T i, typename enable_if::value && !is_same::value>::type* = nullptr ) : internal( static_cast(i) ) {} template - JSON( T f, typename enable_if::value>::type* = nullptr ) : internal( double(f) ), Type( Class::Floating ){} + JSON( T f, typename enable_if::value>::type* = nullptr ) : internal( static_cast(f) ) {} template - JSON( T s, typename enable_if::value>::type* = nullptr ) : internal( std::string( s ) ), Type( Class::String ){} + JSON( T s, typename enable_if::value>::type* = nullptr ) : internal( static_cast(s) ) {} @@ -157,42 +189,53 @@ class JSON template void append( T arg ) { - set_type( Class::Array ); internal.List->emplace_back( arg ); + internal.set_type( Class::Array ); + internal.List->emplace_back( arg ); } template void append( T arg, U... args ) { - append( arg ); append( args... ); + append( arg ); + append( args... ); } template typename enable_if::value, JSON&>::type operator=( T b ) { - set_type( Class::Boolean ); internal.Bool = b; return *this; + internal = Internal(static_cast(b)); + return *this; } template typename enable_if::value && !is_same::value, JSON&>::type operator=( T i ) { - set_type( Class::Integral ); internal.Int = i; return *this; + internal = Internal(static_cast(i)); + return *this; } template typename enable_if::value, JSON&>::type operator=( T f ) { - set_type( Class::Floating ); internal.Float = f; return *this; + internal = Internal(static_cast(f)); + return *this; } template typename enable_if::value, JSON&>::type operator=( T s ) { - set_type( Class::String ); *internal.String = std::string( s ); return *this; + internal = Internal(static_cast(s)); + return *this; } JSON& operator[]( const std::string &key ) { - set_type( Class::Object ); return internal.Map->operator[]( key ); + internal.set_type( Class::Object ); + return internal.Map->operator[]( key ); } JSON& operator[]( const size_t index ) { - set_type( Class::Array ); - if( index >= internal.List->size() ) internal.List->resize( index + 1 ); + internal.set_type( Class::Array ); + if( index >= internal.List->size() ) { + internal.List->resize( index + 1 ); + } + return internal.List->operator[]( index ); + } JSON &at( const std::string &key ) { @@ -211,16 +254,16 @@ class JSON return internal.List->at( index ); } - int length() const { - if( Type == Class::Array ) { - return static_cast(internal.List->size()); + long length() const { + if( internal.Type == Class::Array ) { + return static_cast(internal.List->size()); } else { return -1; } } - bool hasKey( const std::string &key ) const { - if( Type == Class::Object ) { + bool has_key( const std::string &key ) const { + if( internal.Type == Class::Object ) { return internal.Map->find( key ) != internal.Map->end(); } @@ -228,76 +271,84 @@ class JSON } int size() const { - if( Type == Class::Object ) { + if( internal.Type == Class::Object ) { return static_cast(internal.Map->size()); - } else if( Type == Class::Array ) { + } else if( internal.Type == Class::Array ) { return static_cast(internal.List->size()); } else { return -1; } } - Class JSONType() const { return Type; } + Class JSONType() const { return internal.Type; } /// Functions for getting primitives from the JSON object. - bool is_null() const { return Type == Class::Null; } + bool is_null() const { return internal.Type == Class::Null; } std::string to_string() const { bool b; return to_string( b ); } std::string to_string( bool &ok ) const { - ok = (Type == Class::String); + ok = (internal.Type == Class::String); return ok ? *internal.String : std::string(""); } double to_float() const { bool b; return to_float( b ); } double to_float( bool &ok ) const { - ok = (Type == Class::Floating); + ok = (internal.Type == Class::Floating); return ok ? internal.Float : 0.0; } long to_int() const { bool b; return to_int( b ); } long to_int( bool &ok ) const { - ok = (Type == Class::Integral); + ok = (internal.Type == Class::Integral); return ok ? internal.Int : 0; } bool to_bool() const { bool b; return to_bool( b ); } bool to_bool( bool &ok ) const { - ok = (Type == Class::Boolean); + ok = (internal.Type == Class::Boolean); return ok ? internal.Bool : false; } JSONWrapper> object_range() { - if( Type == Class::Object ) + if( internal.Type == Class::Object ) { return JSONWrapper>( internal.Map.get() ); - return JSONWrapper>( nullptr ); + } else { + return JSONWrapper>( nullptr ); + } } JSONWrapper> array_range() { - if( Type == Class::Array ) + if( internal.Type == Class::Array ) { return JSONWrapper>( internal.List.get() ); - return JSONWrapper>( nullptr ); + } else { + return JSONWrapper>( nullptr ); + } } JSONConstWrapper> object_range() const { - if( Type == Class::Object ) + if( internal.Type == Class::Object ) { return JSONConstWrapper>( internal.Map.get() ); + } else { return JSONConstWrapper>( nullptr ); + } } JSONConstWrapper> array_range() const { - if( Type == Class::Array ) + if( internal.Type == Class::Array ) { return JSONConstWrapper>( internal.List.get() ); + } else { return JSONConstWrapper>( nullptr ); + } } - std::string dump( int depth = 1, std::string tab = " ") const { - switch( Type ) { + std::string dump( long depth = 1, std::string tab = " ") const { + switch( internal.Type ) { case Class::Null: return "null"; case Class::Object: { std::string pad = ""; - for( int i = 0; i < depth; ++i, pad += tab ); + for( long i = 0; i < depth; ++i, pad += tab ); std::string s = "{\n"; bool skip = true; @@ -351,29 +402,8 @@ class JSON return output; } - void set_type( Class type ) { - if( type == Type ) - return; - - internal.Map.reset(); - internal.List.reset(); - internal.String.reset(); - - switch( type ) { - case Class::Object: internal.Map = std::make_unique>(); break; - case Class::Array: internal.List = std::make_unique>(); break; - case Class::String: internal.String = std::make_unique(); break; - case Class::Floating: internal.Float = 0.0; break; - case Class::Integral: internal.Int = 0; break; - case Class::Boolean: internal.Bool = false; break; - case Class::Null: break; - } - - Type = type; - } private: - Class Type = Class::Null; };