From 210a398ce80f63fff9ebf189f4a447eda5a10c2c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 23 Oct 2026 10:20:06 +0200 Subject: [PATCH] 1.7/2.4.9: iter_impl, iteration_proxy: drop primitive case lists, share compare preamble (#5891) Object and array stay the first branches; everything else is the primitive case. operator== and operator< share the different-container check. Signed-off-by: Niels Lohmann --- .../nlohmann/detail/iterators/iter_impl.hpp | 179 +++++++----------- .../detail/iterators/iteration_proxy.hpp | 38 ++-- 2 files changed, 78 insertions(+), 139 deletions(-) diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index 120c1b893..84a850356 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -108,33 +108,18 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci { JSON_ASSERT(m_object != nullptr); - switch (m_object->m_data.m_type) + if (m_object->is_object()) { - case value_t::object: - { - m_it.object_iterator = typename object_t::iterator(); - break; - } - - case value_t::array: - { - m_it.array_iterator = typename array_t::iterator(); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator = primitive_iterator_t(); - break; - } + m_it.object_iterator = typename object_t::iterator(); + } + else if (m_object->is_array()) + { + m_it.array_iterator = typename array_t::iterator(); + } + else + { + // primitive (is_primitive(), including discarded) + m_it.primitive_iterator = primitive_iterator_t(); } } @@ -249,33 +234,28 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci { JSON_ASSERT(m_object != nullptr); - switch (m_object->m_data.m_type) + if (m_object->is_object()) { - case value_t::object: - { - m_it.object_iterator = m_object->m_data.m_value.object->end(); - break; - } + m_it.object_iterator = m_object->m_data.m_value.object->end(); + } + else if (m_object->is_array()) + { + m_it.array_iterator = m_object->m_data.m_value.array->end(); + } + else + { + // primitive (is_primitive(), including discarded) + m_it.primitive_iterator.set_end(); + } + } - case value_t::array: - { - m_it.array_iterator = m_object->m_data.m_value.array->end(); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator.set_end(); - break; - } + /// @throw invalid_iterator.212 if @a other points to another container + template + JSON_HEDLEY_ALWAYS_INLINE void check_same_container(const IterImpl& other) const + { + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + throw_literal(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object); } } @@ -424,10 +404,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci bool operator==(const IterImpl& other) const { // if objects are not the same, the comparison is undefined - if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) - { - throw_literal(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object); - } + check_same_container(other); // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 if (m_object == nullptr) @@ -466,10 +443,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci bool operator<(const iter_impl& other) const { // if objects are not the same, the comparison is undefined - if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) - { - throw_literal(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object); - } + check_same_container(other); // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 if (m_object == nullptr) @@ -478,25 +452,18 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci return false; } - switch (m_object->m_data.m_type) + if (m_object->is_object()) { - case value_t::object: - throw_literal(exception_id::iterator_order_on_object, "cannot compare order of object iterators", m_object); - - case value_t::array: - return (m_it.array_iterator < other.m_it.array_iterator); - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return (m_it.primitive_iterator < other.m_it.primitive_iterator); + throw_literal(exception_id::iterator_order_on_object, "cannot compare order of object iterators", m_object); } + + if (m_object->is_array()) + { + return (m_it.array_iterator < other.m_it.array_iterator); + } + + // primitive (is_primitive(), including discarded) + return (m_it.primitive_iterator < other.m_it.primitive_iterator); } /*! @@ -534,30 +501,19 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci { JSON_ASSERT(m_object != nullptr); - switch (m_object->m_data.m_type) + if (m_object->is_object()) { - case value_t::object: - throw_literal(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object); + throw_literal(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object); + } - case value_t::array: - { - std::advance(m_it.array_iterator, i); - break; - } - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - { - m_it.primitive_iterator += i; - break; - } + if (m_object->is_array()) + { + std::advance(m_it.array_iterator, i); + } + else + { + // primitive (is_primitive(), including discarded) + m_it.primitive_iterator += i; } return *this; @@ -613,25 +569,18 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci { JSON_ASSERT(m_object != nullptr); - switch (m_object->m_data.m_type) + if (m_object->is_object()) { - case value_t::object: - throw_literal(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object); - - case value_t::array: - return m_it.array_iterator - other.m_it.array_iterator; - - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return m_it.primitive_iterator - other.m_it.primitive_iterator; + throw_literal(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object); } + + if (m_object->is_array()) + { + return m_it.array_iterator - other.m_it.array_iterator; + } + + // primitive (is_primitive(), including discarded) + return m_it.primitive_iterator - other.m_it.primitive_iterator; } /*! diff --git a/include/nlohmann/detail/iterators/iteration_proxy.hpp b/include/nlohmann/detail/iterators/iteration_proxy.hpp index c66a5c0fd..23a9e3b0d 100644 --- a/include/nlohmann/detail/iterators/iteration_proxy.hpp +++ b/include/nlohmann/detail/iterators/iteration_proxy.hpp @@ -109,35 +109,25 @@ template class iteration_proxy_value { JSON_ASSERT(anchor.m_object != nullptr); - switch (anchor.m_object->type()) + if (anchor.m_object->is_array()) { // use integer array index as key - case value_t::array: + if (array_index != array_index_last) { - if (array_index != array_index_last) - { - int_to_string( array_index_str, array_index ); - array_index_last = array_index; - } - return array_index_str; + int_to_string( array_index_str, array_index ); + array_index_last = array_index; } - - // use key from the object - case value_t::object: - return anchor.key(); - - // use an empty key for all primitive types - case value_t::null: - case value_t::string: - case value_t::boolean: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::number_float: - case value_t::binary: - case value_t::discarded: - default: - return empty_str; + return array_index_str; } + + if (anchor.m_object->is_object()) + { + // use key from the object + return anchor.key(); + } + + // use an empty key for all primitive types + return empty_str; } /// return value of the iterator