diff --git a/src/json.hpp b/src/json.hpp index a7be5c81..a07f10eb 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -299,6 +299,33 @@ struct external_constructor } }; +template <> +struct external_constructor +{ + template + static void construct(Json &j, const typename Json::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template ::value, + int> = 0> + static void construct(Json &j, const CompatibleObjectType &obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = + j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + // very useful construct against boilerplate (more boilerplate needed than in // C++17: http://en.cppreference.com/w/cpp/types/void_t) template struct make_void @@ -458,8 +485,7 @@ struct is_compatible_float_type template struct is_compatible_basic_json_type { - static auto constexpr value = - is_compatible_object_type::value; + static auto constexpr value = false; }; template @@ -611,6 +637,15 @@ void to_json(Json &j, CompatibleArrayType const &arr) external_constructor::construct(j, arr); } +template < + typename Json, typename CompatibleObjectType, + enable_if_t::value, + int> = 0> +void to_json(Json &j, CompatibleObjectType const &arr) +{ + external_constructor::construct(j, arr); +} + template void from_json(Json const& j, typename Json::boolean_t& b) { @@ -707,6 +742,24 @@ void from_json(Json const &j, CompatibleArrayType &arr) }); } + +template < + typename Json, typename CompatibleObjectType, + enable_if_t::value, + int> = 0> +void from_json(Json const &j, CompatibleObjectType &obj) +{ + if (!j.is_object()) + throw std::domain_error("type must be object, but is " + type_name(j)); + + auto inner_object = const_cast(j).template get_ptr(); + using std::begin; + using std::end; + // we could avoid the assignment, but this might require a for loop, which + // might be less efficient than the container constructor for some containers (would it?) + obj = CompatibleObjectType(begin(*inner_object), end(*inner_object)); +} + // overload for arithmetic types, not chosen for basic_json template arguments (BooleanType, etc..) // // note: Is it really necessary to provide explicit overloads for boolean_t etc.. @@ -1806,69 +1859,6 @@ class basic_json assert_invariant(); } - /*! - @brief create an object (explicit) - - Create an object JSON value with a given content. - - @param[in] val a value for the object - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for object value fails - - @liveexample{The following code shows the constructor with an @ref - object_t parameter.,basic_json__object_t} - - @sa @ref basic_json(const CompatibleObjectType&) -- create an object value - from a compatible STL container - - @since version 1.0.0 - */ - basic_json(const object_t& val) - : m_type(value_t::object), m_value(val) - { - assert_invariant(); - } - - /*! - @brief create an object (implicit) - - Create an object JSON value with a given content. This constructor allows - any type @a CompatibleObjectType that can be used to construct values of - type @ref object_t. - - @tparam CompatibleObjectType An object type whose `key_type` and - `value_type` is compatible to @ref object_t. Examples include `std::map`, - `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with - a `key_type` of `std::string`, and a `value_type` from which a @ref - basic_json value can be constructed. - - @param[in] val a value for the object - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for object value fails - - @liveexample{The following code shows the constructor with several - compatible object type parameters.,basic_json__CompatibleObjectType} - - @sa @ref basic_json(const object_t&) -- create an object value - - @since version 1.0.0 - */ - template ::value, - int> = 0> - basic_json(const CompatibleObjectType& val) : m_type(value_t::object) - { - using std::begin; - using std::end; - m_value.object = create(begin(val), end(val)); - assert_invariant(); - } - // constructor chosen when: // - JSONSerializer::to_json exists for type T // - T is not a istream, nor convertible to basic_json (float, vectors, etc) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index a5674238..32a6282e 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -299,6 +299,33 @@ struct external_constructor } }; +template <> +struct external_constructor +{ + template + static void construct(Json &j, const typename Json::object_t& obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template ::value, + int> = 0> + static void construct(Json &j, const CompatibleObjectType &obj) + { + using std::begin; + using std::end; + + j.m_type = value_t::object; + j.m_value.object = + j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } +}; + // very useful construct against boilerplate (more boilerplate needed than in // C++17: http://en.cppreference.com/w/cpp/types/void_t) template struct make_void @@ -458,8 +485,7 @@ struct is_compatible_float_type template struct is_compatible_basic_json_type { - static auto constexpr value = - is_compatible_object_type::value; + static auto constexpr value = false; }; template @@ -611,6 +637,15 @@ void to_json(Json &j, CompatibleArrayType const &arr) external_constructor::construct(j, arr); } +template < + typename Json, typename CompatibleObjectType, + enable_if_t::value, + int> = 0> +void to_json(Json &j, CompatibleObjectType const &arr) +{ + external_constructor::construct(j, arr); +} + template void from_json(Json const& j, typename Json::boolean_t& b) { @@ -707,6 +742,24 @@ void from_json(Json const &j, CompatibleArrayType &arr) }); } + +template < + typename Json, typename CompatibleObjectType, + enable_if_t::value, + int> = 0> +void from_json(Json const &j, CompatibleObjectType &obj) +{ + if (!j.is_object()) + throw std::domain_error("type must be object, but is " + type_name(j)); + + auto inner_object = const_cast(j).template get_ptr(); + using std::begin; + using std::end; + // we could avoid the assignment, but this might require a for loop, which + // might be less efficient than the container constructor for some containers (would it?) + obj = CompatibleObjectType(begin(*inner_object), end(*inner_object)); +} + // overload for arithmetic types, not chosen for basic_json template arguments (BooleanType, etc..) // // note: Is it really necessary to provide explicit overloads for boolean_t etc.. @@ -1807,69 +1860,6 @@ class basic_json assert_invariant(); } - /*! - @brief create an object (explicit) - - Create an object JSON value with a given content. - - @param[in] val a value for the object - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for object value fails - - @liveexample{The following code shows the constructor with an @ref - object_t parameter.,basic_json__object_t} - - @sa @ref basic_json(const CompatibleObjectType&) -- create an object value - from a compatible STL container - - @since version 1.0.0 - */ - basic_json(const object_t& val) - : m_type(value_t::object), m_value(val) - { - assert_invariant(); - } - - /*! - @brief create an object (implicit) - - Create an object JSON value with a given content. This constructor allows - any type @a CompatibleObjectType that can be used to construct values of - type @ref object_t. - - @tparam CompatibleObjectType An object type whose `key_type` and - `value_type` is compatible to @ref object_t. Examples include `std::map`, - `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with - a `key_type` of `std::string`, and a `value_type` from which a @ref - basic_json value can be constructed. - - @param[in] val a value for the object - - @complexity Linear in the size of the passed @a val. - - @throw std::bad_alloc if allocation for object value fails - - @liveexample{The following code shows the constructor with several - compatible object type parameters.,basic_json__CompatibleObjectType} - - @sa @ref basic_json(const object_t&) -- create an object value - - @since version 1.0.0 - */ - template ::value, - int> = 0> - basic_json(const CompatibleObjectType& val) : m_type(value_t::object) - { - using std::begin; - using std::end; - m_value.object = create(begin(val), end(val)); - assert_invariant(); - } - // constructor chosen when: // - JSONSerializer::to_json exists for type T // - T is not a istream, nor convertible to basic_json (float, vectors, etc)