[libcxx-commits] [libcxx] [libc++] Optimize {map, set}::insert(InputIterator, InputIterator) (PR #154703)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Aug 26 07:29:56 PDT 2025
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/154703
>From 3b15ab767559bc7262898bbc29c5a7f67d410c87 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 21 Aug 2025 11:03:06 +0200
Subject: [PATCH] [libc++] Optimize {map,set}::insert(InputIterator,
InputIterator)
---
libcxx/docs/ReleaseNotes/22.rst | 5 ++--
libcxx/include/__tree | 52 +++++++++++++++++++++++++++++++++
libcxx/include/map | 10 ++-----
libcxx/include/set | 10 ++-----
4 files changed, 61 insertions(+), 16 deletions(-)
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 0f3640ef6a834..73b567bff30bb 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -1039,6 +1039,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 9bd2282e77a3c..335e82e5813e9 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 5190fc1f406ba..245fbde4a9490 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
More information about the libcxx-commits
mailing list