json_view: exceptions name the path and the bytes of the value

With JSON_DIAGNOSTICS and JSON_DIAGNOSTIC_POSITIONS, the exceptions of views
now carry the same context as those of basic_json: "(/path) " and
"(bytes a-b) " in front of the message, in basic_json's format (with
JSON_DIAGNOSTICS, no context for the root). Before, views threw without any
context, and since get<T>() reads the view directly, conversions had lost
even the relative path they used to get through materialize().

The throw helpers of detail/view/errors.hpp take an error_site (document
and node; empty without the two macros). Only on the error path, the path is
found by descending from the root (pruned by subtree extent before the first
edit, a full walk through edited sequences after), and the bytes as
materialize() sets them (position_source; a container's end by following the
chain of last elements and scanning to the closing brackets). from_json() for
views and the strict enum macro put the same context in front through
exception_prefix(). Iterators keep their container only under the two
macros, for key(). Without the macros, the accessors compile to the same
code as before.

Tests compare every value's exceptions with those of the parsed or
materialized basic_json value, including edited documents; the checks that
were disabled under the two macros run again.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-30 21:51:23 +01:00
1 parent 755bb16d7a
commit 8ac510b8d3
25 files changed
+1571 -710

No files matched your search

+24 -3
View File
@@ -67,9 +67,17 @@ class view_iterator
/// @param[in] pos the element, or the key of the member
/// @param[in] object whether pos is a key (its value is the next node)
view_iterator(const document_data* d, const node* pos, bool object) noexcept
/// @param[in] container the value iterated over (the context of the
/// exceptions, kept only with JSON_DIAGNOSTICS or
/// JSON_DIAGNOSTIC_POSITIONS)
view_iterator(const document_data* d, const node* pos, bool object, const node* container) noexcept
: m_doc(d), m_pos(pos), m_value_offset(object ? 1 : 0)
{}
#if JSON_DIAGNOSTICS || JSON_DIAGNOSTIC_POSITIONS
, m_container(container)
#endif
{
static_cast<void>(container);
}
NLOHMANN_VIEW_ALWAYS_INLINE View operator*() const noexcept
{
@@ -110,7 +118,7 @@ class view_iterator
{
if (NLOHMANN_VIEW_UNLIKELY(m_value_offset == 0))
{
throw_invalid_iterator(exception_id::iterator_key_not_object, "cannot use key() for non-object iterators");
throw_invalid_iterator(site(), exception_id::iterator_key_not_object, "cannot use key() for non-object iterators");
}
return string_view_t(m_doc->str(*m_pos), m_pos->len);
}
@@ -127,9 +135,22 @@ class view_iterator
}
private:
/// the value iterated over, as the context of an exception
error_site site() const noexcept
{
#if JSON_DIAGNOSTICS || JSON_DIAGNOSTIC_POSITIONS
return error_site(m_doc, m_container);
#else
return error_site();
#endif
}
const document_data* m_doc = nullptr;
const node* m_pos = nullptr;
std::size_t m_value_offset = 0; ///< 1 for objects: the value follows its key
#if JSON_DIAGNOSTICS || JSON_DIAGNOSTIC_POSITIONS
const node* m_container = nullptr;
#endif
};
/*!