-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[libc++] Optimize {map,set}::insert(InputIterator, InputIterator) #154703
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
Open
philnik777
wants to merge
1
commit into
llvm:main
Choose a base branch
from
philnik777:optimize_tree_insert_range_unique
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+402
−93
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3b15ab7
to
7813206
Compare
@llvm/pr-subscribers-libcxx Author: Nikolas Klauser (philnik777) Changes
Fixes #154650 Full diff: https://github.com/llvm/llvm-project/pull/154703.diff 4 Files Affected:
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 5378655c66606..0f2cf1073bb38 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -53,9 +53,10 @@ Improvements and New Features
- The performance of ``find(key)`` in ``map``, ``set``, ``multimap`` and ``multiset`` has been improved by up to 2.3x
- Some reallocations are now avoided in `std::filesystem::path::lexically_relative`, resulting in a performance
improvement of up to 1.7x.
-- The performance of the ``(iterator, iterator)`` constructors of ``multimap`` and ``multiset``
+- The performance of the ``(iterator, iterator)`` constructors of ``map``, ``set``, ``multimap`` and ``multiset``
has been improved by up to 3x
-- The performance of ``insert(iterator, iterator)`` of ``multimap`` and ``multiset`` has been improved by up to 2.5x
+- The performance of ``insert(iterator, iterator)`` of ``map``, ``set``, ``multimap`` and ``multiset`` has been improved
+ by up to 2.5x
- The performance of ``erase(iterator, iterator)`` in the unordered containers has been improved by up to 1.9x
Deprecations and Removals
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index 3ad2129ba9ddf..0ab79e1404afa 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -1025,6 +1025,58 @@ public:
_LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(__node_pointer __nd);
_LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(const_iterator __p, __node_pointer __nd);
+ template <class _InIter, class _Sent>
+ _LIBCPP_HIDE_FROM_ABI void __insert_range_unique(_InIter __first, _Sent __last) {
+ if (__first == __last)
+ return;
+
+ if (__root() == nullptr) {
+ __insert_node_at(
+ __end_node(), __end_node()->__left_, static_cast<__node_base_pointer>(__construct_node(*__first).release()));
+ ++__first;
+ }
+
+ auto __max_node = static_cast<__node_pointer>(std::__tree_max(static_cast<__node_base_pointer>(__root())));
+
+ using __reference = decltype(*__first);
+
+ for (; __first != __last; ++__first) {
+ std::__try_key_extraction<key_type>(
+ [this, &__max_node](const key_type& __key, __reference&& __val) {
+ if (value_comp()(__max_node->__get_value(), __key)) { // __key > __max_node
+ __node_holder __nd = __construct_node(std::forward<__reference>(__val));
+ __insert_node_at(static_cast<__end_node_pointer>(__max_node),
+ __max_node->__right_,
+ static_cast<__node_base_pointer>(__nd.get()));
+ __max_node = __nd.release();
+ } else {
+ __end_node_pointer __parent;
+ __node_base_pointer& __child = __find_equal(__parent, __key);
+ if (__child == nullptr) {
+ __node_holder __nd = __construct_node(std::forward<__reference>(__val));
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd.release()));
+ }
+ }
+ },
+ [this, &__max_node](__reference&& __val) {
+ __node_holder __nd = __construct_node(std::forward<__reference>(__val));
+ if (value_comp()(__max_node->__get_value(), __nd->__get_value())) { // __node > __max_node
+ __insert_node_at(static_cast<__end_node_pointer>(__max_node),
+ __max_node->__right_,
+ static_cast<__node_base_pointer>(__nd.get()));
+ __max_node = __nd.release();
+ } else {
+ __end_node_pointer __parent;
+ __node_base_pointer& __child = __find_equal(__parent, __nd->__get_value());
+ if (__child == nullptr) {
+ __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd.release()));
+ }
+ }
+ },
+ *__first);
+ }
+ }
+
_LIBCPP_HIDE_FROM_ABI iterator __remove_node_pointer(__node_pointer) _NOEXCEPT;
#if _LIBCPP_STD_VER >= 17
diff --git a/libcxx/include/map b/libcxx/include/map
index b53e1c4213487..8ba7719450f66 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -1089,18 +1089,14 @@ public:
# endif
template <class _InputIterator>
- _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) {
- for (const_iterator __e = cend(); __f != __l; ++__f)
- insert(__e.__i_, *__f);
+ _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) {
+ __tree_.__insert_range_unique(__first, __last);
}
# if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<value_type> _Range>
_LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) {
- const_iterator __end = cend();
- for (auto&& __element : __range) {
- insert(__end.__i_, std::forward<decltype(__element)>(__element));
- }
+ __tree_.__insert_range_unique(ranges::begin(__range), ranges::end(__range));
}
# endif
diff --git a/libcxx/include/set b/libcxx/include/set
index b444e8357052a..6470894517fd8 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -742,18 +742,14 @@ public:
}
template <class _InputIterator>
- _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) {
- for (const_iterator __e = cend(); __f != __l; ++__f)
- __tree_.__emplace_hint_unique(__e, *__f);
+ _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) {
+ __tree_.__insert_range_unique(__first, __last);
}
# if _LIBCPP_STD_VER >= 23
template <_ContainerCompatibleRange<value_type> _Range>
_LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) {
- const_iterator __end = cend();
- for (auto&& __element : __range) {
- __tree_.__emplace_hint_unique(__end, std::forward<decltype(__element)>(__element));
- }
+ __tree_.__insert_range_unique(ranges::begin(__range), ranges::end(__range));
}
# endif
|
ldionne
reviewed
Aug 27, 2025
ldionne
reviewed
Aug 28, 2025
7813206
to
472f84e
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #154650