mirror of
https://github.com/nlohmann/json.git
synced 2026-10-02 20:50:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd2dd45abd | ||
|
|
362a902170 | ||
|
|
ba6bf32f6d | ||
|
|
056d187986 | ||
|
|
90078597c7 | ||
|
|
fa28fff7d6 | ||
|
|
e9c84befa1 | ||
|
|
8a26f2dc8f | ||
|
|
2c108d0b56 |
@@ -42,6 +42,10 @@ namespace detail
|
|||||||
* j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an
|
* j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an
|
||||||
* allocated value (e.g., a string). See bug issue
|
* allocated value (e.g., a string). See bug issue
|
||||||
* https://github.com/nlohmann/json/issues/2865 for more information.
|
* https://github.com/nlohmann/json/issues/2865 for more information.
|
||||||
|
*
|
||||||
|
* A value that has to be allocated is created before the old one is destroyed:
|
||||||
|
* were it the other way around, an exception while creating the new value would
|
||||||
|
* leave j with the type of the new value, but the pointer to the destroyed old one.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<value_t> struct external_constructor;
|
template<value_t> struct external_constructor;
|
||||||
@@ -65,18 +69,20 @@ struct external_constructor<value_t::string>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
|
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(s);
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::string;
|
j.m_data.m_type = value_t::string;
|
||||||
j.m_data.m_value = s;
|
j.m_data.m_value = value;
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(std::move(s));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::string;
|
j.m_data.m_type = value_t::string;
|
||||||
j.m_data.m_value = std::move(s);
|
j.m_data.m_value = value;
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,9 +91,10 @@ struct external_constructor<value_t::string>
|
|||||||
int > = 0 >
|
int > = 0 >
|
||||||
static void construct(BasicJsonType& j, const CompatibleStringType& str)
|
static void construct(BasicJsonType& j, const CompatibleStringType& str)
|
||||||
{
|
{
|
||||||
|
auto* created = j.template create<typename BasicJsonType::string_t>(str);
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::string;
|
j.m_data.m_type = value_t::string;
|
||||||
j.m_data.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
|
j.m_data.m_value.string = created;
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -98,18 +105,20 @@ struct external_constructor<value_t::binary>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
|
static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(b);
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::binary;
|
j.m_data.m_type = value_t::binary;
|
||||||
j.m_data.m_value = typename BasicJsonType::binary_t(b);
|
j.m_data.m_value = value;
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
|
static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(std::move(b));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::binary;
|
j.m_data.m_type = value_t::binary;
|
||||||
j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b));
|
j.m_data.m_value = value;
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -159,9 +168,10 @@ struct external_constructor<value_t::array>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
|
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(arr);
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::array;
|
j.m_data.m_type = value_t::array;
|
||||||
j.m_data.m_value = arr;
|
j.m_data.m_value = value;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -169,9 +179,10 @@ struct external_constructor<value_t::array>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(std::move(arr));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::array;
|
j.m_data.m_type = value_t::array;
|
||||||
j.m_data.m_value = std::move(arr);
|
j.m_data.m_value = value;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -187,9 +198,10 @@ struct external_constructor<value_t::array>
|
|||||||
using std::begin;
|
using std::begin;
|
||||||
using std::end;
|
using std::end;
|
||||||
|
|
||||||
|
auto* created = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::array;
|
j.m_data.m_type = value_t::array;
|
||||||
j.m_data.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
|
j.m_data.m_value.array = created;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -197,15 +209,17 @@ struct external_constructor<value_t::array>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, const std::vector<bool>& arr)
|
static void construct(BasicJsonType& j, const std::vector<bool>& arr)
|
||||||
{
|
{
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
typename BasicJsonType::array_t elements;
|
||||||
j.m_data.m_type = value_t::array;
|
elements.reserve(arr.size());
|
||||||
j.m_data.m_value = value_t::array;
|
|
||||||
j.m_data.m_value.array->reserve(arr.size());
|
|
||||||
for (const bool x : arr)
|
for (const bool x : arr)
|
||||||
{
|
{
|
||||||
j.m_data.m_value.array->push_back(x);
|
elements.push_back(x);
|
||||||
j.set_parent(j.m_data.m_value.array->back());
|
|
||||||
}
|
}
|
||||||
|
const typename BasicJsonType::json_value value(std::move(elements));
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::array;
|
||||||
|
j.m_data.m_value = value;
|
||||||
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,11 +227,12 @@ struct external_constructor<value_t::array>
|
|||||||
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||||
static void construct(BasicJsonType& j, const std::valarray<T>& arr)
|
static void construct(BasicJsonType& j, const std::valarray<T>& arr)
|
||||||
{
|
{
|
||||||
|
typename BasicJsonType::array_t elements(arr.size());
|
||||||
|
std::copy(std::begin(arr), std::end(arr), elements.begin());
|
||||||
|
const typename BasicJsonType::json_value value(std::move(elements));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::array;
|
j.m_data.m_type = value_t::array;
|
||||||
j.m_data.m_value = value_t::array;
|
j.m_data.m_value = value;
|
||||||
j.m_data.m_value.array->resize(arr.size());
|
|
||||||
std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin());
|
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -229,14 +244,16 @@ struct external_constructor<value_t::array>
|
|||||||
enable_if_t<is_compatible_range_view<std::remove_cvref_t<CompatibleArrayType>>::value, int> = 0>
|
enable_if_t<is_compatible_range_view<std::remove_cvref_t<CompatibleArrayType>>::value, int> = 0>
|
||||||
static void construct(BasicJsonType& j, CompatibleArrayType && arr)
|
static void construct(BasicJsonType& j, CompatibleArrayType && arr)
|
||||||
{
|
{
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
typename BasicJsonType::array_t elements;
|
||||||
j.m_data.m_type = value_t::array;
|
|
||||||
j.m_data.m_value = value_t::array;
|
|
||||||
for (auto&& x : std::forward<CompatibleArrayType>(arr))
|
for (auto&& x : std::forward<CompatibleArrayType>(arr))
|
||||||
{
|
{
|
||||||
j.m_data.m_value.array->push_back(x);
|
elements.push_back(x);
|
||||||
j.set_parent(j.m_data.m_value.array->back());
|
|
||||||
}
|
}
|
||||||
|
const typename BasicJsonType::json_value value(std::move(elements));
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::array;
|
||||||
|
j.m_data.m_value = value;
|
||||||
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -248,9 +265,10 @@ struct external_constructor<value_t::object>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
|
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(obj);
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::object;
|
j.m_data.m_type = value_t::object;
|
||||||
j.m_data.m_value = obj;
|
j.m_data.m_value = value;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -258,9 +276,10 @@ struct external_constructor<value_t::object>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(std::move(obj));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::object;
|
j.m_data.m_type = value_t::object;
|
||||||
j.m_data.m_value = std::move(obj);
|
j.m_data.m_value = value;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -272,9 +291,10 @@ struct external_constructor<value_t::object>
|
|||||||
using std::begin;
|
using std::begin;
|
||||||
using std::end;
|
using std::end;
|
||||||
|
|
||||||
|
auto* created = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::object;
|
j.m_data.m_type = value_t::object;
|
||||||
j.m_data.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
|
j.m_data.m_value.object = created;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-14
@@ -1894,8 +1894,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
if (is_an_object)
|
if (is_an_object)
|
||||||
{
|
{
|
||||||
// the initializer list is a list of pairs -> create an object
|
// the initializer list is a list of pairs -> create an object
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
m_data.m_value = value_t::object;
|
m_data.m_value = value_t::object;
|
||||||
|
m_data.m_type = value_t::object;
|
||||||
|
|
||||||
for (auto& element_ref : init)
|
for (auto& element_ref : init)
|
||||||
{
|
{
|
||||||
@@ -1917,8 +1917,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// the initializer list describes an array -> create an array
|
// the initializer list describes an array -> create an array
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
m_data.m_value.array = create<array_t>(init.begin(), init.end());
|
m_data.m_value.array = create<array_t>(init.begin(), init.end());
|
||||||
|
m_data.m_type = value_t::array;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_parents();
|
set_parents();
|
||||||
@@ -1931,8 +1931,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json binary(const typename binary_t::container_type& init)
|
static basic_json binary(const typename binary_t::container_type& init)
|
||||||
{
|
{
|
||||||
auto res = basic_json();
|
auto res = basic_json();
|
||||||
res.m_data.m_type = value_t::binary;
|
|
||||||
res.m_data.m_value = init;
|
res.m_data.m_value = init;
|
||||||
|
res.m_data.m_type = value_t::binary;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1942,8 +1942,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
|
static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
|
||||||
{
|
{
|
||||||
auto res = basic_json();
|
auto res = basic_json();
|
||||||
res.m_data.m_type = value_t::binary;
|
|
||||||
res.m_data.m_value = binary_t(init, subtype);
|
res.m_data.m_value = binary_t(init, subtype);
|
||||||
|
res.m_data.m_type = value_t::binary;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1953,8 +1953,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json binary(typename binary_t::container_type&& init)
|
static basic_json binary(typename binary_t::container_type&& init)
|
||||||
{
|
{
|
||||||
auto res = basic_json();
|
auto res = basic_json();
|
||||||
res.m_data.m_type = value_t::binary;
|
|
||||||
res.m_data.m_value = std::move(init);
|
res.m_data.m_value = std::move(init);
|
||||||
|
res.m_data.m_type = value_t::binary;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1964,8 +1964,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
|
static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
|
||||||
{
|
{
|
||||||
auto res = basic_json();
|
auto res = basic_json();
|
||||||
res.m_data.m_type = value_t::binary;
|
|
||||||
res.m_data.m_value = binary_t(std::move(init), subtype);
|
res.m_data.m_value = binary_t(std::move(init), subtype);
|
||||||
|
res.m_data.m_type = value_t::binary;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3011,8 +3011,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// implicitly convert a null value to an empty array
|
// implicitly convert a null value to an empty array
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
m_data.m_value.array = create<array_t>();
|
m_data.m_value.array = create<array_t>();
|
||||||
|
m_data.m_type = value_t::array;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3078,8 +3078,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// implicitly convert a null value to an empty object
|
// implicitly convert a null value to an empty object
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
m_data.m_value.object = create<object_t>();
|
m_data.m_value.object = create<object_t>();
|
||||||
|
m_data.m_type = value_t::object;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3131,8 +3131,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// implicitly convert a null value to an empty object
|
// implicitly convert a null value to an empty object
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
m_data.m_value.object = create<object_t>();
|
m_data.m_value.object = create<object_t>();
|
||||||
|
m_data.m_type = value_t::object;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4082,8 +4082,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
m_data.m_value = value_t::array;
|
m_data.m_value = value_t::array;
|
||||||
|
m_data.m_type = value_t::array;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4115,8 +4115,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
m_data.m_value = value_t::array;
|
m_data.m_value = value_t::array;
|
||||||
|
m_data.m_type = value_t::array;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4147,8 +4147,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// transform a null object into an object
|
// transform a null object into an object
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
m_data.m_value = value_t::object;
|
m_data.m_value = value_t::object;
|
||||||
|
m_data.m_type = value_t::object;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4203,8 +4203,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
m_data.m_value = value_t::array;
|
m_data.m_value = value_t::array;
|
||||||
|
m_data.m_type = value_t::array;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4228,8 +4228,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// transform a null object into an object
|
// transform a null object into an object
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
m_data.m_value = value_t::object;
|
m_data.m_value = value_t::object;
|
||||||
|
m_data.m_type = value_t::object;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6655,6 +6655,10 @@ namespace detail
|
|||||||
* j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an
|
* j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an
|
||||||
* allocated value (e.g., a string). See bug issue
|
* allocated value (e.g., a string). See bug issue
|
||||||
* https://github.com/nlohmann/json/issues/2865 for more information.
|
* https://github.com/nlohmann/json/issues/2865 for more information.
|
||||||
|
*
|
||||||
|
* A value that has to be allocated is created before the old one is destroyed:
|
||||||
|
* were it the other way around, an exception while creating the new value would
|
||||||
|
* leave j with the type of the new value, but the pointer to the destroyed old one.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<value_t> struct external_constructor;
|
template<value_t> struct external_constructor;
|
||||||
@@ -6678,18 +6682,20 @@ struct external_constructor<value_t::string>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
|
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(s);
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::string;
|
j.m_data.m_type = value_t::string;
|
||||||
j.m_data.m_value = s;
|
j.m_data.m_value = value;
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(std::move(s));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::string;
|
j.m_data.m_type = value_t::string;
|
||||||
j.m_data.m_value = std::move(s);
|
j.m_data.m_value = value;
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6698,9 +6704,10 @@ struct external_constructor<value_t::string>
|
|||||||
int > = 0 >
|
int > = 0 >
|
||||||
static void construct(BasicJsonType& j, const CompatibleStringType& str)
|
static void construct(BasicJsonType& j, const CompatibleStringType& str)
|
||||||
{
|
{
|
||||||
|
auto* created = j.template create<typename BasicJsonType::string_t>(str);
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::string;
|
j.m_data.m_type = value_t::string;
|
||||||
j.m_data.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
|
j.m_data.m_value.string = created;
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -6711,18 +6718,20 @@ struct external_constructor<value_t::binary>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
|
static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(b);
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::binary;
|
j.m_data.m_type = value_t::binary;
|
||||||
j.m_data.m_value = typename BasicJsonType::binary_t(b);
|
j.m_data.m_value = value;
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
|
static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(std::move(b));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::binary;
|
j.m_data.m_type = value_t::binary;
|
||||||
j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b));
|
j.m_data.m_value = value;
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -6772,9 +6781,10 @@ struct external_constructor<value_t::array>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
|
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(arr);
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::array;
|
j.m_data.m_type = value_t::array;
|
||||||
j.m_data.m_value = arr;
|
j.m_data.m_value = value;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -6782,9 +6792,10 @@ struct external_constructor<value_t::array>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(std::move(arr));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::array;
|
j.m_data.m_type = value_t::array;
|
||||||
j.m_data.m_value = std::move(arr);
|
j.m_data.m_value = value;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -6800,9 +6811,10 @@ struct external_constructor<value_t::array>
|
|||||||
using std::begin;
|
using std::begin;
|
||||||
using std::end;
|
using std::end;
|
||||||
|
|
||||||
|
auto* created = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::array;
|
j.m_data.m_type = value_t::array;
|
||||||
j.m_data.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
|
j.m_data.m_value.array = created;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -6810,15 +6822,17 @@ struct external_constructor<value_t::array>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, const std::vector<bool>& arr)
|
static void construct(BasicJsonType& j, const std::vector<bool>& arr)
|
||||||
{
|
{
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
typename BasicJsonType::array_t elements;
|
||||||
j.m_data.m_type = value_t::array;
|
elements.reserve(arr.size());
|
||||||
j.m_data.m_value = value_t::array;
|
|
||||||
j.m_data.m_value.array->reserve(arr.size());
|
|
||||||
for (const bool x : arr)
|
for (const bool x : arr)
|
||||||
{
|
{
|
||||||
j.m_data.m_value.array->push_back(x);
|
elements.push_back(x);
|
||||||
j.set_parent(j.m_data.m_value.array->back());
|
|
||||||
}
|
}
|
||||||
|
const typename BasicJsonType::json_value value(std::move(elements));
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::array;
|
||||||
|
j.m_data.m_value = value;
|
||||||
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6826,11 +6840,12 @@ struct external_constructor<value_t::array>
|
|||||||
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||||
static void construct(BasicJsonType& j, const std::valarray<T>& arr)
|
static void construct(BasicJsonType& j, const std::valarray<T>& arr)
|
||||||
{
|
{
|
||||||
|
typename BasicJsonType::array_t elements(arr.size());
|
||||||
|
std::copy(std::begin(arr), std::end(arr), elements.begin());
|
||||||
|
const typename BasicJsonType::json_value value(std::move(elements));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::array;
|
j.m_data.m_type = value_t::array;
|
||||||
j.m_data.m_value = value_t::array;
|
j.m_data.m_value = value;
|
||||||
j.m_data.m_value.array->resize(arr.size());
|
|
||||||
std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin());
|
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -6842,14 +6857,16 @@ struct external_constructor<value_t::array>
|
|||||||
enable_if_t<is_compatible_range_view<std::remove_cvref_t<CompatibleArrayType>>::value, int> = 0>
|
enable_if_t<is_compatible_range_view<std::remove_cvref_t<CompatibleArrayType>>::value, int> = 0>
|
||||||
static void construct(BasicJsonType& j, CompatibleArrayType && arr)
|
static void construct(BasicJsonType& j, CompatibleArrayType && arr)
|
||||||
{
|
{
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
typename BasicJsonType::array_t elements;
|
||||||
j.m_data.m_type = value_t::array;
|
|
||||||
j.m_data.m_value = value_t::array;
|
|
||||||
for (auto&& x : std::forward<CompatibleArrayType>(arr))
|
for (auto&& x : std::forward<CompatibleArrayType>(arr))
|
||||||
{
|
{
|
||||||
j.m_data.m_value.array->push_back(x);
|
elements.push_back(x);
|
||||||
j.set_parent(j.m_data.m_value.array->back());
|
|
||||||
}
|
}
|
||||||
|
const typename BasicJsonType::json_value value(std::move(elements));
|
||||||
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
|
j.m_data.m_type = value_t::array;
|
||||||
|
j.m_data.m_value = value;
|
||||||
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -6861,9 +6878,10 @@ struct external_constructor<value_t::object>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
|
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(obj);
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::object;
|
j.m_data.m_type = value_t::object;
|
||||||
j.m_data.m_value = obj;
|
j.m_data.m_value = value;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -6871,9 +6889,10 @@ struct external_constructor<value_t::object>
|
|||||||
template<typename BasicJsonType>
|
template<typename BasicJsonType>
|
||||||
static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||||
{
|
{
|
||||||
|
const typename BasicJsonType::json_value value(std::move(obj));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::object;
|
j.m_data.m_type = value_t::object;
|
||||||
j.m_data.m_value = std::move(obj);
|
j.m_data.m_value = value;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -6885,9 +6904,10 @@ struct external_constructor<value_t::object>
|
|||||||
using std::begin;
|
using std::begin;
|
||||||
using std::end;
|
using std::end;
|
||||||
|
|
||||||
|
auto* created = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
|
||||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||||
j.m_data.m_type = value_t::object;
|
j.m_data.m_type = value_t::object;
|
||||||
j.m_data.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
|
j.m_data.m_value.object = created;
|
||||||
j.set_parents();
|
j.set_parents();
|
||||||
j.assert_invariant();
|
j.assert_invariant();
|
||||||
}
|
}
|
||||||
@@ -28572,8 +28592,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
if (is_an_object)
|
if (is_an_object)
|
||||||
{
|
{
|
||||||
// the initializer list is a list of pairs -> create an object
|
// the initializer list is a list of pairs -> create an object
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
m_data.m_value = value_t::object;
|
m_data.m_value = value_t::object;
|
||||||
|
m_data.m_type = value_t::object;
|
||||||
|
|
||||||
for (auto& element_ref : init)
|
for (auto& element_ref : init)
|
||||||
{
|
{
|
||||||
@@ -28595,8 +28615,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// the initializer list describes an array -> create an array
|
// the initializer list describes an array -> create an array
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
m_data.m_value.array = create<array_t>(init.begin(), init.end());
|
m_data.m_value.array = create<array_t>(init.begin(), init.end());
|
||||||
|
m_data.m_type = value_t::array;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_parents();
|
set_parents();
|
||||||
@@ -28609,8 +28629,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json binary(const typename binary_t::container_type& init)
|
static basic_json binary(const typename binary_t::container_type& init)
|
||||||
{
|
{
|
||||||
auto res = basic_json();
|
auto res = basic_json();
|
||||||
res.m_data.m_type = value_t::binary;
|
|
||||||
res.m_data.m_value = init;
|
res.m_data.m_value = init;
|
||||||
|
res.m_data.m_type = value_t::binary;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28620,8 +28640,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
|
static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
|
||||||
{
|
{
|
||||||
auto res = basic_json();
|
auto res = basic_json();
|
||||||
res.m_data.m_type = value_t::binary;
|
|
||||||
res.m_data.m_value = binary_t(init, subtype);
|
res.m_data.m_value = binary_t(init, subtype);
|
||||||
|
res.m_data.m_type = value_t::binary;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28631,8 +28651,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json binary(typename binary_t::container_type&& init)
|
static basic_json binary(typename binary_t::container_type&& init)
|
||||||
{
|
{
|
||||||
auto res = basic_json();
|
auto res = basic_json();
|
||||||
res.m_data.m_type = value_t::binary;
|
|
||||||
res.m_data.m_value = std::move(init);
|
res.m_data.m_value = std::move(init);
|
||||||
|
res.m_data.m_type = value_t::binary;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28642,8 +28662,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
|
static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
|
||||||
{
|
{
|
||||||
auto res = basic_json();
|
auto res = basic_json();
|
||||||
res.m_data.m_type = value_t::binary;
|
|
||||||
res.m_data.m_value = binary_t(std::move(init), subtype);
|
res.m_data.m_value = binary_t(std::move(init), subtype);
|
||||||
|
res.m_data.m_type = value_t::binary;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29689,8 +29709,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// implicitly convert a null value to an empty array
|
// implicitly convert a null value to an empty array
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
m_data.m_value.array = create<array_t>();
|
m_data.m_value.array = create<array_t>();
|
||||||
|
m_data.m_type = value_t::array;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29756,8 +29776,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// implicitly convert a null value to an empty object
|
// implicitly convert a null value to an empty object
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
m_data.m_value.object = create<object_t>();
|
m_data.m_value.object = create<object_t>();
|
||||||
|
m_data.m_type = value_t::object;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29809,8 +29829,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// implicitly convert a null value to an empty object
|
// implicitly convert a null value to an empty object
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
m_data.m_value.object = create<object_t>();
|
m_data.m_value.object = create<object_t>();
|
||||||
|
m_data.m_type = value_t::object;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30760,8 +30780,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
m_data.m_value = value_t::array;
|
m_data.m_value = value_t::array;
|
||||||
|
m_data.m_type = value_t::array;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30793,8 +30813,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
m_data.m_value = value_t::array;
|
m_data.m_value = value_t::array;
|
||||||
|
m_data.m_type = value_t::array;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30825,8 +30845,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// transform a null object into an object
|
// transform a null object into an object
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
m_data.m_value = value_t::object;
|
m_data.m_value = value_t::object;
|
||||||
|
m_data.m_type = value_t::object;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30881,8 +30901,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::array;
|
|
||||||
m_data.m_value = value_t::array;
|
m_data.m_value = value_t::array;
|
||||||
|
m_data.m_type = value_t::array;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30906,8 +30926,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// transform a null object into an object
|
// transform a null object into an object
|
||||||
if (is_null())
|
if (is_null())
|
||||||
{
|
{
|
||||||
m_data.m_type = value_t::object;
|
|
||||||
m_data.m_value = value_t::object;
|
m_data.m_value = value_t::object;
|
||||||
|
m_data.m_type = value_t::object;
|
||||||
assert_invariant();
|
assert_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,6 +139,11 @@ json_test_set_test_options(test-unicode4 TEST_PROPERTIES TIMEOUT 3000)
|
|||||||
# only the #972 regression test needs thirdparty/fifo_map on its include path
|
# only the #972 regression test needs thirdparty/fifo_map on its include path
|
||||||
json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include)
|
json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include)
|
||||||
|
|
||||||
|
# GCC's false -Warray-bounds error with JSON_DIAGNOSTICS only shows up when optimizing (#5742)
|
||||||
|
json_test_set_test_options(test-diagnostics-optimized
|
||||||
|
COMPILE_OPTIONS $<$<CXX_COMPILER_ID:GNU>:-O3 -Werror=array-bounds>
|
||||||
|
)
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
# add unit tests
|
# add unit tests
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|||||||
@@ -12,6 +12,11 @@
|
|||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
|
#include <valarray>
|
||||||
|
#if JSON_HAS_RANGES
|
||||||
|
#include <ranges>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// special test case to check if memory is leaked if constructor throws
|
// special test case to check if memory is leaked if constructor throws
|
||||||
@@ -592,3 +597,173 @@ TEST_CASE("bad my_allocator::construct")
|
|||||||
j["test"].push_back("should not leak");
|
j["test"].push_back("should not leak");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the no-exceptions CI job skips every CHECK_THROWS_AS, which would leave
|
||||||
|
// next_construct_fails set for the next allocation outside a check
|
||||||
|
#if !defined(JSON_NOEXCEPTION)
|
||||||
|
TEST_CASE("a failed allocation leaves the value unchanged")
|
||||||
|
{
|
||||||
|
// create JSON type using the throwing allocator
|
||||||
|
using my_json = nlohmann::basic_json<std::map,
|
||||||
|
std::vector,
|
||||||
|
std::string,
|
||||||
|
bool,
|
||||||
|
std::int64_t,
|
||||||
|
std::uint64_t,
|
||||||
|
double,
|
||||||
|
my_allocator>;
|
||||||
|
|
||||||
|
// Each of these creates a string, array, object, or binary value. The
|
||||||
|
// value must be created before the type is changed: otherwise, a failed
|
||||||
|
// creation left a value of the new type without anything behind it (an
|
||||||
|
// assertion in its destructor, a null pointer everywhere else) or, when
|
||||||
|
// an old value was destroyed first, with a pointer to that destroyed one.
|
||||||
|
|
||||||
|
SECTION("creating a binary value")
|
||||||
|
{
|
||||||
|
const std::vector<std::uint8_t> bytes = {1, 2, 3};
|
||||||
|
my_json _;
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(_ = my_json::binary(bytes), std::bad_alloc&);
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(_ = my_json::binary(bytes, 42), std::bad_alloc&);
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(_ = my_json::binary(std::vector<std::uint8_t>(bytes)), std::bad_alloc&);
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(_ = my_json::binary(std::vector<std::uint8_t>(bytes), 42), std::bad_alloc&);
|
||||||
|
next_construct_fails = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("turning a null value into an array or object")
|
||||||
|
{
|
||||||
|
my_json j;
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(j[0], std::bad_alloc&);
|
||||||
|
CHECK(j.is_null());
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(j["key"], std::bad_alloc&);
|
||||||
|
CHECK(j.is_null());
|
||||||
|
|
||||||
|
#ifdef JSON_HAS_CPP_17
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(j[std::string_view("key")], std::bad_alloc&);
|
||||||
|
CHECK(j.is_null());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(j.push_back(my_json(1)), std::bad_alloc&);
|
||||||
|
CHECK(j.is_null());
|
||||||
|
|
||||||
|
const my_json one = 1;
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(j.push_back(one), std::bad_alloc&);
|
||||||
|
CHECK(j.is_null());
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(j.push_back(my_json::object_t::value_type("key", 1)), std::bad_alloc&);
|
||||||
|
CHECK(j.is_null());
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(j.emplace_back(1), std::bad_alloc&);
|
||||||
|
CHECK(j.is_null());
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(j.emplace("key", 1), std::bad_alloc&);
|
||||||
|
CHECK(j.is_null());
|
||||||
|
|
||||||
|
const my_json object = {{"key", 1}};
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(j.update(object), std::bad_alloc&);
|
||||||
|
CHECK(j.is_null());
|
||||||
|
|
||||||
|
next_construct_fails = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// With iterator debugging, VS 2015's containers construct a proxy with the
|
||||||
|
// allocator in constructors that cannot report its failure, so a failing
|
||||||
|
// allocator crashes this section there (SIGSEGV with VS 2015 Debug x86).
|
||||||
|
#if !(defined(_MSC_VER) && _MSC_VER < 1910 && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
|
||||||
|
SECTION("converting into an existing value")
|
||||||
|
{
|
||||||
|
// to_json replaces the value it is given; the old one must survive a
|
||||||
|
// failed creation of the new one
|
||||||
|
my_json j = "old";
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, std::string("new")), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, std::vector<int> {1, 2}), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, std::vector<bool> {true, false}), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, std::map<std::string, int> {{"a", 1}}), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, my_json::binary_t({1, 2})), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
// the overloads for lvalues of the value types, for the value types
|
||||||
|
// themselves, and for the remaining compatible types
|
||||||
|
const std::string string = "new";
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, string), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, "new"), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
// to_json only moves a binary value that it converted from another
|
||||||
|
// container type, which my_json's std::vector<std::uint8_t> is not
|
||||||
|
using binary_constructor = nlohmann::detail::external_constructor<nlohmann::detail::value_t::binary>;
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(binary_constructor::construct(j, my_json::binary_t({1, 2})), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
my_json::array_t array = {1, 2};
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, array), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, std::move(array)), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
my_json::object_t object = {{"a", 1}};
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, object), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, std::move(object)), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, std::valarray<int> {1, 2}), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
|
||||||
|
#if JSON_HAS_RANGES && !defined(__MINGW32__)
|
||||||
|
const std::vector<int> numbers = {1, 2};
|
||||||
|
next_construct_fails = true;
|
||||||
|
CHECK_THROWS_AS(nlohmann::to_json(j, numbers | std::views::filter([](int /*unused*/)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
})), std::bad_alloc&);
|
||||||
|
CHECK(j == "old");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
next_construct_fails = false;
|
||||||
|
nlohmann::to_json(j, std::vector<int> {1, 2});
|
||||||
|
CHECK(j == my_json({1, 2}));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
// __ _____ _____ _____
|
||||||
|
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||||
|
// | | |__ | | | | | | version 3.12.0
|
||||||
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
//
|
||||||
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
// Regression test for https://github.com/nlohmann/json/issues/5742: with
|
||||||
|
// JSON_DIAGNOSTICS, GCC (12 to at least 16) reported a false -Warray-bounds
|
||||||
|
// error in the inlined set_parents() at -O3. The type of a new string was set
|
||||||
|
// before the string was allocated, so GCC had to assume that operator new
|
||||||
|
// could change it again and checked the object branch of set_parents()
|
||||||
|
// against the string's allocation. Setting the type after creating the value
|
||||||
|
// avoids this. The warning depends on GCC's inlining decisions, so the
|
||||||
|
// sections cover two patterns that trigger it on different GCC versions
|
||||||
|
// (#4819 and #5742).
|
||||||
|
// On GCC, this file is compiled with -O3 -Werror=array-bounds (see
|
||||||
|
// tests/CMakeLists.txt), so the test fails to build if the warning returns.
|
||||||
|
|
||||||
|
#include "doctest_compatibility.h"
|
||||||
|
|
||||||
|
#ifdef JSON_DIAGNOSTICS
|
||||||
|
#undef JSON_DIAGNOSTICS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define JSON_DIAGNOSTICS 1
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
using nlohmann::json;
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
enum class diag_color
|
||||||
|
{
|
||||||
|
red,
|
||||||
|
green,
|
||||||
|
blue
|
||||||
|
};
|
||||||
|
|
||||||
|
void to_json(json& j, const diag_color& c)
|
||||||
|
{
|
||||||
|
static const std::pair<diag_color, json> m[] = // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||||
|
{
|
||||||
|
{diag_color::red, "r"},
|
||||||
|
{diag_color::green, "g"},
|
||||||
|
{diag_color::blue, "b"},
|
||||||
|
};
|
||||||
|
const auto* it = std::find_if(std::begin(m), std::end(m), [c](const std::pair<diag_color, json>& p)
|
||||||
|
{
|
||||||
|
return p.first == c;
|
||||||
|
});
|
||||||
|
j = it->second;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_CASE("diagnostics with optimization")
|
||||||
|
{
|
||||||
|
SECTION("issue #4819 - object in vector")
|
||||||
|
{
|
||||||
|
std::vector<json> jsons{};
|
||||||
|
jsons.emplace_back(json({{"key", "value"}}));
|
||||||
|
CHECK(jsons.back()["key"] == "value");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("issue #5742 - string values from a static table")
|
||||||
|
{
|
||||||
|
json j = json::array();
|
||||||
|
j.push_back(diag_color::red);
|
||||||
|
j.push_back(diag_color::green);
|
||||||
|
j.push_back(diag_color::blue);
|
||||||
|
CHECK(j.dump() == R"(["r","g","b"])");
|
||||||
|
CHECK_THROWS_WITH_AS(j[1].get<int>(), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user