Repository navigation
Speed up container destruction, iterator access and diff() #5835
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -294,40 +294,25 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci | |
| { | ||
| JSON_ASSERT(m_object != nullptr); | ||
|
|
||
| switch (m_object->m_data.m_type) | ||
| if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array)) | ||
| { | ||
| case value_t::object: | ||
| { | ||
| JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); | ||
| return m_it.object_iterator->second; | ||
| } | ||
|
|
||
| case value_t::array: | ||
| { | ||
| JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); | ||
| return *m_it.array_iterator; | ||
| } | ||
|
|
||
| case value_t::null: | ||
| throw_cannot_get_value(); | ||
| JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); | ||
| return *m_it.array_iterator; | ||
| } | ||
|
|
||
| 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: | ||
| { | ||
| if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) | ||
| { | ||
| return *m_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()); | ||
| return m_it.object_iterator->second; | ||
| } | ||
|
|
||
| throw_cannot_get_value(); | ||
| } | ||
| // 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())) | ||
| { | ||
| return *m_object; | ||
| } | ||
|
|
||
| throw_cannot_get_value(); | ||
| } | ||
|
|
||
| /*! | ||
|
|
@@ -338,38 +323,25 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci | |
| { | ||
| JSON_ASSERT(m_object != nullptr); | ||
|
|
||
| switch (m_object->m_data.m_type) | ||
| if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why duplicate the code from the switch here? Was this supposed to be a move? If so, why?
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Written by Claude Code on behalf of @nlohmann. You're right, the duplication was unintended: it is now a move (commit 7cc6f32). The array/object branches sit in front of the switch so the hot path inlines (range-for over an array 2.5 → 1.3 ns/element); the switch bodies for those cases are gone, and what remained only handled primitives, so it is now plain code. No behaviour change. |
||
| { | ||
| case value_t::object: | ||
| { | ||
| JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end()); | ||
| return &(m_it.object_iterator->second); | ||
| } | ||
|
|
||
| case value_t::array: | ||
| { | ||
| JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); | ||
| return &*m_it.array_iterator; | ||
| } | ||
| JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end()); | ||
| return &*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: | ||
| { | ||
| if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) | ||
| { | ||
| return m_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()); | ||
| return &(m_it.object_iterator->second); | ||
| } | ||
|
|
||
| throw_cannot_get_value(); | ||
| } | ||
| // neither array nor object: a primitive value | ||
| if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) | ||
| { | ||
| return m_object; | ||
| } | ||
|
|
||
| throw_cannot_get_value(); | ||
| } | ||
|
|
||
| /*! | ||
|
|
@@ -391,35 +363,20 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci | |
| { | ||
| JSON_ASSERT(m_object != nullptr); | ||
|
|
||
| switch (m_object->m_data.m_type) | ||
| if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why duplicate the code from the switch here? Was this supposed to be a move? If so, why?
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Written by Claude Code on behalf of @nlohmann. You're right, the duplication was unintended: it is now a move (commit 7cc6f32). The array/object branches sit in front of the switch so the hot path inlines (range-for over an array 2.5 → 1.3 ns/element); the switch bodies for those cases are gone, and what remained only handled primitives, so it is now plain code. No behaviour change. |
||
| { | ||
| case value_t::object: | ||
| { | ||
| std::advance(m_it.object_iterator, 1); | ||
| break; | ||
| } | ||
|
|
||
| case value_t::array: | ||
| { | ||
| std::advance(m_it.array_iterator, 1); | ||
| break; | ||
| } | ||
| ++m_it.array_iterator; | ||
| return *this; | ||
| } | ||
|
|
||
| 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; | ||
| break; | ||
| } | ||
| if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) | ||
| { | ||
| std::advance(m_it.object_iterator, 1); | ||
| return *this; | ||
| } | ||
|
|
||
| // neither array nor object: a primitive value | ||
| ++m_it.primitive_iterator; | ||
| return *this; | ||
| } | ||
|
|
||
|
|
@@ -442,35 +399,20 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci | |
| { | ||
| JSON_ASSERT(m_object != nullptr); | ||
|
|
||
| switch (m_object->m_data.m_type) | ||
| if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array)) | ||
| { | ||
| case value_t::object: | ||
| { | ||
| std::advance(m_it.object_iterator, -1); | ||
| break; | ||
| } | ||
|
|
||
| case value_t::array: | ||
| { | ||
| std::advance(m_it.array_iterator, -1); | ||
| break; | ||
| } | ||
| --m_it.array_iterator; | ||
| return *this; | ||
| } | ||
|
|
||
| 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; | ||
| break; | ||
| } | ||
| if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) | ||
| { | ||
| std::advance(m_it.object_iterator, -1); | ||
| return *this; | ||
| } | ||
|
|
||
| // neither array nor object: a primitive value | ||
| --m_it.primitive_iterator; | ||
| return *this; | ||
| } | ||
|
|
||
|
|
@@ -493,25 +435,18 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci | |
| return true; | ||
| } | ||
|
|
||
| switch (m_object->m_data.m_type) | ||
| if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::array)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why duplicate the code from the switch here? Was this supposed to be a move? If so, why?
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Written by Claude Code on behalf of @nlohmann. You're right, the duplication was unintended: it is now a move (commit 7cc6f32). The array/object branches sit in front of the switch so the hot path inlines (range-for over an array 2.5 → 1.3 ns/element); the switch bodies for those cases are gone, and what remained only handled primitives, so it is now plain code. No behaviour change. |
||
| { | ||
| case value_t::object: | ||
| return (m_it.object_iterator == other.m_it.object_iterator); | ||
|
|
||
| case value_t::array: | ||
| return (m_it.array_iterator == other.m_it.array_iterator); | ||
| 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); | ||
| if (JSON_HEDLEY_LIKELY(m_object->m_data.m_type == value_t::object)) | ||
| { | ||
| return (m_it.object_iterator == other.m_it.object_iterator); | ||
| } | ||
|
|
||
| // neither array nor object: a primitive value | ||
| return (m_it.primitive_iterator == other.m_it.primitive_iterator); | ||
| } | ||
|
|
||
| /*! | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why duplicate the code from the switch here? Was this supposed to be a move? If so, why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Written by Claude Code on behalf of @nlohmann. You're right, the duplication was unintended: it is now a move (commit 7cc6f32). The array/object branches sit in front of the switch so the hot path inlines (range-for over an array 2.5 → 1.3 ns/element); the switch bodies for those cases are gone, and what remained only handled primitives, so it is now plain code. No behaviour change.