diff --git a/include/boost/json/impl/value.ipp b/include/boost/json/impl/value.ipp index c11115cd..c46c73a8 100644 --- a/include/boost/json/impl/value.ipp +++ b/include/boost/json/impl/value.ipp @@ -18,18 +18,169 @@ namespace boost { namespace json { -//------------------------------------------------------------------------------ -// -// Special members -// -//------------------------------------------------------------------------------ - value:: ~value() { destroy(); } +value:: +value() noexcept + : value( + json::kind::null, + default_storage()) +{ +} + +value:: +value(storage_ptr sp) noexcept + : value( + json::kind::null, + std::move(sp)) +{ +} + +value:: +value(json::kind k) noexcept + : value( + k, + default_storage()) +{ +} + +value:: +value( + json::kind k, + storage_ptr sp) noexcept +{ + switch(k) + { + case json::kind::object: + ::new(&obj_) object( + std::move(sp)); + break; + + case json::kind::array: + ::new(&arr_) array( + std::move(sp)); + break; + + case json::kind::string: + ::new(&str_) string( + string::allocator_type( + std::move(sp))); + break; + + case json::kind::number: + ::new(&nat_.num_) number; + ::new(&nat_.sp_) + storage_ptr(std::move(sp)); + break; + + case json::kind::boolean: + case json::kind::null: + ::new(&nat_.sp_) + storage_ptr(std::move(sp)); + break; + } + kind_ = k; +} + +value:: +value(value const& other) + : value( + other, + other.get_storage()) +{ +} + +value:: +value( + value const& other, + storage_ptr sp) +{ + switch(other.kind_) + { + case json::kind::object: + ::new(&obj_) object( + other.obj_, std::move(sp)); + break; + + case json::kind::array: + ::new(&arr_) array( + other.arr_, std::move(sp)); + break; + + case json::kind::string: + // workaround for some stdlibs + construct_string( + other.str_, + std::move(sp)); + break; + + case json::kind::number: + ::new(&nat_.num_) number( + other.nat_.num_); + ::new(&nat_.sp_) storage_ptr( + std::move(sp)); + break; + + case json::kind::boolean: + nat_.bool_ = other.nat_.bool_; + ::new(&nat_.sp_) storage_ptr( + std::move(sp)); + break; + + case json::kind::null: + ::new(&nat_.sp_) storage_ptr( + std::move(sp)); + break; + } + kind_ = other.kind_; +} + +value:: +value(pilfered p) noexcept +{ + auto& other = p.get(); + switch(other.kind_) + { + case json::kind::object: + relocate(&obj_, other.obj_); + ::new(&other.nat_.sp_) storage_ptr; + break; + + case json::kind::array: + relocate(&arr_, other.arr_); + ::new(&other.nat_.sp_) storage_ptr; + break; + + case json::kind::string: + relocate(&str_, other.str_); + ::new(&other.nat_.sp_) storage_ptr; + break; + + case json::kind::number: + relocate(&nat_.num_, other.nat_.num_); + ::new(&nat_.sp_) storage_ptr( + std::move(other.nat_.sp_)); + break; + + case json::kind::boolean: + nat_.bool_ = other.nat_.bool_; + ::new(&nat_.sp_) storage_ptr( + std::move(other.nat_.sp_)); + break; + + case json::kind::null: + ::new(&nat_.sp_) storage_ptr( + std::move(other.nat_.sp_)); + break; + } + kind_ = other.kind_; + other.kind_ = json::kind::null; +} + value:: value(value&& other) noexcept { @@ -94,109 +245,15 @@ value( break; case json::kind::string: - ::new(&str_) string( + // workaround for some stdlibs + construct_string( std::move(other.str_), - string::allocator_type( - std::move(sp))); - break; - - case json::kind::number: - relocate(&nat_.num_, other.nat_.num_); - ::new(&nat_.sp_) storage_ptr( std::move(sp)); break; - case json::kind::boolean: - nat_.bool_ = other.nat_.bool_; - ::new(&nat_.sp_) storage_ptr( - std::move(sp)); - break; - - case json::kind::null: - ::new(&nat_.sp_) storage_ptr( - std::move(sp)); - break; - } - kind_ = other.kind_; -} - -value:: -value(pilfered p) noexcept -{ - auto& other = p.get(); - switch(other.kind_) - { - case json::kind::object: - relocate(&obj_, other.obj_); - ::new(&other.nat_.sp_) storage_ptr; - break; - - case json::kind::array: - relocate(&arr_, other.arr_); - ::new(&other.nat_.sp_) storage_ptr; - break; - - case json::kind::string: - relocate(&str_, other.str_); - ::new(&other.nat_.sp_) storage_ptr; - break; - case json::kind::number: - relocate(&nat_.num_, other.nat_.num_); - ::new(&nat_.sp_) storage_ptr( - std::move(other.nat_.sp_)); - break; - - case json::kind::boolean: - nat_.bool_ = other.nat_.bool_; - ::new(&nat_.sp_) storage_ptr( - std::move(other.nat_.sp_)); - break; - - case json::kind::null: - ::new(&nat_.sp_) storage_ptr( - std::move(other.nat_.sp_)); - break; - } - kind_ = other.kind_; - other.kind_ = json::kind::null; -} - -value:: -value(value const& other) - : value( - other, - other.get_storage()) -{ -} - -value:: -value( - value const& other, - storage_ptr sp) -{ - switch(other.kind_) - { - case json::kind::object: - ::new(&obj_) object( - other.obj_, std::move(sp)); - break; - - case json::kind::array: - ::new(&arr_) array( - other.arr_, std::move(sp)); - break; - - case json::kind::string: - ::new(&str_) string( - other.str_, - string::allocator_type( - std::move(sp))); - break; - - case json::kind::number: - ::new(&nat_.num_) number( - other.nat_.num_); + relocate( + &nat_.num_, other.nat_.num_); ::new(&nat_.sp_) storage_ptr( std::move(sp)); break; @@ -220,7 +277,7 @@ value:: operator=(value&& other) { undo u(this); - move( + ::new(this) value( std::move(other), u.old.get_storage()); u.commit = true; @@ -235,50 +292,18 @@ operator=(value const& other) return *this; undo u(this); - ::new(this) value( - other, u.old.get_storage()); + ::new(this) value(other, + u.old.get_storage()); u.commit = true; return *this; } //------------------------------------------------------------------------------ // -// Construction and Assignment +// Conversion // //------------------------------------------------------------------------------ -value:: -value() noexcept - : value( - json::kind::null, - default_storage()) -{ -} - -value:: -value(storage_ptr sp) noexcept - : value( - json::kind::null, - std::move(sp)) -{ -} - -value:: -value(json::kind k) noexcept - : value( - k, - default_storage()) -{ -} - -value:: -value( - json::kind k, - storage_ptr sp) noexcept -{ - construct(k, std::move(sp)); -} - value:: value(object obj) noexcept : obj_(std::move(obj)) @@ -308,7 +333,9 @@ value:: value( array arr, storage_ptr sp) - : arr_(std::move(arr), std::move(sp)) + : arr_( + std::move(arr), + std::move(sp)) , kind_(json::kind::array) { } @@ -324,9 +351,11 @@ value:: value( string str, storage_ptr sp) - : str_(move_string(str, sp)) - , kind_(json::kind::string) { + // workaround for some stdlibs + construct_string( + std::move(str), + std::move(sp)); } value:: @@ -362,15 +391,15 @@ value( { if(maybe_object(init)) { - kind_ = json::kind::object; ::new(&obj_) object( init, std::move(sp)); + kind_ = json::kind::object; } else { - kind_ = json::kind::array; ::new(&arr_) array( init, std::move(sp)); + kind_ = json::kind::array; } } @@ -378,12 +407,11 @@ value& value:: operator=(object obj) { - object tmp( + undo u(this); + ::new(this) value( std::move(obj), - destroy()); - ::new(&obj_) object( - std::move(tmp)); - kind_ = json::kind::object; + u.old.get_storage()); + u.commit = true; return *this; } @@ -391,61 +419,23 @@ value& value:: operator=(array arr) { - array tmp( + undo u(this); + ::new(this) value( std::move(arr), - destroy()); - ::new(&arr_) array( - std::move(tmp)); - kind_ = json::kind::array; + u.old.get_storage()); + u.commit = true; return *this; } -struct value::op_assign_string -{ - value& this_; - - template - typename std::enable_if< - ! std::is_constructible::value>::type - operator()(S& str) - { - // workaround for missing std::string - // ctors in some stdlib versions - auto tmp = S(typename - string::allocator_type( - this_.get_storage())); - tmp = std::move(str); - this_.destroy(); - ::new(&this_.str_) string( - std::move(tmp)); - this_.kind_ = json::kind::string; - } - - template - typename std::enable_if< - std::is_constructible::value>::type - operator()(S& str) - { - auto tmp = S( - std::move(str), typename - string::allocator_type( - this_.get_storage())); - this_.destroy(); - ::new(&this_.str_) string( - std::move(tmp)); - this_.kind_ = json::kind::string; - } -}; - value& value:: operator=(string str) { - op_assign_string{*this}(str); + undo u(this); + ::new(this) value( + std::move(str), + u.old.get_storage()); + u.commit = true; return *this; } @@ -461,29 +451,31 @@ reset(json::kind k) noexcept { if(kind_ != k) { - construct(k, destroy()); + undo u(this); + ::new(this) value( + k, u.old.get_storage()); + u.commit = true; + return; } - else + + switch(kind_) { - switch(kind_) - { - case json::kind::object: - obj_.clear(); - break; + case json::kind::object: + obj_.clear(); + break; - case json::kind::array: - arr_.clear(); - break; + case json::kind::array: + arr_.clear(); + break; - case json::kind::string: - str_.clear(); - break; + case json::kind::string: + str_.clear(); + break; - case json::kind::number: - case json::kind::boolean: - case json::kind::null: - break; - } + case json::kind::number: + case json::kind::boolean: + case json::kind::null: + break; } } @@ -940,36 +932,6 @@ pop_back() // private -template -typename std::enable_if< - ! std::is_constructible::value, string>::type -value:: -move_string(S& str, storage_ptr& sp) -{ - // workaround for missing std::string - // ctors in some stdlib versions - auto s = string(typename - string::allocator_type( - std::move(sp))); - s = std::move(str); - return s; -} - -template -typename std::enable_if< - std::is_constructible::value, string>::type -value:: -move_string(S& str, storage_ptr& sp) -{ - return {std::move(str), typename - string::allocator_type( - std::move(sp))}; -} - storage_ptr value:: destroy() noexcept @@ -1005,220 +967,44 @@ destroy() noexcept return sp; } -void +template +auto value:: -construct( - json::kind k, - storage_ptr sp) noexcept +construct_string( + S&& str, storage_ptr sp) -> + typename std::enable_if< + ! std::is_constructible::value>::type + { - switch(k) - { - case json::kind::object: - // requires: noexcept construction - ::new(&obj_) object(std::move(sp)); - break; - - case json::kind::array: - // requires: noexcept construction - ::new(&arr_) array(std::move(sp)); - break; - - case json::kind::string: - // requires: noexcept construction - ::new(&str_) string( - string::allocator_type( - std::move(sp))); - break; - - case json::kind::number: - ::new(&nat_.num_) number{}; - ::new(&nat_.sp_) - storage_ptr(std::move(sp)); - break; - - case json::kind::boolean: - case json::kind::null: - ::new(&nat_.sp_) - storage_ptr(std::move(sp)); - break; - } - kind_ = k; + // workaround for missing std::string + // ctors in some stdlib versions + auto s = string(typename + string::allocator_type( + std::move(sp))); + s = std::move(str); + ::new(&str_) string( + std::move(s)); + kind_ = json::kind::string; } -struct value::op_move_string -{ - value& this_; - storage_ptr& sp_; - - template - typename std::enable_if< - ! std::is_constructible::value>::type - operator()(S& str) - { - // workaround for missing std::string - // ctors in some stdlib versions - auto tmp = S(typename - string::allocator_type(sp_)); - tmp = std::move(str); - ::new(&this_.str_) string(std::move(tmp)); - } - - template - typename std::enable_if< - std::is_constructible::value>::type - operator()(S& str) - { - ::new(&this_.str_) string( - std::move(str), typename - string::allocator_type(sp_)); - } -}; - -// unchecked -void +template +auto value:: -move( - value&& other, storage_ptr sp) +construct_string( + S&& str, storage_ptr sp) -> + typename std::enable_if< + std::is_constructible::value>::type { - switch(other.kind_) - { - case json::kind::object: - #ifndef BOOST_NO_EXCEPTIONS - try - { - #endif - ::new(&obj_) object( - std::move(other.obj_), sp); - #ifndef BOOST_NO_EXCEPTIONS - } - catch(...) - { - kind_ = json::kind::null; - ::new(&nat_.sp_) - storage_ptr(std::move(sp)); - throw; - } - #endif - kind_ = other.kind_; - sp = other.obj_.release_storage(); - other.obj_.~object(); - ::new(&other.nat_.sp_) - storage_ptr(std::move(sp)); - other.kind_ = json::kind::null; - break; - - case json::kind::array: - #ifndef BOOST_NO_EXCEPTIONS - try - { - #endif - ::new(&arr_) array( - std::move(other.arr_), sp); - #ifndef BOOST_NO_EXCEPTIONS - } - catch(...) - { - kind_ = json::kind::null; - ::new(&nat_.sp_) - storage_ptr(std::move(sp)); - throw; - } - #endif - kind_ = other.kind_; - sp = other.arr_.release_storage(); - other.arr_.~array(); - ::new(&other.nat_.sp_) - storage_ptr(std::move(sp)); - other.kind_ = json::kind::null; - break; - - case json::kind::string: - #ifndef BOOST_NO_EXCEPTIONS - try - #endif - { - op_move_string{*this, sp}(other.str_); - } - #ifndef BOOST_NO_EXCEPTIONS - catch(...) - { - kind_ = json::kind::null; - ::new(&nat_.sp_) - storage_ptr(std::move(sp)); - throw; - } - #endif - kind_ = other.kind_; - sp = other.str_.get_allocator().get_storage(); - other.str_.~string(); - ::new(&other.nat_.sp_) - storage_ptr(std::move(sp)); - other.kind_ = json::kind::null; - break; - - case json::kind::number: - ::new(&nat_.sp_) - storage_ptr(std::move(sp)); - ::new(&nat_.num_) number( - std::move(other.nat_.num_)); - kind_ = other.kind_; - other.nat_.num_.~number(); - other.kind_ = json::kind::null; - break; - - case json::kind::boolean: - ::new(&nat_.sp_) - storage_ptr(std::move(sp)); - nat_.bool_ = other.nat_.bool_; - kind_ = other.kind_; - other.kind_ = json::kind::null; - break; - - case json::kind::null: - ::new(&nat_.sp_) - storage_ptr(std::move(sp)); - kind_ = other.kind_; - other.kind_ = json::kind::null; - break; - } + ::new(&str_) string(std::move(str), + typename string::allocator_type( + std::move(sp))); + kind_ = json::kind::string; } -struct value::op_copy_string -{ - value& this_; - storage_ptr& sp_; - - template - typename std::enable_if< - ! std::is_constructible::value>::type - operator()(S const& str) - { - // workaround for missing std::string - // ctors in some stdlib versions - auto tmp = string(typename - string::allocator_type(sp_)); - tmp = str; - ::new(&this_.str_) string(std::move(tmp)); - } - - template - typename std::enable_if< - std::is_constructible::value>::type - operator()(S const& str) - { - ::new(&this_.str_) string(str, - typename string::allocator_type(sp_)); - } -}; - //------------------------------------------------------------------------------ // friends diff --git a/include/boost/json/value.hpp b/include/boost/json/value.hpp index d18c01cb..a432198f 100644 --- a/include/boost/json/value.hpp +++ b/include/boost/json/value.hpp @@ -121,54 +121,10 @@ class value json::kind kind_; public: - //-------------------------------------------------------------------------- - // - // Special members - // - //-------------------------------------------------------------------------- - /// Destroy a value and all of its contents BOOST_JSON_DECL ~value(); - /// Move constructor - BOOST_JSON_DECL - value(value&& other) noexcept; - - /// Storage-extended move constructor - BOOST_JSON_DECL - value( - value&& other, - storage_ptr sp); - - /// Pilfer constructor - BOOST_JSON_DECL - value(pilfered other) noexcept; - - /// Construct a copy of a value - BOOST_JSON_DECL - value(value const& other); - - /// Construct a copy of a value using the specified storage - BOOST_JSON_DECL - value( - value const& other, - storage_ptr sp); - - /// Move-assign a value - BOOST_JSON_DECL - value& operator=(value&& other); - - /// Assign a copy of a value - BOOST_JSON_DECL - value& operator=(value const& other); - - //-------------------------------------------------------------------------- - // - // Construction and Assignment - // - //-------------------------------------------------------------------------- - /** Construct a null value using the default storage. */ BOOST_JSON_DECL @@ -206,70 +162,110 @@ public: json::kind k, storage_ptr sp) noexcept; - /** Construct a value from an object. + /// Copy constructor + BOOST_JSON_DECL + value(value const& other); + + /// Storage-extended copy constructor + BOOST_JSON_DECL + value( + value const& other, + storage_ptr sp); + + /// Pilfer constructor + BOOST_JSON_DECL + value(pilfered other) noexcept; + + /// Move constructor + BOOST_JSON_DECL + value(value&& other) noexcept; + + /// Storage-extended move constructor + BOOST_JSON_DECL + value( + value&& other, + storage_ptr sp); + + /// Move assignment + BOOST_JSON_DECL + value& operator=(value&& other); + + /// Copy assignment + BOOST_JSON_DECL + value& operator=(value const& other); + + //-------------------------------------------------------------------------- + // + // Conversion + // + //-------------------------------------------------------------------------- + + /** Construct an object */ BOOST_JSON_DECL value(object obj) noexcept; - /** Construct a value from an object using the specified storage + /** Construct an object */ BOOST_JSON_DECL value(object obj, storage_ptr sp); - /** Construct a value from an array. + /** Construct an array */ BOOST_JSON_DECL value(array arr) noexcept; - /** Construct a value from an array using the specified storage + /** Construct an array */ BOOST_JSON_DECL value(array arr, storage_ptr sp); - /** Construct a value from a string. + /** Construct a string */ BOOST_JSON_DECL value(string str) noexcept; - /** Construct a value from a string using the specified storage + /** Construct a string */ BOOST_JSON_DECL value(string str, storage_ptr sp); - /** Construct a value from a number + /** Construct a number */ BOOST_JSON_DECL value(number num); - /** Construct a value from a number using the specified storage + /** Construct a number */ BOOST_JSON_DECL value(number num, storage_ptr sp); - /** Construct an array from an initializer list. + /** Construct an object or array */ BOOST_JSON_DECL - value(std::initializer_list init); + value( + std::initializer_list init); - /** Construct an array from an initializer list using the specified storage. + /** Construct an object or array */ BOOST_JSON_DECL - value(std::initializer_list init, + value( + std::initializer_list init, storage_ptr sp); - /** Assign a value from an object + /** Assign an object */ BOOST_JSON_DECL value& operator=(object obj); - /** Assign a value from an array + /** Assign an array */ BOOST_JSON_DECL value& operator=(array arr); - /** Assign a value from a string + /** Assign a string */ BOOST_JSON_DECL value& @@ -381,7 +377,7 @@ public: // //-------------------------------------------------------------------------- - /// Construct a value from another type + /// Construct from another type template< class T #ifndef GENERATING_DOCUMENTATION @@ -394,7 +390,7 @@ public: { } - /// Construct a value from another type using the specified storage + /// Construct from another type using the specified storage template< class T #ifndef GENERATING_DOCUMENTATION @@ -893,26 +889,6 @@ public: //-------------------------------------------------------------------------- private: - struct op_assign_string; - struct op_move_string; - struct op_copy_string; - - template - static - typename std::enable_if< - ! std::is_constructible::value, string>::type - move_string(S& str, storage_ptr& store); - - template - static - typename std::enable_if< - std::is_constructible::value, string>::type - move_string(S& str, storage_ptr& store); - BOOST_JSON_DECL storage_ptr destroy() noexcept; @@ -922,9 +898,23 @@ private: construct( json::kind, storage_ptr) noexcept; - BOOST_JSON_DECL - void - move(value&&, storage_ptr); + template + auto + construct_string( + S&& str, storage_ptr store) -> + typename std::enable_if< + ! std::is_constructible::value>::type; + + template + auto + construct_string( + S&& str, storage_ptr store) -> + typename std::enable_if< + std::is_constructible::value>::type; BOOST_JSON_DECL friend