Compare commits

...
Author SHA1 Message Date
Niels Lohmann 1a2828f36c Iterator: test for objects before arrays
#5835 replaced the switch on the value type in operator*, operator->,
operator++, operator-- and operator== of iter_impl with an if chain that
tests for an array first. Every step over an object then pays for a
failed test and a taken branch: with the iterator inlined, walking
twitter.json took 14% more cycles than with 3.12.0, and citm_catalog.json
3.5% more.

Test for objects first. Walking every value of the three files now
takes fewer cycles than with 3.12.0 (Apple M1 Max, Apple clang 21):
citm_catalog.json 1.21x, twitter.json 1.04x, canada.json 1.17x as fast.
canada.json, which holds only arrays, gives back part of the gain of
#5835 (develop: 1.62x); the other orders tried (arrays first without
hints, objects first without hints, a switch) each left one of the
files slower than 3.12.0.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-07 23:44:11 +01:00
2 changed files with 66 additions and 58 deletions

No files matched your search

+33 -29
View File
@@ -277,18 +277,22 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array)) // objects are tested before arrays here and in the other operators:
{ // with arrays first, walking a document of objects such as
JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); // twitter.json took 14% more cycles than with 3.12.0's switch; with
return *m_it.array_iterator; // objects first, no document walks slower than with 3.12.0
}
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object))
{ {
JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
return m_it.object_iterator->second; return m_it.object_iterator->second;
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
return *m_it.array_iterator;
}
// neither array nor object: a primitive value (null has no value to point to) // neither array nor object: a primitive value (null has no value to point to)
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type != value_t::null && m_it.primitive_iterator.is_begin())) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type != value_t::null && m_it.primitive_iterator.is_begin()))
{ {
@@ -306,18 +310,18 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
return &*m_it.array_iterator;
}
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object))
{ {
JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
return &(m_it.object_iterator->second); return &(m_it.object_iterator->second);
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
return &*m_it.array_iterator;
}
// neither array nor object: a primitive value // neither array nor object: a primitive value
if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
{ {
@@ -346,18 +350,18 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
++m_it.array_iterator;
return *this;
}
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object))
{ {
std::advance(m_it.object_iterator, 1); std::advance(m_it.object_iterator, 1);
return *this; return *this;
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
++m_it.array_iterator;
return *this;
}
// neither array nor object: a primitive value // neither array nor object: a primitive value
++m_it.primitive_iterator; ++m_it.primitive_iterator;
return *this; return *this;
@@ -382,18 +386,18 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
--m_it.array_iterator;
return *this;
}
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object))
{ {
std::advance(m_it.object_iterator, -1); std::advance(m_it.object_iterator, -1);
return *this; return *this;
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
--m_it.array_iterator;
return *this;
}
// neither array nor object: a primitive value // neither array nor object: a primitive value
--m_it.primitive_iterator; --m_it.primitive_iterator;
return *this; return *this;
@@ -415,16 +419,16 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
return true; return true;
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
return (m_it.array_iterator == other.m_it.array_iterator);
}
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object))
{ {
return (m_it.object_iterator == other.m_it.object_iterator); return (m_it.object_iterator == other.m_it.object_iterator);
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
return (m_it.array_iterator == other.m_it.array_iterator);
}
// neither array nor object: a primitive value // neither array nor object: a primitive value
return (m_it.primitive_iterator == other.m_it.primitive_iterator); return (m_it.primitive_iterator == other.m_it.primitive_iterator);
} }
+33 -29
View File
@@ -24506,18 +24506,22 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array)) // objects are tested before arrays here and in the other operators:
{ // with arrays first, walking a document of objects such as
JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); // twitter.json took 14% more cycles than with 3.12.0's switch; with
return *m_it.array_iterator; // objects first, no document walks slower than with 3.12.0
}
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object))
{ {
JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
return m_it.object_iterator->second; return m_it.object_iterator->second;
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
return *m_it.array_iterator;
}
// neither array nor object: a primitive value (null has no value to point to) // neither array nor object: a primitive value (null has no value to point to)
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type != value_t::null && m_it.primitive_iterator.is_begin())) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type != value_t::null && m_it.primitive_iterator.is_begin()))
{ {
@@ -24535,18 +24539,18 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
return &*m_it.array_iterator;
}
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object))
{ {
JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
return &(m_it.object_iterator->second); return &(m_it.object_iterator->second);
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
return &*m_it.array_iterator;
}
// neither array nor object: a primitive value // neither array nor object: a primitive value
if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
{ {
@@ -24575,18 +24579,18 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
++m_it.array_iterator;
return *this;
}
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object))
{ {
std::advance(m_it.object_iterator, 1); std::advance(m_it.object_iterator, 1);
return *this; return *this;
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
++m_it.array_iterator;
return *this;
}
// neither array nor object: a primitive value // neither array nor object: a primitive value
++m_it.primitive_iterator; ++m_it.primitive_iterator;
return *this; return *this;
@@ -24611,18 +24615,18 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
--m_it.array_iterator;
return *this;
}
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object))
{ {
std::advance(m_it.object_iterator, -1); std::advance(m_it.object_iterator, -1);
return *this; return *this;
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
--m_it.array_iterator;
return *this;
}
// neither array nor object: a primitive value // neither array nor object: a primitive value
--m_it.primitive_iterator; --m_it.primitive_iterator;
return *this; return *this;
@@ -24644,16 +24648,16 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
return true; return true;
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
return (m_it.array_iterator == other.m_it.array_iterator);
}
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object))
{ {
return (m_it.object_iterator == other.m_it.object_iterator); return (m_it.object_iterator == other.m_it.object_iterator);
} }
if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array))
{
return (m_it.array_iterator == other.m_it.array_iterator);
}
// neither array nor object: a primitive value // neither array nor object: a primitive value
return (m_it.primitive_iterator == other.m_it.primitive_iterator); return (m_it.primitive_iterator == other.m_it.primitive_iterator);
} }