Skip to content

Commit 691222a

Browse files
committed
[libc++] Optimize multi{map,set}::insert
1 parent cfdbbb8 commit 691222a

File tree

4 files changed

+39
-13
lines changed

4 files changed

+39
-13
lines changed

libcxx/docs/ReleaseNotes/22.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ Improvements and New Features
4949
- The performance of ``unordered_set::operator=(const unordered_set&)`` has been improved by up to 5x.
5050
- The performance of ``map::erase`` and ``set::erase`` has been improved by up to 2x
5151
- The performance of ``find(key)`` in ``map``, ``set``, ``multimap`` and ``multiset`` has been improved by up to 2.3x
52+
- The performance of the ``(iterator, iterator)`` constructors of ``multimap`` and ``multiset``
53+
has been improved by up to 3x
54+
- The performance of ``insert(iterator, iterator)`` of ``multimap`` and ``multiset`` has been improved by up to 2.5x
5255

5356
Deprecations and Removals
5457
-------------------------

libcxx/include/__tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,35 @@ public:
999999
__emplace_hint_multi(__p, std::move(__value));
10001000
}
10011001

1002+
template <class _InIter, class _Sent>
1003+
_LIBCPP_HIDE_FROM_ABI void __insert_range_multi(_InIter __first, _Sent __last) {
1004+
if (__first == __last)
1005+
return;
1006+
1007+
if (__root() == nullptr) { // Make sure we always have a root node
1008+
__insert_node_at(
1009+
__end_node(), __end_node()->__left_, static_cast<__node_base_pointer>(__construct_node(*__first).release()));
1010+
++__first;
1011+
}
1012+
1013+
auto __max_node = static_cast<__node_pointer>(std::__tree_max(static_cast<__node_base_pointer>(__root())));
1014+
1015+
for (; __first != __last; ++__first) {
1016+
__node_holder __nd = __construct_node(*__first);
1017+
// Always check the max node first. This optimizes for sorted ranges inserted at the end.
1018+
if (!value_comp()(__nd->__get_value(), __max_node->__get_value())) { // __node >= __max_val
1019+
__insert_node_at(static_cast<__end_node_pointer>(__max_node),
1020+
__max_node->__right_,
1021+
static_cast<__node_base_pointer>(__nd.get()));
1022+
__max_node = __nd.release();
1023+
} else {
1024+
__end_node_pointer __parent;
1025+
__node_base_pointer& __child = __find_leaf_high(__parent, __nd->__value_);
1026+
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd.release()));
1027+
}
1028+
}
1029+
}
1030+
10021031
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __node_assign_unique(const value_type& __v, __node_pointer __dest);
10031032

10041033
_LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(__node_pointer __nd);

libcxx/include/map

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20
593593
# include <__memory/unique_ptr.h>
594594
# include <__memory_resource/polymorphic_allocator.h>
595595
# include <__node_handle>
596+
# include <__ranges/access.h>
596597
# include <__ranges/concepts.h>
597598
# include <__ranges/container_compatible_range.h>
598599
# include <__ranges/from_range.h>
@@ -1749,17 +1750,13 @@ public:
17491750

17501751
template <class _InputIterator>
17511752
_LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) {
1752-
for (const_iterator __e = cend(); __f != __l; ++__f)
1753-
__tree_.__emplace_hint_multi(__e.__i_, *__f);
1753+
__tree_.__insert_range_multi(__f, __l);
17541754
}
17551755

17561756
# if _LIBCPP_STD_VER >= 23
17571757
template <_ContainerCompatibleRange<value_type> _Range>
17581758
_LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) {
1759-
const_iterator __end = cend();
1760-
for (auto&& __element : __range) {
1761-
__tree_.__emplace_hint_multi(__end.__i_, std::forward<decltype(__element)>(__element));
1762-
}
1759+
__tree_.__insert_range_multi(ranges::begin(__range), ranges::end(__range));
17631760
}
17641761
# endif
17651762

libcxx/include/set

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred); // C++20
530530
# include <__memory/allocator_traits.h>
531531
# include <__memory_resource/polymorphic_allocator.h>
532532
# include <__node_handle>
533+
# include <__ranges/access.h>
533534
# include <__ranges/concepts.h>
534535
# include <__ranges/container_compatible_range.h>
535536
# include <__ranges/from_range.h>
@@ -1205,18 +1206,14 @@ public:
12051206
}
12061207

12071208
template <class _InputIterator>
1208-
_LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) {
1209-
for (const_iterator __e = cend(); __f != __l; ++__f)
1210-
__tree_.__emplace_hint_multi(__e, *__f);
1209+
_LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) {
1210+
__tree_.__insert_range_multi(__first, __last);
12111211
}
12121212

12131213
# if _LIBCPP_STD_VER >= 23
12141214
template <_ContainerCompatibleRange<value_type> _Range>
12151215
_LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) {
1216-
const_iterator __end = cend();
1217-
for (auto&& __element : __range) {
1218-
__tree_.__emplace_hint_multi(__end, std::forward<decltype(__element)>(__element));
1219-
}
1216+
__tree_.__insert_range_multi(ranges::begin(__range), ranges::end(__range));
12201217
}
12211218
# endif
12221219

0 commit comments

Comments
 (0)