mirror of
https://github.com/nlohmann/json.git
synced 2026-09-07 00:37:58 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bb551f46f | ||
|
|
09b6b6b5ba |
@@ -125,6 +125,7 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
|
||||
- `"_ArrayType_"` is one of `uint8`, `int8`, `uint16`, `int16`, `uint32`, `int32`, `uint64`, `int64`, `single`,
|
||||
`double`, `char`, or `byte`,
|
||||
- `"_ArraySize_"` is an array, since the dimensions are written as the ND-array header's length,
|
||||
- every entry of `"_ArraySize_"` is a non-negative integer, and their product is representable as a `std::size_t`,
|
||||
- `"_ArrayData_"` holds exactly that many elements, and
|
||||
- every element of `"_ArrayData_"` is a number of the kind named by `"_ArrayType_"` (a floating-point number for
|
||||
|
||||
@@ -1668,6 +1668,15 @@ class binary_writer
|
||||
CharType dtype = it->second;
|
||||
|
||||
key = "_ArraySize_";
|
||||
// the dimensions are written verbatim as the header length below, so a
|
||||
// value that is not an array cannot produce a valid one: null emits 'Z'
|
||||
// and an object emits '{', neither of which a reader accepts after '#'.
|
||||
// Such an object is not a valid ndarray and falls back to a plain object.
|
||||
if (!value.at(key).is_array())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t len = (value.at(key).empty() ? 0 : 1);
|
||||
for (const auto& el : value.at(key))
|
||||
{
|
||||
|
||||
@@ -3573,6 +3573,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
using std::swap;
|
||||
swap(*(m_data.m_value.array), other);
|
||||
set_parents();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3589,6 +3590,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
using std::swap;
|
||||
swap(*(m_data.m_value.object), other);
|
||||
set_parents();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -18676,6 +18676,15 @@ class binary_writer
|
||||
CharType dtype = it->second;
|
||||
|
||||
key = "_ArraySize_";
|
||||
// the dimensions are written verbatim as the header length below, so a
|
||||
// value that is not an array cannot produce a valid one: null emits 'Z'
|
||||
// and an object emits '{', neither of which a reader accepts after '#'.
|
||||
// Such an object is not a valid ndarray and falls back to a plain object.
|
||||
if (!value.at(key).is_array())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t len = (value.at(key).empty() ? 0 : 1);
|
||||
for (const auto& el : value.at(key))
|
||||
{
|
||||
@@ -24992,6 +25001,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
using std::swap;
|
||||
swap(*(m_data.m_value.array), other);
|
||||
set_parents();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -25008,6 +25018,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
using std::swap;
|
||||
swap(*(m_data.m_value.object), other);
|
||||
set_parents();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -2751,6 +2751,31 @@ TEST_CASE("BJData")
|
||||
CHECK(json::to_bjdata(j_ok) == std::vector<uint8_t>({'[', '$', 'U', '#', '[', 'i', 2, 'i', 3, ']', 1, 2, 3, 4, 5, 6}));
|
||||
CHECK(json::from_bjdata(json::to_bjdata(j_ok), true, true) == j_ok);
|
||||
}
|
||||
|
||||
SECTION("ndarray whose _ArraySize_ is not an array stays as object")
|
||||
{
|
||||
// the shape is written verbatim as the header length, so a
|
||||
// value that is not an array cannot produce a valid one: null
|
||||
// would emit 'Z' and an object '{', neither of which a reader
|
||||
// accepts after '#'. Both have to stay plain objects.
|
||||
json const j_null = json({{"_ArrayType_", "uint8"}, {"_ArraySize_", nullptr}, {"_ArrayData_", json::array()}});
|
||||
const auto out_null = json::to_bjdata(j_null);
|
||||
CHECK(out_null.at(0) == '{');
|
||||
CHECK(json::from_bjdata(out_null) == j_null);
|
||||
|
||||
// an object shape passes the per-entry check by iterating its
|
||||
// values rather than dimensions, so it needs rejecting too
|
||||
json const j_obj = json({{"_ArrayType_", "uint8"}, {"_ArraySize_", {{"a", 1}}}, {"_ArrayData_", {1}}});
|
||||
const auto out_obj = json::to_bjdata(j_obj);
|
||||
CHECK(out_obj.at(0) == '{');
|
||||
CHECK(json::from_bjdata(out_obj) == j_obj);
|
||||
|
||||
// a scalar shape is not a dimension list either
|
||||
json const j_num = json({{"_ArrayType_", "uint8"}, {"_ArraySize_", 1}, {"_ArrayData_", {1}}});
|
||||
const auto out_num = json::to_bjdata(j_num);
|
||||
CHECK(out_num.at(0) == '{');
|
||||
CHECK(json::from_bjdata(out_num) == j_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -273,5 +273,36 @@ TEST_CASE("Regression tests for extended diagnostics")
|
||||
CHECK(j1["numbers"]["two"] == 2);
|
||||
CHECK(j1["string"] == "t");
|
||||
}
|
||||
|
||||
SECTION("Regression test - swap(array_t&)/swap(object_t&) must update JSON_DIAGNOSTICS parent pointers")
|
||||
{
|
||||
// swap(array_t&)
|
||||
{
|
||||
json j = json::array();
|
||||
json::array_t arr = {json::array({1})};
|
||||
j.swap(arr);
|
||||
|
||||
// parent pointers of the moved-in elements must point into j, not
|
||||
// into the now-defunct free-standing array_t
|
||||
CHECK_THROWS_WITH_AS(j[0][0].get<std::string>(), "[json.exception.type_error.302] (/0/0) type must be string, but is number", json::type_error);
|
||||
|
||||
// must not trigger assert_invariant() in a debug/assert-enabled build
|
||||
json const k = j;
|
||||
CHECK(k == j);
|
||||
}
|
||||
|
||||
// swap(object_t&)
|
||||
{
|
||||
json o = json::object();
|
||||
json::object_t obj = {{"a", json::array({1})}};
|
||||
o.swap(obj);
|
||||
|
||||
CHECK_THROWS_WITH_AS(o["a"][0].get<std::string>(), "[json.exception.type_error.302] (/a/0) type must be string, but is number", json::type_error);
|
||||
|
||||
// must not trigger assert_invariant() in a debug/assert-enabled build
|
||||
json const p = o;
|
||||
CHECK(p == o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user