1
0
mirror of https://github.com/nlohmann/json.git synced 2025-07-24 02:21:01 +03:00

🐛 fix invariants

This commit is contained in:
Niels Lohmann
2021-01-10 22:40:50 +01:00
parent 9d0150c234
commit ff57bdcc8b
5 changed files with 118 additions and 60 deletions

View File

@ -1233,13 +1233,29 @@ class basic_json
invariant. Furthermore, it has to be called each time the type of a JSON
value is changed, because the invariant expresses a relationship between
@a m_type and @a m_value.
Furthermore, the parent relation is checked for arrays and objects: If
@a check_parents true and the value is an array or object, then the
container's elements must have the current value as parent.
@param[in] check_parents whether the parent relation should be checked.
The value is true by default and should only be set to true
during destruction of objects when the invariant does not
need to hold.
*/
void assert_invariant() const noexcept
void assert_invariant(bool check_parents = true) const noexcept
{
JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr);
JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr);
JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr);
JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr);
#if JSON_DIAGNOSTICS
JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j)
{
return j.m_parent == this;
}));
#endif
}
reference set_parent(reference j, bool recursive)
@ -1497,6 +1513,7 @@ class basic_json
std::forward<CompatibleType>(val))))
{
JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
set_parent(*this, true);
assert_invariant();
}
@ -1575,6 +1592,7 @@ class basic_json
default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
}
set_parent(*this, true);
assert_invariant();
}
@ -1689,10 +1707,9 @@ class basic_json
for (auto& element_ref : init)
{
auto element = element_ref.moved_or_copied();
auto res = m_value.object->emplace(
std::move(*((*element.m_value.array)[0].m_value.string)),
std::move((*element.m_value.array)[1]));
set_parent(res.first->second, false);
m_value.object->emplace(
std::move(*((*element.m_value.array)[0].m_value.string)),
std::move((*element.m_value.array)[1]));
}
}
else
@ -1700,9 +1717,9 @@ class basic_json
// the initializer list describes an array -> create array
m_type = value_t::array;
m_value.array = create<array_t>(init.begin(), init.end());
set_parent(*this, true);
}
set_parent(*this, true);
assert_invariant();
}
@ -2045,7 +2062,6 @@ class basic_json
{
m_value.object = create<object_t>(first.m_it.object_iterator,
last.m_it.object_iterator);
set_parent(*this, true);
break;
}
@ -2053,7 +2069,6 @@ class basic_json
{
m_value.array = create<array_t>(first.m_it.array_iterator,
last.m_it.array_iterator);
set_parent(*this, true);
break;
}
@ -2067,6 +2082,7 @@ class basic_json
JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + std::string(first.m_object->type_name()), diagnostics_t()));
}
set_parent(*this, true);
assert_invariant();
}
@ -2116,14 +2132,12 @@ class basic_json
case value_t::object:
{
m_value = *other.m_value.object;
set_parent(*this, true);
break;
}
case value_t::array:
{
m_value = *other.m_value.array;
set_parent(*this, true);
break;
}
@ -2167,6 +2181,7 @@ class basic_json
break;
}
set_parent(*this, true);
assert_invariant();
}
@ -2201,7 +2216,7 @@ class basic_json
m_value(std::move(other.m_value))
{
// check that passed value is valid
other.assert_invariant();
other.assert_invariant(false);
// invalidate payload
other.m_type = value_t::null;
@ -2248,6 +2263,7 @@ class basic_json
swap(m_type, other.m_type);
swap(m_value, other.m_value);
set_parent(*this, true);
assert_invariant();
return *this;
}
@ -2269,7 +2285,7 @@ class basic_json
*/
~basic_json() noexcept
{
assert_invariant();
assert_invariant(false);
m_value.destroy(m_type);
}
@ -5990,6 +6006,8 @@ class basic_json
{
std::swap(m_type, other.m_type);
std::swap(m_value, other.m_value);
set_parent(*this, true);
assert_invariant();
}