diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst index 191dab6b77564..42b7ec156fe5c 100644 --- a/libcxx/docs/ReleaseNotes/22.rst +++ b/libcxx/docs/ReleaseNotes/22.rst @@ -49,6 +49,9 @@ Improvements and New Features - The performance of ``unordered_set::operator=(const unordered_set&)`` has been improved by up to 5x. - The performance of ``map::erase`` and ``set::erase`` has been improved by up to 2x - The performance of ``find(key)`` in ``map``, ``set``, ``multimap`` and ``multiset`` has been improved by up to 2.3x +- The performance of the ``(iterator, iterator)`` constructors of ``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 Deprecations and Removals ------------------------- diff --git a/libcxx/include/__tree b/libcxx/include/__tree index d154ce1616b93..bffb52c2368ea 100644 --- a/libcxx/include/__tree +++ b/libcxx/include/__tree @@ -999,6 +999,35 @@ public: __emplace_hint_multi(__p, std::move(__value)); } + template + _LIBCPP_HIDE_FROM_ABI void __insert_range_multi(_InIter __first, _Sent __last) { + if (__first == __last) + return; + + if (__root() == nullptr) { // Make sure we always have a root node + __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()))); + + for (; __first != __last; ++__first) { + __node_holder __nd = __construct_node(*__first); + // Always check the max node first. This optimizes for sorted ranges inserted at the end. + if (!value_comp()(__nd->__get_value(), __max_node->__get_value())) { // __node >= __max_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_leaf_high(__parent, __nd->__value_); + __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd.release())); + } + } + } + _LIBCPP_HIDE_FROM_ABI pair __node_assign_unique(const value_type& __v, __node_pointer __dest); _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(__node_pointer __nd); diff --git a/libcxx/include/map b/libcxx/include/map index 9f98abef9afe0..d8ff14b078f6d 100644 --- a/libcxx/include/map +++ b/libcxx/include/map @@ -593,6 +593,7 @@ erase_if(multimap& c, Predicate pred); // C++20 # include <__memory/unique_ptr.h> # include <__memory_resource/polymorphic_allocator.h> # include <__node_handle> +# include <__ranges/access.h> # include <__ranges/concepts.h> # include <__ranges/container_compatible_range.h> # include <__ranges/from_range.h> @@ -1749,17 +1750,13 @@ public: template _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) { - for (const_iterator __e = cend(); __f != __l; ++__f) - __tree_.__emplace_hint_multi(__e.__i_, *__f); + __tree_.__insert_range_multi(__f, __l); } # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange _Range> _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { - const_iterator __end = cend(); - for (auto&& __element : __range) { - __tree_.__emplace_hint_multi(__end.__i_, std::forward(__element)); - } + __tree_.__insert_range_multi(ranges::begin(__range), ranges::end(__range)); } # endif diff --git a/libcxx/include/set b/libcxx/include/set index c77345bc5dc1f..18488b56e7dd2 100644 --- a/libcxx/include/set +++ b/libcxx/include/set @@ -530,6 +530,7 @@ erase_if(multiset& c, Predicate pred); // C++20 # include <__memory/allocator_traits.h> # include <__memory_resource/polymorphic_allocator.h> # include <__node_handle> +# include <__ranges/access.h> # include <__ranges/concepts.h> # include <__ranges/container_compatible_range.h> # include <__ranges/from_range.h> @@ -1205,18 +1206,14 @@ public: } template - _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) { - for (const_iterator __e = cend(); __f != __l; ++__f) - __tree_.__emplace_hint_multi(__e, *__f); + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + __tree_.__insert_range_multi(__first, __last); } # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange _Range> _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { - const_iterator __end = cend(); - for (auto&& __element : __range) { - __tree_.__emplace_hint_multi(__end, std::forward(__element)); - } + __tree_.__insert_range_multi(ranges::begin(__range), ranges::end(__range)); } # endif