Merge branch 'json-view/21-images' into json-view/22-view-dump-fast

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-09 23:51:41 +02:00
commit e9dd4d2dae
25 files changed
+378 -285

No files matched your search

+35 -50
View File
@@ -2939,8 +2939,8 @@ NLOHMANN_JSON_NAMESPACE_END
// large objects). An object with document_data::index_min_members members or
// more gets an open-addressing table after parsing; its node stores the
// number of the table (1-based) in `extra`. A slot holds the offset of a key
// node from its object node (0: empty). Of duplicate keys, the last is kept,
// as for the linear search, and as basic_json::parse() does.
// node from its object node (0: empty). Of duplicate keys, the first is kept,
// as for the linear search.
//
// The hash is not seeded, so keys chosen to collide could make the build
// quadratic. A key therefore sits at most index_max_displacement slots away
@@ -3009,8 +3009,7 @@ inline void build_object_index(document_data& d, node* obj)
const node* const other = obj + slots[i];
if (other->len == k->len && (k->len == 0 || std::memcmp(d.str(*other), key, k->len) == 0))
{
duplicate = true; // keep the last: the key's slot now leads to this member
slots[i] = static_cast<std::uint32_t>(k - obj);
duplicate = true; // keep the first
break;
}
if (++distance > index_max_displacement)
@@ -3047,7 +3046,7 @@ inline void build_object_indexes(document_data& d)
}
}
/// the key node of the last member with this key of an indexed object, or
/// the key node of the first member with this key of an indexed object, or
/// nullptr
inline const node* find_indexed(const document_data& d, const node* obj, const char* key, std::size_t n) noexcept
{
@@ -3141,9 +3140,10 @@ class short_key
std::uint64_t m_b = 0;
};
/// the key node of the last member of an object with the given key, or
/// nullptr (the last one, as materialize() and parse() keep it); most keys are
/// rejected by their length, from the index alone
/// the key node of the first member of an object with the given key, or
/// nullptr (the search stops at the first match; materialize() and parse()
/// keep the last value of a duplicate key instead); most keys are rejected by
/// their length, from the index alone
template<bool Editable>
const node* find_member(const document_data& d, const node* object, const char* key, std::size_t n) noexcept
{
@@ -3154,7 +3154,6 @@ const node* find_member(const document_data& d, const node* object, const char*
}
const node* const end = nav::end(d, object);
const auto* const k = reinterpret_cast<const unsigned char*>(key); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
const node* last = nullptr;
if (NLOHMANN_VIEW_LIKELY(n <= 16))
{
const short_key probe(k, n);
@@ -3162,19 +3161,19 @@ const node* find_member(const document_data& d, const node* object, const char*
{
if (m->len == n && probe.matches(reinterpret_cast<const unsigned char*>(d.str(*m)))) // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
{
last = m;
return m;
}
}
return last;
return nullptr;
}
for (const node* m = nav::first(d, object); m != end; m = document_data::after(m + 1))
{
if (m->len == n && std::memcmp(d.str(*m), key, n) == 0)
{
last = m;
return m;
}
}
return last;
return nullptr;
}
/// whether an integer type is accepted as an array index by the view's
@@ -3361,23 +3360,25 @@ class editor
{
become_empty(o, value_t::object);
}
// an existing member: assign the one that lookups find (the last
// one, should the key occur more than once), and drop the others, so
// that lookups, iteration, and materialize() agree. The key stays at
// the position of its first occurrence, as materialize() puts it.
// an existing member: assign it (and drop later duplicates, so that
// lookups, iteration, and materialize() agree)
node* slot = nullptr;
std::size_t matches = 0;
bool duplicates = false;
for (const node* k = nav::first(m_doc, o), *end = nav::end(m_doc, o); k != end; k = document_data::after(k + 1))
{
if (key_equals(*k, key))
{
if (slot != nullptr)
{
duplicates = true;
break;
}
slot = const_cast<node*>(nav::value(k + 1)); // NOLINT(cppcoreguidelines-pro-type-const-cast): the nodes belong to this document
++matches;
}
}
if (slot != nullptr)
{
if (matches > 1)
if (duplicates)
{
erase_members(o, key, true);
}
@@ -3523,38 +3524,27 @@ class editor
return k.len == key.size() && (key.size() == 0 || std::memcmp(m_doc.str(k), key.data(), key.size()) == 0);
}
/// Remove the members with this key from an object: all of them, or all
/// but one. That one stays where the first occurrence is, but holds the
/// value of the last (the one that lookups find, which views may refer to).
std::size_t erase_members(node* o, string_view_t key, bool keep_one)
/// remove the members with this key (all, or all but the first) from an object
std::size_t erase_members(node* o, string_view_t key, bool keep_first)
{
node* const h = block_of(m_doc, o, 0);
node last_value{}; // the entry of the value of the last member
node* const end = h + h->next;
if (keep_one)
{
for (node* r = h + 1; r != end; r += 2)
{
if (key_equals(*r, key))
{
last_value = r[1];
}
}
}
node* w = h + 1;
std::size_t erased = 0;
bool kept = false;
for (node* r = h + 1; r != end; r += 2)
for (node* r = h + 1, *end = h + h->next; r != end; r += 2)
{
const bool match = key_equals(*r, key);
if (match && (kept || !keep_one))
if (match && (kept || !keep_first))
{
++erased;
continue;
}
w[0] = r[0];
w[1] = match ? last_value : r[1];
kept = kept || match;
if (w != r)
{
w[0] = r[0];
w[1] = r[1];
}
w += 2;
}
h->next = static_cast<std::uint32_t>(w - h);
@@ -5835,11 +5825,6 @@ class output_buffer
{
const auto size = static_cast<std::size_t>(m_pos - m_out.data());
m_out.resize(size);
// do not keep a buffer that was sized for a much larger output
if (m_out.capacity() > 1024 && m_out.capacity() / 2 > size)
{
m_out.shrink_to_fit();
}
}
NLOHMANN_VIEW_ALWAYS_INLINE void reserve(std::size_t n)
@@ -7151,7 +7136,7 @@ class basic_json_view
// element access //
////////////////////
/// the value of the member with this key (the last one, should the key
/// the value of the member with this key (the first one, should the key
/// occur more than once); a discarded view if there is none, or if this
/// is a discarded view (so that v["a"]["b"] is safe). Throws type_error.305
/// if this is any other value but an object.
@@ -7215,7 +7200,7 @@ class basic_json_view
return detail::view::resolve_pointer(*this, detail::json_pointer_access::reference_tokens(ptr), detail::view::pointer_mode::unchecked);
}
/// the value of the member with this key (the last one, should the key
/// the value of the member with this key (the first one, should the key
/// occur more than once). Throws type_error.304 if this is not an object,
/// and out_of_range.403 if there is no such member.
basic_json_view at(string_view_t key) const
@@ -7273,7 +7258,7 @@ class basic_json_view
}
/// the member with this key converted to T, or the default value if there
/// is no such member (the last one, should the key occur more than
/// is no such member (the first one, should the key occur more than
/// once). Throws type_error.306 if this is not an object.
template < typename T, typename std::enable_if < !std::is_same<typename std::decay<T>::type, const char*>::value, int >::type = 0 >
T value(string_view_t key, const T& default_value) const
@@ -7338,7 +7323,7 @@ class basic_json_view
// lookup //
////////////
/// an iterator to the member with this key (the last one, should the
/// an iterator to the member with this key (the first one, should the
/// key occur more than once), or end(); end() also for non-objects
iterator find(string_view_t key) const
{
@@ -7673,7 +7658,7 @@ class basic_json_view
return (std::min)(m_doc->size - m_node->off, static_cast<std::size_t>(1024) + nodes * 16);
}
/// the value of the last member with this key, or a discarded view
/// the value of the first member with this key, or a discarded view
/// (object required)
NLOHMANN_VIEW_ALWAYS_INLINE basic_json_view lookup(string_view_t key) const noexcept
{