1
0
mirror of https://github.com/nlohmann/json synced 2025-01-15 03:30:04 +00:00

🚧 better diagnostics

This commit is contained in:
Niels Lohmann 2021-01-01 17:23:10 +01:00
parent 68c3696382
commit a4d491e22d
No known key found for this signature in database
GPG Key ID: 7F3CEA63AE251B69
2 changed files with 222 additions and 2 deletions

View File

@ -1642,6 +1642,9 @@ class basic_json
std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref) std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)
{ {
auto element = element_ref.moved_or_copied(); auto element = element_ref.moved_or_copied();
#ifdef JSON_DIAGNOSTICS
(*element.m_value.array)[1].m_parent = this;
#endif
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]));
@ -1652,6 +1655,12 @@ 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());
#ifdef JSON_DIAGNOSTICS
for (auto& element : *m_value.array)
{
element.m_parent = this;
}
#endif
} }
assert_invariant(); assert_invariant();
@ -2696,6 +2705,49 @@ class basic_json
/// @} /// @}
private: private:
#ifdef JSON_DIAGNOSTICS
std::string diagnostics()
{
std::string result;
for (basic_json* current = this; current->m_parent != nullptr; current = current->m_parent)
{
switch (current->m_parent->type())
{
case value_t::array:
{
for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i)
{
if (current->m_parent->m_value.array->operator[](i) == *current)
{
result = "/" + std::to_string(i) + result;
continue;
}
}
break;
}
case value_t::object:
{
for (auto it : *current->m_parent->m_value.object)
{
if (it.second == *current)
{
result = "/" + it.first + result;
continue;
}
}
break;
}
default:
break;
}
}
return result;
}
#endif
////////////////// //////////////////
// value access // // value access //
////////////////// //////////////////
@ -3318,7 +3370,13 @@ class basic_json
{ {
JSON_TRY JSON_TRY
{ {
#ifdef JSON_DIAGNOSTICS
reference result = m_value.array->at(idx);
result.m_parent = this;
return result;
#else
return m_value.array->at(idx); return m_value.array->at(idx);
#endif
} }
JSON_CATCH (std::out_of_range&) JSON_CATCH (std::out_of_range&)
{ {
@ -3416,7 +3474,13 @@ class basic_json
{ {
JSON_TRY JSON_TRY
{ {
#ifdef JSON_DIAGNOSTICS
reference result = m_value.object->at(key);
result.m_parent = this;
return result;
#else
return m_value.object->at(key); return m_value.object->at(key);
#endif
} }
JSON_CATCH (std::out_of_range&) JSON_CATCH (std::out_of_range&)
{ {
@ -3525,9 +3589,18 @@ class basic_json
m_value.array->insert(m_value.array->end(), m_value.array->insert(m_value.array->end(),
idx - m_value.array->size() + 1, idx - m_value.array->size() + 1,
basic_json()); basic_json());
#ifdef JSON_DIAGNOSTICS
m_value.array->back().m_parent = this;
#endif
} }
#ifdef JSON_DIAGNOSTICS
reference result = m_value.array->operator[](idx);
result.m_parent = this;
return result;
#else
return m_value.array->operator[](idx); return m_value.array->operator[](idx);
#endif
} }
JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name())));
@ -3603,7 +3676,13 @@ class basic_json
// operator[] only works for objects // operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
#ifdef JSON_DIAGNOSTICS
reference result = m_value.object->operator[](key);
result.m_parent = this;
return result;
#else
return m_value.object->operator[](key); return m_value.object->operator[](key);
#endif
} }
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
@ -3693,7 +3772,13 @@ class basic_json
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
#ifdef JSON_DIAGNOSTICS
reference result = m_value.object->operator[](key);
result.m_parent = this;
return result;
#else
return m_value.object->operator[](key); return m_value.object->operator[](key);
#endif
} }
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
@ -5249,6 +5334,9 @@ class basic_json
// add element to array (move semantics) // add element to array (move semantics)
m_value.array->push_back(std::move(val)); m_value.array->push_back(std::move(val));
#ifdef JSON_DIAGNOSTICS
m_value.array->back().m_parent = this;
#endif
// if val is moved from, basic_json move constructor marks it null so we do not call the destructor // if val is moved from, basic_json move constructor marks it null so we do not call the destructor
} }
@ -5284,6 +5372,9 @@ class basic_json
// add element to array // add element to array
m_value.array->push_back(val); m_value.array->push_back(val);
#ifdef JSON_DIAGNOSTICS
m_value.array->back().m_parent = this;
#endif
} }
/*! /*!
@ -5332,8 +5423,13 @@ class basic_json
assert_invariant(); assert_invariant();
} }
// add element to array // add element to object
#ifdef JSON_DIAGNOSTICS
auto res = m_value.object->insert(val);
res.first->second.m_parent = this;
#else
m_value.object->insert(val); m_value.object->insert(val);
#endif
} }
/*! /*!
@ -5437,9 +5533,18 @@ class basic_json
// add element to array (perfect forwarding) // add element to array (perfect forwarding)
#ifdef JSON_HAS_CPP_17 #ifdef JSON_HAS_CPP_17
#ifdef JSON_DIAGNOSTICS
reference result = m_value.array->emplace_back(std::forward<Args>(args)...);
result.m_parent = this;
return result;
#else
return m_value.array->emplace_back(std::forward<Args>(args)...); return m_value.array->emplace_back(std::forward<Args>(args)...);
#endif
#else #else
m_value.array->emplace_back(std::forward<Args>(args)...); m_value.array->emplace_back(std::forward<Args>(args)...);
#ifdef JSON_DIAGNOSTICS
m_value.array->back().m_parent = this;
#endif
return m_value.array->back(); return m_value.array->back();
#endif #endif
} }
@ -6967,6 +7072,11 @@ class basic_json
/// the value of the current element /// the value of the current element
json_value m_value = {}; json_value m_value = {};
#ifdef JSON_DIAGNOSTICS
/// a pointer to a parent value (for debugging purposes)
basic_json* m_parent = nullptr;
#endif
////////////////////////////////////////// //////////////////////////////////////////
// binary serialization/deserialization // // binary serialization/deserialization //
////////////////////////////////////////// //////////////////////////////////////////

View File

@ -18266,6 +18266,9 @@ class basic_json
std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref) std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)
{ {
auto element = element_ref.moved_or_copied(); auto element = element_ref.moved_or_copied();
#ifdef JSON_DIAGNOSTICS
(*element.m_value.array)[1].m_parent = this;
#endif
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]));
@ -18276,6 +18279,12 @@ 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());
#ifdef JSON_DIAGNOSTICS
for (auto& element : *m_value.array)
{
element.m_parent = this;
}
#endif
} }
assert_invariant(); assert_invariant();
@ -19320,6 +19329,49 @@ class basic_json
/// @} /// @}
private: private:
#ifdef JSON_DIAGNOSTICS
std::string diagnostics()
{
std::string result;
for (basic_json* current = this; current->m_parent != nullptr; current = current->m_parent)
{
switch (current->m_parent->type())
{
case value_t::array:
{
for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i)
{
if (current->m_parent->m_value.array->operator[](i) == *current)
{
result = "/" + std::to_string(i) + result;
continue;
}
}
break;
}
case value_t::object:
{
for (auto it : *current->m_parent->m_value.object)
{
if (it.second == *current)
{
result = "/" + it.first + result;
continue;
}
}
break;
}
default:
break;
}
}
return result;
}
#endif
////////////////// //////////////////
// value access // // value access //
////////////////// //////////////////
@ -19942,7 +19994,13 @@ class basic_json
{ {
JSON_TRY JSON_TRY
{ {
#ifdef JSON_DIAGNOSTICS
reference result = m_value.array->at(idx);
result.m_parent = this;
return result;
#else
return m_value.array->at(idx); return m_value.array->at(idx);
#endif
} }
JSON_CATCH (std::out_of_range&) JSON_CATCH (std::out_of_range&)
{ {
@ -20040,7 +20098,13 @@ class basic_json
{ {
JSON_TRY JSON_TRY
{ {
#ifdef JSON_DIAGNOSTICS
reference result = m_value.object->at(key);
result.m_parent = this;
return result;
#else
return m_value.object->at(key); return m_value.object->at(key);
#endif
} }
JSON_CATCH (std::out_of_range&) JSON_CATCH (std::out_of_range&)
{ {
@ -20149,9 +20213,18 @@ class basic_json
m_value.array->insert(m_value.array->end(), m_value.array->insert(m_value.array->end(),
idx - m_value.array->size() + 1, idx - m_value.array->size() + 1,
basic_json()); basic_json());
#ifdef JSON_DIAGNOSTICS
m_value.array->back().m_parent = this;
#endif
} }
#ifdef JSON_DIAGNOSTICS
reference result = m_value.array->operator[](idx);
result.m_parent = this;
return result;
#else
return m_value.array->operator[](idx); return m_value.array->operator[](idx);
#endif
} }
JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name())));
@ -20227,7 +20300,13 @@ class basic_json
// operator[] only works for objects // operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
#ifdef JSON_DIAGNOSTICS
reference result = m_value.object->operator[](key);
result.m_parent = this;
return result;
#else
return m_value.object->operator[](key); return m_value.object->operator[](key);
#endif
} }
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
@ -20317,7 +20396,13 @@ class basic_json
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
#ifdef JSON_DIAGNOSTICS
reference result = m_value.object->operator[](key);
result.m_parent = this;
return result;
#else
return m_value.object->operator[](key); return m_value.object->operator[](key);
#endif
} }
JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
@ -21873,6 +21958,9 @@ class basic_json
// add element to array (move semantics) // add element to array (move semantics)
m_value.array->push_back(std::move(val)); m_value.array->push_back(std::move(val));
#ifdef JSON_DIAGNOSTICS
m_value.array->back().m_parent = this;
#endif
// if val is moved from, basic_json move constructor marks it null so we do not call the destructor // if val is moved from, basic_json move constructor marks it null so we do not call the destructor
} }
@ -21908,6 +21996,9 @@ class basic_json
// add element to array // add element to array
m_value.array->push_back(val); m_value.array->push_back(val);
#ifdef JSON_DIAGNOSTICS
m_value.array->back().m_parent = this;
#endif
} }
/*! /*!
@ -21956,8 +22047,13 @@ class basic_json
assert_invariant(); assert_invariant();
} }
// add element to array // add element to object
#ifdef JSON_DIAGNOSTICS
auto res = m_value.object->insert(val);
res.first->second.m_parent = this;
#else
m_value.object->insert(val); m_value.object->insert(val);
#endif
} }
/*! /*!
@ -22061,9 +22157,18 @@ class basic_json
// add element to array (perfect forwarding) // add element to array (perfect forwarding)
#ifdef JSON_HAS_CPP_17 #ifdef JSON_HAS_CPP_17
#ifdef JSON_DIAGNOSTICS
reference result = m_value.array->emplace_back(std::forward<Args>(args)...);
result.m_parent = this;
return result;
#else
return m_value.array->emplace_back(std::forward<Args>(args)...); return m_value.array->emplace_back(std::forward<Args>(args)...);
#endif
#else #else
m_value.array->emplace_back(std::forward<Args>(args)...); m_value.array->emplace_back(std::forward<Args>(args)...);
#ifdef JSON_DIAGNOSTICS
m_value.array->back().m_parent = this;
#endif
return m_value.array->back(); return m_value.array->back();
#endif #endif
} }
@ -23591,6 +23696,11 @@ class basic_json
/// the value of the current element /// the value of the current element
json_value m_value = {}; json_value m_value = {};
#ifdef JSON_DIAGNOSTICS
/// a pointer to a parent value (for debugging purposes)
basic_json* m_parent = nullptr;
#endif
////////////////////////////////////////// //////////////////////////////////////////
// binary serialization/deserialization // // binary serialization/deserialization //
////////////////////////////////////////// //////////////////////////////////////////