diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index 37cfecbc5..9f3437d94 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -248,20 +248,33 @@ auto from_json_array_impl(const BasicJsonType& j, std::array& arr, } } +// reserve() is called through this pair (modeled on from_json_object_reserve) +// so from_json_array_impl below has a single body for both ConstructibleArrayType +// that support reserve() and those that don't. +template +auto from_json_array_reserve(ConstructibleArrayType& arr, typename ConstructibleArrayType::size_type size, priority_tag<1> /*unused*/) +-> decltype(arr.reserve(size), void()) +{ + arr.reserve(size); +} + +template +inline void from_json_array_reserve(ConstructibleArrayType& /*arr*/, std::size_t /*size*/, priority_tag<0> /*unused*/) +{} + template::value, int> = 0> auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) -> decltype( - arr.reserve(std::declval()), j.template get(), void()) { using std::end; ConstructibleArrayType ret; - ret.reserve(j.size()); + from_json_array_reserve(ret, j.size(), priority_tag<1> {}); std::transform(j.begin(), j.end(), std::inserter(ret, end(ret)), [](const BasicJsonType & i) { @@ -272,27 +285,6 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p arr = std::move(ret); } -template::value, - int> = 0> -inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, - priority_tag<0> /*unused*/) -{ - using std::end; - - ConstructibleArrayType ret; - std::transform( - j.begin(), j.end(), std::inserter(ret, end(ret)), - [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); - arr = std::move(ret); -} - template < typename BasicJsonType, typename ConstructibleArrayType, enable_if_t < is_constructible_array_type::value&& @@ -514,10 +506,10 @@ auto from_json(BasicJsonType&& j, TupleRelated&& t) return from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {}); } -template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, - typename = enable_if_t < !std::is_constructible < - typename BasicJsonType::string_t, Key >::value >> -inline void from_json(const BasicJsonType& j, std::map& m) +// shared body for std::map/std::unordered_map with a non-string Key: both +// containers are read from an array of [key, value] pairs the same way +template +inline void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { @@ -530,28 +522,24 @@ inline void from_json(const BasicJsonType& j, std::map(), p.at(1).template get()); + m.emplace(p.at(0).template get(), p.at(1).template get()); } } +template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +inline void from_json(const BasicJsonType& j, std::map& m) +{ + from_json_pair_array_to_map(j, m); +} + template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, typename = enable_if_t < !std::is_constructible < typename BasicJsonType::string_t, Key >::value >> inline void from_json(const BasicJsonType& j, std::unordered_map& m) { - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); - } - m.clear(); - for (const auto& p : j) - { - if (JSON_HEDLEY_UNLIKELY(!p.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j)); - } - m.emplace(p.at(0).template get(), p.at(1).template get()); - } + from_json_pair_array_to_map(j, m); } #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 146e46841..c28971608 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5668,20 +5668,33 @@ auto from_json_array_impl(const BasicJsonType& j, std::array& arr, } } +// reserve() is called through this pair (modeled on from_json_object_reserve) +// so from_json_array_impl below has a single body for both ConstructibleArrayType +// that support reserve() and those that don't. +template +auto from_json_array_reserve(ConstructibleArrayType& arr, typename ConstructibleArrayType::size_type size, priority_tag<1> /*unused*/) +-> decltype(arr.reserve(size), void()) +{ + arr.reserve(size); +} + +template +inline void from_json_array_reserve(ConstructibleArrayType& /*arr*/, std::size_t /*size*/, priority_tag<0> /*unused*/) +{} + template::value, int> = 0> auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) -> decltype( - arr.reserve(std::declval()), j.template get(), void()) { using std::end; ConstructibleArrayType ret; - ret.reserve(j.size()); + from_json_array_reserve(ret, j.size(), priority_tag<1> {}); std::transform(j.begin(), j.end(), std::inserter(ret, end(ret)), [](const BasicJsonType & i) { @@ -5692,27 +5705,6 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p arr = std::move(ret); } -template::value, - int> = 0> -inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, - priority_tag<0> /*unused*/) -{ - using std::end; - - ConstructibleArrayType ret; - std::transform( - j.begin(), j.end(), std::inserter(ret, end(ret)), - [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); - arr = std::move(ret); -} - template < typename BasicJsonType, typename ConstructibleArrayType, enable_if_t < is_constructible_array_type::value&& @@ -5934,10 +5926,10 @@ auto from_json(BasicJsonType&& j, TupleRelated&& t) return from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {}); } -template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, - typename = enable_if_t < !std::is_constructible < - typename BasicJsonType::string_t, Key >::value >> -inline void from_json(const BasicJsonType& j, std::map& m) +// shared body for std::map/std::unordered_map with a non-string Key: both +// containers are read from an array of [key, value] pairs the same way +template +inline void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m) { if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { @@ -5950,28 +5942,24 @@ inline void from_json(const BasicJsonType& j, std::map(), p.at(1).template get()); + m.emplace(p.at(0).template get(), p.at(1).template get()); } } +template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +inline void from_json(const BasicJsonType& j, std::map& m) +{ + from_json_pair_array_to_map(j, m); +} + template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, typename = enable_if_t < !std::is_constructible < typename BasicJsonType::string_t, Key >::value >> inline void from_json(const BasicJsonType& j, std::unordered_map& m) { - if (JSON_HEDLEY_UNLIKELY(!j.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); - } - m.clear(); - for (const auto& p : j) - { - if (JSON_HEDLEY_UNLIKELY(!p.is_array())) - { - JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j)); - } - m.emplace(p.at(0).template get(), p.at(1).template get()); - } + from_json_pair_array_to_map(j, m); } #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM