🐛 fix invariants

parent 9d0150c2
...@@ -132,6 +132,7 @@ struct external_constructor<value_t::array> ...@@ -132,6 +132,7 @@ struct external_constructor<value_t::array>
{ {
j.m_type = value_t::array; j.m_type = value_t::array;
j.m_value = arr; j.m_value = arr;
j.set_parent(j, true);
j.assert_invariant(); j.assert_invariant();
} }
...@@ -140,6 +141,7 @@ struct external_constructor<value_t::array> ...@@ -140,6 +141,7 @@ struct external_constructor<value_t::array>
{ {
j.m_type = value_t::array; j.m_type = value_t::array;
j.m_value = std::move(arr); j.m_value = std::move(arr);
j.set_parent(j, true);
j.assert_invariant(); j.assert_invariant();
} }
...@@ -152,6 +154,7 @@ struct external_constructor<value_t::array> ...@@ -152,6 +154,7 @@ struct external_constructor<value_t::array>
using std::end; using std::end;
j.m_type = value_t::array; j.m_type = value_t::array;
j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr)); j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
j.set_parent(j, true);
j.assert_invariant(); j.assert_invariant();
} }
...@@ -164,6 +167,9 @@ struct external_constructor<value_t::array> ...@@ -164,6 +167,9 @@ struct external_constructor<value_t::array>
for (const bool x : arr) for (const bool x : arr)
{ {
j.m_value.array->push_back(x); j.m_value.array->push_back(x);
#if JSON_DIAGNOSTICS
j.m_value.array->back().m_parent = &j;
#endif
} }
j.assert_invariant(); j.assert_invariant();
} }
...@@ -179,6 +185,7 @@ struct external_constructor<value_t::array> ...@@ -179,6 +185,7 @@ struct external_constructor<value_t::array>
{ {
std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
} }
j.set_parent(j, true);
j.assert_invariant(); j.assert_invariant();
} }
}; };
...@@ -191,6 +198,7 @@ struct external_constructor<value_t::object> ...@@ -191,6 +198,7 @@ struct external_constructor<value_t::object>
{ {
j.m_type = value_t::object; j.m_type = value_t::object;
j.m_value = obj; j.m_value = obj;
j.set_parent(j, true);
j.assert_invariant(); j.assert_invariant();
} }
...@@ -199,6 +207,7 @@ struct external_constructor<value_t::object> ...@@ -199,6 +207,7 @@ struct external_constructor<value_t::object>
{ {
j.m_type = value_t::object; j.m_type = value_t::object;
j.m_value = std::move(obj); j.m_value = std::move(obj);
j.set_parent(j, true);
j.assert_invariant(); j.assert_invariant();
} }
...@@ -211,6 +220,7 @@ struct external_constructor<value_t::object> ...@@ -211,6 +220,7 @@ struct external_constructor<value_t::object>
j.m_type = value_t::object; j.m_type = value_t::object;
j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj)); j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
j.set_parent(j, true);
j.assert_invariant(); j.assert_invariant();
} }
}; };
......
...@@ -236,6 +236,7 @@ class json_sax_dom_parser ...@@ -236,6 +236,7 @@ class json_sax_dom_parser
bool end_object() bool end_object()
{ {
ref_stack.back()->set_parent(*ref_stack.back(), true);
ref_stack.pop_back(); ref_stack.pop_back();
return true; return true;
} }
...@@ -254,6 +255,7 @@ class json_sax_dom_parser ...@@ -254,6 +255,7 @@ class json_sax_dom_parser
bool end_array() bool end_array()
{ {
ref_stack.back()->set_parent(*ref_stack.back(), true);
ref_stack.pop_back(); ref_stack.pop_back();
return true; return true;
} }
...@@ -298,18 +300,12 @@ class json_sax_dom_parser ...@@ -298,18 +300,12 @@ class json_sax_dom_parser
if (ref_stack.back()->is_array()) if (ref_stack.back()->is_array())
{ {
ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v)); ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
#if JSON_DIAGNOSTICS
ref_stack.back()->m_value.array->back().m_parent = ref_stack.back();
#endif
return &(ref_stack.back()->m_value.array->back()); return &(ref_stack.back()->m_value.array->back());
} }
JSON_ASSERT(ref_stack.back()->is_object()); JSON_ASSERT(ref_stack.back()->is_object());
JSON_ASSERT(object_element); JSON_ASSERT(object_element);
*object_element = BasicJsonType(std::forward<Value>(v)); *object_element = BasicJsonType(std::forward<Value>(v));
#if JSON_DIAGNOSTICS
object_element->m_parent = ref_stack.back();
#endif
return object_element; return object_element;
} }
...@@ -432,10 +428,17 @@ class json_sax_dom_callback_parser ...@@ -432,10 +428,17 @@ class json_sax_dom_callback_parser
bool end_object() bool end_object()
{ {
if (ref_stack.back() && !callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) if (ref_stack.back())
{ {
// discard object if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
*ref_stack.back() = discarded; {
// discard object
*ref_stack.back() = discarded;
}
else
{
ref_stack.back()->set_parent(*ref_stack.back(), true);
}
} }
JSON_ASSERT(!ref_stack.empty()); JSON_ASSERT(!ref_stack.empty());
...@@ -483,7 +486,11 @@ class json_sax_dom_callback_parser ...@@ -483,7 +486,11 @@ class json_sax_dom_callback_parser
if (ref_stack.back()) if (ref_stack.back())
{ {
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
if (!keep) if (keep)
{
ref_stack.back()->set_parent(*ref_stack.back(), true);
}
else
{ {
// discard array // discard array
*ref_stack.back() = discarded; *ref_stack.back() = discarded;
...@@ -582,9 +589,6 @@ class json_sax_dom_callback_parser ...@@ -582,9 +589,6 @@ class json_sax_dom_callback_parser
if (ref_stack.back()->is_array()) if (ref_stack.back()->is_array())
{ {
ref_stack.back()->m_value.array->emplace_back(std::move(value)); ref_stack.back()->m_value.array->emplace_back(std::move(value));
#if JSON_DIAGNOSTICS
ref_stack.back()->m_value.array->back().m_parent = ref_stack.back();
#endif
return {true, &(ref_stack.back()->m_value.array->back())}; return {true, &(ref_stack.back()->m_value.array->back())};
} }
...@@ -602,9 +606,6 @@ class json_sax_dom_callback_parser ...@@ -602,9 +606,6 @@ class json_sax_dom_callback_parser
JSON_ASSERT(object_element); JSON_ASSERT(object_element);
*object_element = std::move(value); *object_element = std::move(value);
#if JSON_DIAGNOSTICS
object_element->m_parent = ref_stack.back();
#endif
return {true, object_element}; return {true, object_element};
} }
......
...@@ -90,7 +90,6 @@ class parser ...@@ -90,7 +90,6 @@ class parser
{ {
json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions); json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
sax_parse_internal(&sdp); sax_parse_internal(&sdp);
result.assert_invariant();
// in strict mode, input must be completely read // in strict mode, input must be completely read
if (strict && (get_token() != token_type::end_of_input)) if (strict && (get_token() != token_type::end_of_input))
...@@ -119,7 +118,6 @@ class parser ...@@ -119,7 +118,6 @@ class parser
{ {
json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions); json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
sax_parse_internal(&sdp); sax_parse_internal(&sdp);
result.assert_invariant();
// in strict mode, input must be completely read // in strict mode, input must be completely read
if (strict && (get_token() != token_type::end_of_input)) if (strict && (get_token() != token_type::end_of_input))
...@@ -137,6 +135,8 @@ class parser ...@@ -137,6 +135,8 @@ class parser
return; return;
} }
} }
result.assert_invariant();
} }
/*! /*!
......
...@@ -1233,13 +1233,29 @@ class basic_json ...@@ -1233,13 +1233,29 @@ class basic_json
invariant. Furthermore, it has to be called each time the type of a 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 value is changed, because the invariant expresses a relationship between
@a m_type and @a m_value. @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::object || m_value.object != nullptr);
JSON_ASSERT(m_type != value_t::array || m_value.array != 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::string || m_value.string != nullptr);
JSON_ASSERT(m_type != value_t::binary || m_value.binary != 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) reference set_parent(reference j, bool recursive)
...@@ -1497,6 +1513,7 @@ class basic_json ...@@ -1497,6 +1513,7 @@ class basic_json
std::forward<CompatibleType>(val)))) std::forward<CompatibleType>(val))))
{ {
JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val)); JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
set_parent(*this, true);
assert_invariant(); assert_invariant();
} }
...@@ -1575,6 +1592,7 @@ class basic_json ...@@ -1575,6 +1592,7 @@ class basic_json
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
set_parent(*this, true);
assert_invariant(); assert_invariant();
} }
...@@ -1689,10 +1707,9 @@ class basic_json ...@@ -1689,10 +1707,9 @@ class basic_json
for (auto& element_ref : init) for (auto& element_ref : init)
{ {
auto element = element_ref.moved_or_copied(); auto element = element_ref.moved_or_copied();
auto res = m_value.object->emplace( m_value.object->emplace(
std::move(*((*element.m_value.array)[0].m_value.string)), std::move(*((*element.m_value.array)[0].m_value.string)),
std::move((*element.m_value.array)[1])); std::move((*element.m_value.array)[1]));
set_parent(res.first->second, false);
} }
} }
else else
...@@ -1700,9 +1717,9 @@ class basic_json ...@@ -1700,9 +1717,9 @@ class basic_json
// the initializer list describes an array -> create array // the initializer list describes an array -> create array
m_type = value_t::array; m_type = value_t::array;
m_value.array = create<array_t>(init.begin(), init.end()); m_value.array = create<array_t>(init.begin(), init.end());
set_parent(*this, true);
} }
set_parent(*this, true);
assert_invariant(); assert_invariant();
} }
...@@ -2045,7 +2062,6 @@ class basic_json ...@@ -2045,7 +2062,6 @@ class basic_json
{ {
m_value.object = create<object_t>(first.m_it.object_iterator, m_value.object = create<object_t>(first.m_it.object_iterator,
last.m_it.object_iterator); last.m_it.object_iterator);
set_parent(*this, true);
break; break;
} }
...@@ -2053,7 +2069,6 @@ class basic_json ...@@ -2053,7 +2069,6 @@ class basic_json
{ {
m_value.array = create<array_t>(first.m_it.array_iterator, m_value.array = create<array_t>(first.m_it.array_iterator,
last.m_it.array_iterator); last.m_it.array_iterator);
set_parent(*this, true);
break; break;
} }
...@@ -2067,6 +2082,7 @@ class basic_json ...@@ -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())); 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(); assert_invariant();
} }
...@@ -2116,14 +2132,12 @@ class basic_json ...@@ -2116,14 +2132,12 @@ class basic_json
case value_t::object: case value_t::object:
{ {
m_value = *other.m_value.object; m_value = *other.m_value.object;
set_parent(*this, true);
break; break;
} }
case value_t::array: case value_t::array:
{ {
m_value = *other.m_value.array; m_value = *other.m_value.array;
set_parent(*this, true);
break; break;
} }
...@@ -2167,6 +2181,7 @@ class basic_json ...@@ -2167,6 +2181,7 @@ class basic_json
break; break;
} }
set_parent(*this, true);
assert_invariant(); assert_invariant();
} }
...@@ -2201,7 +2216,7 @@ class basic_json ...@@ -2201,7 +2216,7 @@ class basic_json
m_value(std::move(other.m_value)) m_value(std::move(other.m_value))
{ {
// check that passed value is valid // check that passed value is valid
other.assert_invariant(); other.assert_invariant(false);
// invalidate payload // invalidate payload
other.m_type = value_t::null; other.m_type = value_t::null;
...@@ -2248,6 +2263,7 @@ class basic_json ...@@ -2248,6 +2263,7 @@ class basic_json
swap(m_type, other.m_type); swap(m_type, other.m_type);
swap(m_value, other.m_value); swap(m_value, other.m_value);
set_parent(*this, true);
assert_invariant(); assert_invariant();
return *this; return *this;
} }
...@@ -2269,7 +2285,7 @@ class basic_json ...@@ -2269,7 +2285,7 @@ class basic_json
*/ */
~basic_json() noexcept ~basic_json() noexcept
{ {
assert_invariant(); assert_invariant(false);
m_value.destroy(m_type); m_value.destroy(m_type);
} }
...@@ -5990,6 +6006,8 @@ class basic_json ...@@ -5990,6 +6006,8 @@ class basic_json
{ {
std::swap(m_type, other.m_type); std::swap(m_type, other.m_type);
std::swap(m_value, other.m_value); std::swap(m_value, other.m_value);
set_parent(*this, true);
assert_invariant(); assert_invariant();
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment