De-duplicate from_json.hpp's map and array-fallback bodies
Several from_json() overload pairs in from_json.hpp were copies of each other, so a fix has to be applied twice (as #5681 already does): - from_json(..., std::map&) and from_json(..., std::unordered_map&) for non-string keys had identical 16-line bodies: array check, m.clear(), pair check loop, m.emplace(...). Route both through a new from_json_pair_array_to_map(j, m) helper. - The from_json_array_impl priority_tag<1> and priority_tag<0> fallbacks ran the same std::transform/std::inserter loop, differing only in ret.reserve(j.size()). Merge them into one body and, modeled on the existing from_json_object_reserve, add a from_json_array_reserve pair so the reserve() call is only made for ConstructibleArrayType that support it. Error ids (type_error.302), messages, diagnostic paths ((at(0)/at(1)) and behavior for types with/without reserve() are unchanged; only the duplication is removed. Public API: no change. Overlaps #5681, which changes the "&j" to "&p" line in both map bodies; the shared helper here should make that a one-line change instead of two on rebase. Signed-off-by: Niels Lohmann <mail@nlohmann.me> #5708 item 5
This commit is contained in:
2 files changed
+58
-82
No files matched your search
@@ -248,20 +248,33 @@ auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& 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<typename ConstructibleArrayType>
|
||||||
|
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<typename ConstructibleArrayType>
|
||||||
|
inline void from_json_array_reserve(ConstructibleArrayType& /*arr*/, std::size_t /*size*/, priority_tag<0> /*unused*/)
|
||||||
|
{}
|
||||||
|
|
||||||
template<typename BasicJsonType, typename ConstructibleArrayType,
|
template<typename BasicJsonType, typename ConstructibleArrayType,
|
||||||
enable_if_t<
|
enable_if_t<
|
||||||
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
|
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
|
||||||
int> = 0>
|
int> = 0>
|
||||||
auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
|
auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
|
||||||
-> decltype(
|
-> decltype(
|
||||||
arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
|
|
||||||
j.template get<typename ConstructibleArrayType::value_type>(),
|
j.template get<typename ConstructibleArrayType::value_type>(),
|
||||||
void())
|
void())
|
||||||
{
|
{
|
||||||
using std::end;
|
using std::end;
|
||||||
|
|
||||||
ConstructibleArrayType ret;
|
ConstructibleArrayType ret;
|
||||||
ret.reserve(j.size());
|
from_json_array_reserve(ret, j.size(), priority_tag<1> {});
|
||||||
std::transform(j.begin(), j.end(),
|
std::transform(j.begin(), j.end(),
|
||||||
std::inserter(ret, end(ret)), [](const BasicJsonType & i)
|
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);
|
arr = std::move(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType, typename ConstructibleArrayType,
|
|
||||||
enable_if_t<
|
|
||||||
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::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<BasicJsonType>() returns *this, this won't call a from_json
|
|
||||||
// method when value_type is BasicJsonType
|
|
||||||
return i.template get<typename ConstructibleArrayType::value_type>();
|
|
||||||
});
|
|
||||||
arr = std::move(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename BasicJsonType, typename ConstructibleArrayType,
|
template < typename BasicJsonType, typename ConstructibleArrayType,
|
||||||
enable_if_t <
|
enable_if_t <
|
||||||
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
|
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
@@ -514,10 +506,10 @@ auto from_json(BasicJsonType&& j, TupleRelated&& t)
|
|||||||
return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
|
return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
|
// shared body for std::map/std::unordered_map with a non-string Key: both
|
||||||
typename = enable_if_t < !std::is_constructible <
|
// containers are read from an array of [key, value] pairs the same way
|
||||||
typename BasicJsonType::string_t, Key >::value >>
|
template<typename BasicJsonType, typename MapType>
|
||||||
inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
|
inline void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
@@ -530,28 +522,24 @@ inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allo
|
|||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
|
||||||
}
|
}
|
||||||
m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
|
m.emplace(p.at(0).template get<typename MapType::key_type>(), p.at(1).template get<typename MapType::mapped_type>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<Key, Value, Compare, Allocator>& m)
|
||||||
|
{
|
||||||
|
from_json_pair_array_to_map(j, m);
|
||||||
|
}
|
||||||
|
|
||||||
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
||||||
typename = enable_if_t < !std::is_constructible <
|
typename = enable_if_t < !std::is_constructible <
|
||||||
typename BasicJsonType::string_t, Key >::value >>
|
typename BasicJsonType::string_t, Key >::value >>
|
||||||
inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
from_json_pair_array_to_map(j, m);
|
||||||
{
|
|
||||||
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<Key>(), p.at(1).template get<Value>());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
|||||||
@@ -5668,20 +5668,33 @@ auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& 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<typename ConstructibleArrayType>
|
||||||
|
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<typename ConstructibleArrayType>
|
||||||
|
inline void from_json_array_reserve(ConstructibleArrayType& /*arr*/, std::size_t /*size*/, priority_tag<0> /*unused*/)
|
||||||
|
{}
|
||||||
|
|
||||||
template<typename BasicJsonType, typename ConstructibleArrayType,
|
template<typename BasicJsonType, typename ConstructibleArrayType,
|
||||||
enable_if_t<
|
enable_if_t<
|
||||||
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
|
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
|
||||||
int> = 0>
|
int> = 0>
|
||||||
auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
|
auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
|
||||||
-> decltype(
|
-> decltype(
|
||||||
arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
|
|
||||||
j.template get<typename ConstructibleArrayType::value_type>(),
|
j.template get<typename ConstructibleArrayType::value_type>(),
|
||||||
void())
|
void())
|
||||||
{
|
{
|
||||||
using std::end;
|
using std::end;
|
||||||
|
|
||||||
ConstructibleArrayType ret;
|
ConstructibleArrayType ret;
|
||||||
ret.reserve(j.size());
|
from_json_array_reserve(ret, j.size(), priority_tag<1> {});
|
||||||
std::transform(j.begin(), j.end(),
|
std::transform(j.begin(), j.end(),
|
||||||
std::inserter(ret, end(ret)), [](const BasicJsonType & i)
|
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);
|
arr = std::move(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType, typename ConstructibleArrayType,
|
|
||||||
enable_if_t<
|
|
||||||
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::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<BasicJsonType>() returns *this, this won't call a from_json
|
|
||||||
// method when value_type is BasicJsonType
|
|
||||||
return i.template get<typename ConstructibleArrayType::value_type>();
|
|
||||||
});
|
|
||||||
arr = std::move(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename BasicJsonType, typename ConstructibleArrayType,
|
template < typename BasicJsonType, typename ConstructibleArrayType,
|
||||||
enable_if_t <
|
enable_if_t <
|
||||||
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
|
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
|
||||||
@@ -5934,10 +5926,10 @@ auto from_json(BasicJsonType&& j, TupleRelated&& t)
|
|||||||
return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
|
return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
|
// shared body for std::map/std::unordered_map with a non-string Key: both
|
||||||
typename = enable_if_t < !std::is_constructible <
|
// containers are read from an array of [key, value] pairs the same way
|
||||||
typename BasicJsonType::string_t, Key >::value >>
|
template<typename BasicJsonType, typename MapType>
|
||||||
inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
|
inline void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
@@ -5950,28 +5942,24 @@ inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allo
|
|||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
|
||||||
}
|
}
|
||||||
m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
|
m.emplace(p.at(0).template get<typename MapType::key_type>(), p.at(1).template get<typename MapType::mapped_type>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<Key, Value, Compare, Allocator>& m)
|
||||||
|
{
|
||||||
|
from_json_pair_array_to_map(j, m);
|
||||||
|
}
|
||||||
|
|
||||||
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
||||||
typename = enable_if_t < !std::is_constructible <
|
typename = enable_if_t < !std::is_constructible <
|
||||||
typename BasicJsonType::string_t, Key >::value >>
|
typename BasicJsonType::string_t, Key >::value >>
|
||||||
inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
from_json_pair_array_to_map(j, m);
|
||||||
{
|
|
||||||
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<Key>(), p.at(1).template get<Value>());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||||
|
|||||||
Reference in new issue
Block a user