diff --git a/src/json.hpp b/src/json.hpp index a07f10eb..c50212c1 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -834,6 +834,7 @@ struct DecimalSeparator : std::numpunct } }; +} // taken from ranges-v3 // TODO add doc @@ -2908,151 +2909,6 @@ class basic_json /// @} private: - ////////////////// - // value access // - ////////////////// - - template::value and - std::is_convertible::value, int>::type = 0> - T get_impl(T*) const - { - if (is_object()) - { - return T(m_value.object->begin(), m_value.object->end()); - } - else - { - - JSON_THROW(std::domain_error("type must be object, but is " + type_name())); - } - - /// get an object (explicit) - object_t get_impl(object_t* /*unused*/) const - { - if (is_object()) - { - return *(m_value.object); - } - - JSON_THROW(std::domain_error("type must be object, but is " + type_name())); - } - - /// get an array (explicit) - template < - class T, - typename std::enable_if < - std::is_convertible::value and - not std::is_same::value and - not std::is_arithmetic::value and - not std::is_convertible::value and - not detail::has_mapped_type::value, - int >::type = 0 > - T get_impl(T*) const - { - if (is_array()) - { - T to_vector; - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) - { - return i.get(); - }); - return to_vector; - } - - JSON_THROW(std::domain_error("type must be array, but is " + type_name())); - } - - /// get an array (explicit) - template::value and - not std::is_same::value, int>::type = 0> - std::vector get_impl(std::vector* /*unused*/) const - { - if (is_array()) - { - std::vector to_vector; - to_vector.reserve(m_value.array->size()); - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) - { - return i.get(); - }); - return to_vector; - } - - JSON_THROW(std::domain_error("type must be array, but is " + type_name())); - } - - /// get an array (explicit) - template::value and - not detail::has_mapped_type::value, int>::type = 0> - T get_impl(T* /*unused*/) const - { - if (is_array()) - { - return T(m_value.array->begin(), m_value.array->end()); - } - - JSON_THROW(std::domain_error("type must be array, but is " + type_name())); - } - - /// get an array (explicit) - array_t get_impl(array_t* /*unused*/) const - { - if (is_array()) - { - return *(m_value.array); - } - - JSON_THROW(std::domain_error("type must be array, but is " + type_name())); - } - - /// get a string (explicit) - template::value, int>::type = 0> - T get_impl(T* /*unused*/) const - { - if (is_string()) - { - return *m_value.string; - } - - JSON_THROW(std::domain_error("type must be string, but is " + type_name())); - } - - /// get a number (explicit) - template::value, int>::type = 0> - T get_impl(T* /*unused*/) const - { - switch (m_type) - { - case value_t::number_integer: - { - return static_cast(m_value.number_integer); - } - - case value_t::number_unsigned: - { - return static_cast(m_value.number_unsigned); - } - - case value_t::number_float: - { - return static_cast(m_value.number_float); - } - - default: - { - JSON_THROW(std::domain_error("type must be number, but is " + type_name())); - } - } - } - /// get a boolean (explicit) boolean_t get_impl(boolean_t* /*unused*/) const { @@ -3180,54 +3036,6 @@ class basic_json } public: - - /// @name value access - /// Direct access to the stored value of a JSON value. - /// @{ - - /*! - @brief get a value (explicit) - - Explicit type conversion between the JSON value and a compatible value. - - @tparam ValueType non-pointer type compatible to the JSON value, for - instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays - - @return copy of the JSON value, converted to type @a ValueType - - @throw std::domain_error in case passed type @a ValueType is incompatible - to JSON; example: `"type must be object, but is null"` - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,get__ValueType_const} - - @internal - The idea of using a casted null pointer to choose the correct - implementation is from . - @endinternal - - @sa @ref operator ValueType() const for implicit conversion - @sa @ref get() for pointer-member access - - @since version 1.0.0 - */ - template ::value and - detail::is_compatible_basic_json_type< - uncvref_t, basic_json_t>::value, - int> = 0> - auto get() const - -> decltype(this->get_impl(static_cast(nullptr))) { - return get_impl(static_cast(nullptr)); - } - // if T is basic_json, simply returns *this template ::value, int> = 0> @@ -3236,16 +3044,22 @@ class basic_json return *this; } + // This overload is chosen when: + // - T is not basic_json_t + // - JSONSerializer::from_json(basic_json const&, T&) exists + // - and JSONSerializer::from_json(basic_json const&) does not exist + // + // the latter is preferred if both are present (since it does not require a default construction of T) template < typename T, - enable_if_t, basic_json_t>>, + enable_if_t>::value and detail::has_from_json>>::value and - not std::is_same>::value, + uncvref_t>::value and + not detail::has_non_default_from_json< + JSONSerializer, basic_json_t, uncvref_t>::value, int> = 0> - // do we really want the uncvref ? if a user call get, shouldn't we static assert ? + // do we really want the uncvref ? if a user call get, shouldn't we + // static assert ? auto get() const -> uncvref_t { using type = uncvref_t; @@ -3258,19 +3072,22 @@ class basic_json return ret; } - // This overload is chosen for non-default constructible user-defined-types + // This overload is chosen when: + // - T is not basic_json_t + // - and JSONSerializer::from_json(basic_json const&) does not exist + // TODO add constexpr, noexcept(...) template < typename T, - enable_if_t, basic_json_t>>, - detail::has_non_default_from_json>>::value, - short> = 0 > - T get() const + enable_if_t>::value and + detail::has_non_default_from_json< + JSONSerializer, basic_json_t, uncvref_t>::value, + int> = 0> + uncvref_t get() const { - return JSONSerializer::from_json(*this); + return JSONSerializer::from_json(*this); } + // TODO what to do with those... /*! @brief get a pointer value (explicit) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 32a6282e..f83ca76b 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2909,148 +2909,6 @@ class basic_json /// @} private: - ////////////////// - // value access // - ////////////////// - - template::value and - std::is_convertible::value, int>::type = 0> - T get_impl(T* /*unused*/) const - { - if (is_object()) - { - return T(m_value.object->begin(), m_value.object->end()); - } - - JSON_THROW(std::domain_error("type must be object, but is " + type_name())); - } - - /// get an object (explicit) - object_t get_impl(object_t* /*unused*/) const - { - if (is_object()) - { - return *(m_value.object); - } - - JSON_THROW(std::domain_error("type must be object, but is " + type_name())); - } - - /// get an array (explicit) - template < - class T, - typename std::enable_if < - std::is_convertible::value and - not std::is_same::value and - not std::is_arithmetic::value and - not std::is_convertible::value and - not detail::has_mapped_type::value, - int >::type = 0 > - { - if (is_array()) - { - T to_vector; - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) - { - return i.get(); - }); - return to_vector; - } - - JSON_THROW(std::domain_error("type must be array, but is " + type_name())); - } - - /// get an array (explicit) - template::value and - not std::is_same::value, int>::type = 0> - std::vector get_impl(std::vector* /*unused*/) const - { - if (is_array()) - { - std::vector to_vector; - to_vector.reserve(m_value.array->size()); - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) - { - return i.get(); - }); - return to_vector; - } - - JSON_THROW(std::domain_error("type must be array, but is " + type_name())); - } - - /// get an array (explicit) - template::value and - not detail::has_mapped_type::value, int>::type = 0> - T get_impl(T* /*unused*/) const - { - if (is_array()) - { - return T(m_value.array->begin(), m_value.array->end()); - } - - JSON_THROW(std::domain_error("type must be array, but is " + type_name())); - } - - /// get an array (explicit) - array_t get_impl(array_t* /*unused*/) const - { - if (is_array()) - { - return *(m_value.array); - } - - JSON_THROW(std::domain_error("type must be array, but is " + type_name())); - } - - /// get a string (explicit) - template::value, int>::type = 0> - T get_impl(T* /*unused*/) const - { - if (is_string()) - { - return *m_value.string; - } - - JSON_THROW(std::domain_error("type must be string, but is " + type_name())); - } - - /// get a number (explicit) - template::value, int>::type = 0> - T get_impl(T* /*unused*/) const - { - switch (m_type) - { - case value_t::number_integer: - { - return static_cast(m_value.number_integer); - } - - case value_t::number_unsigned: - { - return static_cast(m_value.number_unsigned); - } - - case value_t::number_float: - { - return static_cast(m_value.number_float); - } - - default: - { - JSON_THROW(std::domain_error("type must be number, but is " + type_name())); - } - } - } - /// get a boolean (explicit) boolean_t get_impl(boolean_t* /*unused*/) const { @@ -3178,54 +3036,6 @@ class basic_json } public: - - /// @name value access - /// Direct access to the stored value of a JSON value. - /// @{ - - /*! - @brief get a value (explicit) - - Explicit type conversion between the JSON value and a compatible value. - - @tparam ValueType non-pointer type compatible to the JSON value, for - instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays - - @return copy of the JSON value, converted to type @a ValueType - - @throw std::domain_error in case passed type @a ValueType is incompatible - to JSON; example: `"type must be object, but is null"` - - @complexity Linear in the size of the JSON value. - - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,get__ValueType_const} - - @internal - The idea of using a casted null pointer to choose the correct - implementation is from . - @endinternal - - @sa @ref operator ValueType() const for implicit conversion - @sa @ref get() for pointer-member access - - @since version 1.0.0 - */ - template ::value and - detail::is_compatible_basic_json_type< - uncvref_t, basic_json_t>::value, - int> = 0> - auto get() const - -> decltype(this->get_impl(static_cast(nullptr))) { - return get_impl(static_cast(nullptr)); - } - // if T is basic_json, simply returns *this template ::value, int> = 0> @@ -3234,16 +3044,22 @@ class basic_json return *this; } + // This overload is chosen when: + // - T is not basic_json_t + // - JSONSerializer::from_json(basic_json const&, T&) exists + // - and JSONSerializer::from_json(basic_json const&) does not exist + // + // the latter is preferred if both are present (since it does not require a default construction of T) template < typename T, - enable_if_t, basic_json_t>>, + enable_if_t>::value and detail::has_from_json>>::value and - not std::is_same>::value, + uncvref_t>::value and + not detail::has_non_default_from_json< + JSONSerializer, basic_json_t, uncvref_t>::value, int> = 0> - // do we really want the uncvref ? if a user call get, shouldn't we static assert ? + // do we really want the uncvref ? if a user call get, shouldn't we + // static assert ? auto get() const -> uncvref_t { using type = uncvref_t; @@ -3256,19 +3072,22 @@ class basic_json return ret; } - // This overload is chosen for non-default constructible user-defined-types + // This overload is chosen when: + // - T is not basic_json_t + // - and JSONSerializer::from_json(basic_json const&) does not exist + // TODO add constexpr, noexcept(...) template < typename T, - enable_if_t, basic_json_t>>, - detail::has_non_default_from_json>>::value, - short> = 0 > - T get() const + enable_if_t>::value and + detail::has_non_default_from_json< + JSONSerializer, basic_json_t, uncvref_t>::value, + int> = 0> + uncvref_t get() const { - return JSONSerializer::from_json(*this); + return JSONSerializer::from_json(*this); } + // TODO what to do with those... /*! @brief get a pointer value (explicit)