[libcxx-commits] [libcxx] 7624c61 - [libc++] Optimize {map, set}::insert(InputIterator, InputIterator) (#154703)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Sep 2 23:15:33 PDT 2025


Author: Nikolas Klauser
Date: 2025-09-03T08:15:29+02:00
New Revision: 7624c6141974f66f24ea90a18a55a111e98baa40

URL: https://github.com/llvm/llvm-project/commit/7624c6141974f66f24ea90a18a55a111e98baa40
DIFF: https://github.com/llvm/llvm-project/commit/7624c6141974f66f24ea90a18a55a111e98baa40.diff

LOG: [libc++] Optimize {map,set}::insert(InputIterator, InputIterator) (#154703)

```
----------------------------------------------------------------------------------------------------------------------------
Benchmark                                                                                                old             new
----------------------------------------------------------------------------------------------------------------------------
std::map<int, int>::ctor(iterator, iterator) (unsorted sequence)/0                                   14.2 ns         14.8 ns
std::map<int, int>::ctor(iterator, iterator) (unsorted sequence)/32                                   519 ns          404 ns
std::map<int, int>::ctor(iterator, iterator) (unsorted sequence)/1024                               52460 ns        36242 ns
std::map<int, int>::ctor(iterator, iterator) (unsorted sequence)/8192                              724222 ns       706496 ns
std::map<int, int>::ctor(iterator, iterator) (sorted sequence)/0                                     14.2 ns         14.7 ns
std::map<int, int>::ctor(iterator, iterator) (sorted sequence)/32                                     429 ns          349 ns
std::map<int, int>::ctor(iterator, iterator) (sorted sequence)/1024                                 23601 ns        14734 ns
std::map<int, int>::ctor(iterator, iterator) (sorted sequence)/8192                                267753 ns       112155 ns
std::map<int, int>::insert(iterator, iterator) (all new keys)/0                                       434 ns          448 ns
std::map<int, int>::insert(iterator, iterator) (all new keys)/32                                      950 ns          963 ns
std::map<int, int>::insert(iterator, iterator) (all new keys)/1024                                  27205 ns        25344 ns
std::map<int, int>::insert(iterator, iterator) (all new keys)/8192                                 294248 ns       280713 ns
std::map<int, int>::insert(iterator, iterator) (half new keys)/0                                      435 ns          449 ns
std::map<int, int>::insert(iterator, iterator) (half new keys)/32                                     771 ns          706 ns
std::map<int, int>::insert(iterator, iterator) (half new keys)/1024                                 30841 ns        17495 ns
std::map<int, int>::insert(iterator, iterator) (half new keys)/8192                                468807 ns       285847 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from same type)/0                    449 ns          453 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from same type)/32                  1021 ns          932 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from same type)/1024               29796 ns        19518 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from same type)/8192              345688 ns       153966 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from zip_view)/0                     449 ns          450 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from zip_view)/32                   1026 ns          807 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from zip_view)/1024                31632 ns        15573 ns
std::map<int, int>::insert(iterator, iterator) (product_iterator from zip_view)/8192               303024 ns       128946 ns
std::map<int, int>::erase(iterator, iterator) (erase half the container)/0                            447 ns          452 ns
std::map<int, int>::erase(iterator, iterator) (erase half the container)/32                           687 ns          710 ns
std::map<int, int>::erase(iterator, iterator) (erase half the container)/1024                        8604 ns         8581 ns
std::map<int, int>::erase(iterator, iterator) (erase half the container)/8192                       65693 ns        67406 ns
std::map<std::string, int>::ctor(iterator, iterator) (unsorted sequence)/0                           15.0 ns         15.0 ns
std::map<std::string, int>::ctor(iterator, iterator) (unsorted sequence)/32                          2781 ns         1845 ns
std::map<std::string, int>::ctor(iterator, iterator) (unsorted sequence)/1024                      187999 ns       182103 ns
std::map<std::string, int>::ctor(iterator, iterator) (unsorted sequence)/8192                     2937242 ns      2934912 ns
std::map<std::string, int>::ctor(iterator, iterator) (sorted sequence)/0                             15.0 ns         15.2 ns
std::map<std::string, int>::ctor(iterator, iterator) (sorted sequence)/32                            1326 ns         2462 ns
std::map<std::string, int>::ctor(iterator, iterator) (sorted sequence)/1024                         81778 ns        72193 ns
std::map<std::string, int>::ctor(iterator, iterator) (sorted sequence)/8192                       1177292 ns       669152 ns
std::map<std::string, int>::insert(iterator, iterator) (all new keys)/0                               439 ns          454 ns
std::map<std::string, int>::insert(iterator, iterator) (all new keys)/32                             2483 ns         2465 ns
std::map<std::string, int>::insert(iterator, iterator) (all new keys)/1024                         187614 ns       188072 ns
std::map<std::string, int>::insert(iterator, iterator) (all new keys)/8192                        1654675 ns      1706603 ns
std::map<std::string, int>::insert(iterator, iterator) (half new keys)/0                              437 ns          452 ns
std::map<std::string, int>::insert(iterator, iterator) (half new keys)/32                            1836 ns         1820 ns
std::map<std::string, int>::insert(iterator, iterator) (half new keys)/1024                        114885 ns       121865 ns
std::map<std::string, int>::insert(iterator, iterator) (half new keys)/8192                       1151960 ns      1197318 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from same type)/0            438 ns          455 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from same type)/32          1599 ns         1614 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from same type)/1024       95935 ns        82159 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from same type)/8192      776480 ns       941043 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from zip_view)/0             435 ns          462 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from zip_view)/32           1723 ns         1550 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from zip_view)/1024       107096 ns        92850 ns
std::map<std::string, int>::insert(iterator, iterator) (product_iterator from zip_view)/8192       893976 ns       775046 ns
std::map<std::string, int>::erase(iterator, iterator) (erase half the container)/0                    436 ns          453 ns
std::map<std::string, int>::erase(iterator, iterator) (erase half the container)/32                   775 ns          824 ns
std::map<std::string, int>::erase(iterator, iterator) (erase half the container)/1024               20241 ns        20454 ns
std::map<std::string, int>::erase(iterator, iterator) (erase half the container)/8192              139038 ns       138032 ns
std::set<int>::ctor(iterator, iterator) (unsorted sequence)/0                                        14.8 ns         14.7 ns
std::set<int>::ctor(iterator, iterator) (unsorted sequence)/32                                        468 ns          426 ns
std::set<int>::ctor(iterator, iterator) (unsorted sequence)/1024                                    54289 ns        39028 ns
std::set<int>::ctor(iterator, iterator) (unsorted sequence)/8192                                   738438 ns       695720 ns
std::set<int>::ctor(iterator, iterator) (sorted sequence)/0                                          14.7 ns         14.6 ns
std::set<int>::ctor(iterator, iterator) (sorted sequence)/32                                          478 ns          391 ns
std::set<int>::ctor(iterator, iterator) (sorted sequence)/1024                                      24017 ns        13905 ns
std::set<int>::ctor(iterator, iterator) (sorted sequence)/8192                                     267862 ns       111378 ns
std::set<int>::insert(iterator, iterator) (all new keys)/0                                            458 ns          450 ns
std::set<int>::insert(iterator, iterator) (all new keys)/32                                          1066 ns          956 ns
std::set<int>::insert(iterator, iterator) (all new keys)/1024                                       29190 ns        25212 ns
std::set<int>::insert(iterator, iterator) (all new keys)/8192                                      320441 ns       279602 ns
std::set<int>::insert(iterator, iterator) (half new keys)/0                                           454 ns          453 ns
std::set<int>::insert(iterator, iterator) (half new keys)/32                                          816 ns          709 ns
std::set<int>::insert(iterator, iterator) (half new keys)/1024                                      32072 ns        17074 ns
std::set<int>::insert(iterator, iterator) (half new keys)/8192                                     403386 ns       286202 ns
std::set<int>::erase(iterator, iterator) (erase half the container)/0                                 451 ns          452 ns
std::set<int>::erase(iterator, iterator) (erase half the container)/32                                710 ns          703 ns
std::set<int>::erase(iterator, iterator) (erase half the container)/1024                             8261 ns         8499 ns
std::set<int>::erase(iterator, iterator) (erase half the container)/8192                            64466 ns        67343 ns
std::set<std::string>::ctor(iterator, iterator) (unsorted sequence)/0                                15.2 ns         15.0 ns
std::set<std::string>::ctor(iterator, iterator) (unsorted sequence)/32                               3069 ns         3005 ns
std::set<std::string>::ctor(iterator, iterator) (unsorted sequence)/1024                           189552 ns       180933 ns
std::set<std::string>::ctor(iterator, iterator) (unsorted sequence)/8192                          2887579 ns      2691678 ns
std::set<std::string>::ctor(iterator, iterator) (sorted sequence)/0                                  15.1 ns         14.9 ns
std::set<std::string>::ctor(iterator, iterator) (sorted sequence)/32                                 2611 ns         2514 ns
std::set<std::string>::ctor(iterator, iterator) (sorted sequence)/1024                              91581 ns        78727 ns
std::set<std::string>::ctor(iterator, iterator) (sorted sequence)/8192                            1192640 ns      1158959 ns
std::set<std::string>::insert(iterator, iterator) (all new keys)/0                                    452 ns          457 ns
std::set<std::string>::insert(iterator, iterator) (all new keys)/32                                  2530 ns         2544 ns
std::set<std::string>::insert(iterator, iterator) (all new keys)/1024                              195352 ns       179614 ns
std::set<std::string>::insert(iterator, iterator) (all new keys)/8192                             1737890 ns      1749615 ns
std::set<std::string>::insert(iterator, iterator) (half new keys)/0                                   451 ns          454 ns
std::set<std::string>::insert(iterator, iterator) (half new keys)/32                                 1949 ns         1766 ns
std::set<std::string>::insert(iterator, iterator) (half new keys)/1024                             128853 ns       109467 ns
std::set<std::string>::insert(iterator, iterator) (half new keys)/8192                            1233077 ns      1177289 ns
std::set<std::string>::erase(iterator, iterator) (erase half the container)/0                         450 ns          451 ns
std::set<std::string>::erase(iterator, iterator) (erase half the container)/32                        809 ns          812 ns
std::set<std::string>::erase(iterator, iterator) (erase half the container)/1024                    21736 ns        21922 ns
std::set<std::string>::erase(iterator, iterator) (erase half the container)/8192                   135884 ns       133228 ns
```

Fixes #154650

Added: 
    

Modified: 
    libcxx/docs/ReleaseNotes/22.rst
    libcxx/include/__tree
    libcxx/include/map
    libcxx/include/set
    libcxx/test/std/containers/associative/map/map.modifiers/insert_iter_iter.pass.cpp
    libcxx/test/std/containers/associative/set/insert_iter_iter.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index cd8171dc5d1e8..463907f780453 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
 - The performance of ``map::insert_or_assign`` has been improved by up to 2x
 

diff  --git a/libcxx/include/__tree b/libcxx/include/__tree
index 0f43ecfd05db2..2edda2ba082af 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 395b434fe4a5b..b0c30e888e64e 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
 

diff  --git a/libcxx/test/std/containers/associative/map/map.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/associative/map/map.modifiers/insert_iter_iter.pass.cpp
index 0baff65f61938..dfbeb33698e6c 100644
--- a/libcxx/test/std/containers/associative/map/map.modifiers/insert_iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/map.modifiers/insert_iter_iter.pass.cpp
@@ -13,64 +13,188 @@
 // template <class InputIterator>
 //   void insert(InputIterator first, InputIterator last);
 
-#include <map>
+#include <array>
 #include <cassert>
+#include <map>
 
-#include "test_macros.h"
 #include "test_iterators.h"
 #include "min_allocator.h"
 
-int main(int, char**) {
-  {
-    typedef std::map<int, double> M;
-    typedef std::pair<int, double> P;
-    P ar[] = {
-        P(1, 1),
-        P(1, 1.5),
-        P(1, 2),
-        P(2, 1),
-        P(2, 1.5),
-        P(2, 2),
-        P(3, 1),
-        P(3, 1.5),
-        P(3, 2),
-    };
-    M m;
-    m.insert(cpp17_input_iterator<P*>(ar), cpp17_input_iterator<P*>(ar + sizeof(ar) / sizeof(ar[0])));
-    assert(m.size() == 3);
-    assert(m.begin()->first == 1);
-    assert(m.begin()->second == 1);
-    assert(std::next(m.begin())->first == 2);
-    assert(std::next(m.begin())->second == 1);
-    assert(std::next(m.begin(), 2)->first == 3);
-    assert(std::next(m.begin(), 2)->second == 1);
+template <class Iter, class Alloc>
+void test_alloc() {
+  {   // Check that an empty range works correctly
+    { // Without elements in the container
+      using Map = std::map<int, int, std::less<int>, Alloc>;
+
+      std::array<std::pair<const int, int>, 0> arr;
+
+      Map map;
+      map.insert(Iter(arr.data()), Iter(arr.data() + arr.size()));
+      assert(map.size() == 0);
+      assert(map.begin() == map.end());
+    }
+    { // With 1 element in the container
+      using Map  = std::map<int, int, std::less<int>, Alloc>;
+      using Pair = std::pair<const int, int>;
+
+      std::array<Pair, 0> arr;
+
+      Map map;
+      map.insert(Pair(0, 0));
+      map.insert(Iter(arr.data()), Iter(arr.data() + arr.size()));
+      assert(map.size() == 1);
+      assert(*std::next(map.begin(), 0) == Pair(0, 0));
+      assert(std::next(map.begin(), 1) == map.end());
+    }
+    { // With multiple elements in the container
+      using Map  = std::map<int, int, std::less<int>, Alloc>;
+      using Pair = std::pair<const int, int>;
+
+      std::array<Pair, 0> arr;
+
+      Map map;
+      map.insert(Pair(0, 0));
+      map.insert(Pair(1, 1));
+      map.insert(Pair(2, 2));
+      map.insert(Iter(arr.data()), Iter(arr.data() + arr.size()));
+      assert(map.size() == 3);
+      assert(*std::next(map.begin(), 0) == Pair(0, 0));
+      assert(*std::next(map.begin(), 1) == Pair(1, 1));
+      assert(*std::next(map.begin(), 2) == Pair(2, 2));
+      assert(std::next(map.begin(), 3) == map.end());
+    }
   }
-#if TEST_STD_VER >= 11
-  {
-    typedef std::map<int, double, std::less<int>, min_allocator<std::pair<const int, double>>> M;
-    typedef std::pair<int, double> P;
-    P ar[] = {
-        P(1, 1),
-        P(1, 1.5),
-        P(1, 2),
-        P(2, 1),
-        P(2, 1.5),
-        P(2, 2),
-        P(3, 1),
-        P(3, 1.5),
-        P(3, 2),
-    };
-    M m;
-    m.insert(cpp17_input_iterator<P*>(ar), cpp17_input_iterator<P*>(ar + sizeof(ar) / sizeof(ar[0])));
-    assert(m.size() == 3);
-    assert(m.begin()->first == 1);
-    assert(m.begin()->second == 1);
-    assert(std::next(m.begin())->first == 2);
-    assert(std::next(m.begin())->second == 1);
-    assert(std::next(m.begin(), 2)->first == 3);
-    assert(std::next(m.begin(), 2)->second == 1);
+  {   // Check that 1 element is inserted correctly
+    { // Without elements in the container
+      using Map  = std::map<int, int, std::less<int>, Alloc>;
+      using Pair = std::pair<const int, int>;
+
+      Pair arr[] = {Pair(1, 1)};
+
+      Map map;
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 1);
+      assert(*std::next(map.begin(), 0) == Pair(1, 1));
+      assert(std::next(map.begin(), 1) == map.end());
+    }
+    { // With 1 element in the container - a 
diff erent key
+      using Map  = std::map<int, int, std::less<int>, Alloc>;
+      using Pair = std::pair<const int, int>;
+
+      Pair arr[] = {Pair(1, 1)};
+
+      Map map;
+      map.insert(Pair(0, 0));
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 2);
+      assert(*std::next(map.begin(), 0) == Pair(0, 0));
+      assert(*std::next(map.begin(), 1) == Pair(1, 1));
+      assert(std::next(map.begin(), 2) == map.end());
+    }
+    { // With 1 element in the container - the same key
+      using Map  = std::map<int, int, std::less<int>, Alloc>;
+      using Pair = std::pair<const int, int>;
+
+      Pair arr[] = {Pair(1, 1)};
+
+      Map map;
+      map.insert(Pair(1, 2));
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 1);
+      assert(*std::next(map.begin(), 0) == Pair(1, 2));
+      assert(std::next(map.begin(), 1) == map.end());
+    }
+    { // With multiple elements in the container
+      using Map  = std::map<int, int, std::less<int>, Alloc>;
+      using Pair = std::pair<const int, int>;
+
+      Pair arr[] = {Pair(1, 1)};
+
+      Map map;
+      map.insert(Pair(0, 0));
+      map.insert(Pair(1, 1));
+      map.insert(Pair(2, 2));
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 3);
+      assert(*std::next(map.begin(), 0) == Pair(0, 0));
+      assert(*std::next(map.begin(), 1) == Pair(1, 1));
+      assert(*std::next(map.begin(), 2) == Pair(2, 2));
+      assert(std::next(map.begin(), 3) == map.end());
+    }
   }
-#endif
+  {   // Check that multiple elements are inserted correctly
+    { // Without elements in the container
+      using Map  = std::map<int, int, std::less<int>, Alloc>;
+      using Pair = std::pair<const int, int>;
+
+      Pair arr[] = {Pair(1, 1), Pair(1, 1), Pair(3, 3)};
+
+      Map map;
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 2);
+      assert(*std::next(map.begin(), 0) == Pair(1, 1));
+      assert(*std::next(map.begin(), 1) == Pair(3, 3));
+      assert(std::next(map.begin(), 2) == map.end());
+    }
+    { // With 1 element in the container - a 
diff erent key
+      using Map  = std::map<int, int, std::less<int>, Alloc>;
+      using Pair = std::pair<const int, int>;
+
+      Pair arr[] = {Pair(1, 1), Pair(1, 1), Pair(3, 3)};
+
+      Map map;
+      map.insert(Pair(0, 0));
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 3);
+      assert(*std::next(map.begin(), 0) == Pair(0, 0));
+      assert(*std::next(map.begin(), 1) == Pair(1, 1));
+      assert(*std::next(map.begin(), 2) == Pair(3, 3));
+      assert(std::next(map.begin(), 3) == map.end());
+    }
+    { // With 1 element in the container - the same key
+      using Map  = std::map<int, int, std::less<int>, Alloc>;
+      using Pair = std::pair<const int, int>;
+
+      Pair arr[] = {Pair(1, 1), Pair(2, 2), Pair(3, 3)};
+
+      Map map;
+      map.insert(Pair(1, 1));
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 3);
+      assert(*std::next(map.begin(), 0) == Pair(1, 1));
+      assert(*std::next(map.begin(), 1) == Pair(2, 2));
+      assert(*std::next(map.begin(), 2) == Pair(3, 3));
+      assert(std::next(map.begin(), 3) == map.end());
+    }
+    { // With multiple elements in the container
+      using Map  = std::map<int, int, std::less<int>, Alloc>;
+      using Pair = std::pair<const int, int>;
+
+      Pair arr[] = {Pair(1, 1), Pair(3, 3), Pair(4, 4)};
+
+      Map map;
+      map.insert(Pair(0, 0));
+      map.insert(Pair(1, 1));
+      map.insert(Pair(2, 2));
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 5);
+      assert(*std::next(map.begin(), 0) == Pair(0, 0));
+      assert(*std::next(map.begin(), 1) == Pair(1, 1));
+      assert(*std::next(map.begin(), 2) == Pair(2, 2));
+      assert(*std::next(map.begin(), 3) == Pair(3, 3));
+      assert(*std::next(map.begin(), 4) == Pair(4, 4));
+      assert(std::next(map.begin(), 5) == map.end());
+    }
+  }
+}
+
+void test() {
+  test_alloc<cpp17_input_iterator<std::pair<const int, int>*>, std::allocator<std::pair<const int, int> > >();
+  test_alloc<cpp17_input_iterator<std::pair<const int, int>*>, min_allocator<std::pair<const int, int> > >();
+}
+
+int main(int, char**) {
+  test();
 
   return 0;
 }

diff  --git a/libcxx/test/std/containers/associative/set/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/associative/set/insert_iter_iter.pass.cpp
index 6c9707ca31a81..8576c63a72de9 100644
--- a/libcxx/test/std/containers/associative/set/insert_iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/associative/set/insert_iter_iter.pass.cpp
@@ -13,38 +13,178 @@
 // template <class InputIterator>
 //   void insert(InputIterator first, InputIterator last);
 
-#include <set>
+#include <array>
 #include <cassert>
+#include <set>
 
-#include "test_macros.h"
-#include "test_iterators.h"
 #include "min_allocator.h"
+#include "test_iterators.h"
 
-int main(int, char**) {
-  {
-    typedef std::set<int> M;
-    typedef int V;
-    V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
-    M m;
-    m.insert(cpp17_input_iterator<const V*>(ar), cpp17_input_iterator<const V*>(ar + sizeof(ar) / sizeof(ar[0])));
-    assert(m.size() == 3);
-    assert(*m.begin() == 1);
-    assert(*std::next(m.begin()) == 2);
-    assert(*std::next(m.begin(), 2) == 3);
+template <class Iter, class Alloc>
+void test_alloc() {
+  {   // Check that an empty range works correctly
+    { // Without elements in the container
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      std::array<int, 0> arr;
+
+      Map map;
+      map.insert(Iter(arr.data()), Iter(arr.data() + arr.size()));
+      assert(map.size() == 0);
+      assert(map.begin() == map.end());
+    }
+    { // With 1 element in the container
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      std::array<int, 0> arr;
+
+      Map map;
+      map.insert(0);
+      map.insert(Iter(arr.data()), Iter(arr.data() + arr.size()));
+      assert(map.size() == 1);
+      assert(*std::next(map.begin(), 0) == 0);
+      assert(std::next(map.begin(), 1) == map.end());
+    }
+    { // With multiple elements in the container
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      std::array<int, 0> arr;
+
+      Map map;
+      map.insert(0);
+      map.insert(1);
+      map.insert(2);
+      map.insert(Iter(arr.data()), Iter(arr.data() + arr.size()));
+      assert(map.size() == 3);
+      assert(*std::next(map.begin(), 0) == 0);
+      assert(*std::next(map.begin(), 1) == 1);
+      assert(*std::next(map.begin(), 2) == 2);
+      assert(std::next(map.begin(), 3) == map.end());
+    }
   }
-#if TEST_STD_VER >= 11
-  {
-    typedef std::set<int, std::less<int>, min_allocator<int>> M;
-    typedef int V;
-    V ar[] = {1, 1, 1, 2, 2, 2, 3, 3, 3};
-    M m;
-    m.insert(cpp17_input_iterator<const V*>(ar), cpp17_input_iterator<const V*>(ar + sizeof(ar) / sizeof(ar[0])));
-    assert(m.size() == 3);
-    assert(*m.begin() == 1);
-    assert(*std::next(m.begin()) == 2);
-    assert(*std::next(m.begin(), 2) == 3);
+  {   // Check that 1 element is inserted correctly
+    { // Without elements in the container
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      int arr[] = {1};
+
+      Map map;
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 1);
+      assert(*std::next(map.begin(), 0) == 1);
+      assert(std::next(map.begin(), 1) == map.end());
+    }
+    { // With 1 element in the container - a 
diff erent key
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      int arr[] = {1};
+
+      Map map;
+      map.insert(0);
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 2);
+      assert(*std::next(map.begin(), 0) == 0);
+      assert(*std::next(map.begin(), 1) == 1);
+      assert(std::next(map.begin(), 2) == map.end());
+    }
+    { // With 1 element in the container - the same key
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      int arr[] = {1};
+
+      Map map;
+      map.insert(1);
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 1);
+      assert(*std::next(map.begin(), 0) == 1);
+      assert(std::next(map.begin(), 1) == map.end());
+    }
+    { // With multiple elements in the container
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      int arr[] = {1};
+
+      Map map;
+      map.insert(0);
+      map.insert(1);
+      map.insert(2);
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 3);
+      assert(*std::next(map.begin(), 0) == 0);
+      assert(*std::next(map.begin(), 1) == 1);
+      assert(*std::next(map.begin(), 2) == 2);
+      assert(std::next(map.begin(), 3) == map.end());
+    }
+  }
+  {   // Check that multiple elements are inserted correctly
+    { // Without elements in the container
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      int arr[] = {1, 1, 3};
+
+      Map map;
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 2);
+      assert(*std::next(map.begin(), 0) == 1);
+      assert(*std::next(map.begin(), 1) == 3);
+      assert(std::next(map.begin(), 2) == map.end());
+    }
+    { // With 1 element in the container - a 
diff erent key
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      int arr[] = {1, 1, 3};
+
+      Map map;
+      map.insert(0);
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 3);
+      assert(*std::next(map.begin(), 0) == 0);
+      assert(*std::next(map.begin(), 1) == 1);
+      assert(*std::next(map.begin(), 2) == 3);
+      assert(std::next(map.begin(), 3) == map.end());
+    }
+    { // With 1 element in the container - the same key
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      int arr[] = {1, 2, 3};
+
+      Map map;
+      map.insert(1);
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 3);
+      assert(*std::next(map.begin(), 0) == 1);
+      assert(*std::next(map.begin(), 1) == 2);
+      assert(*std::next(map.begin(), 2) == 3);
+      assert(std::next(map.begin(), 3) == map.end());
+    }
+    { // With multiple elements in the container
+      using Map = std::set<int, std::less<int>, Alloc>;
+
+      int arr[] = {1, 3, 4};
+
+      Map map;
+      map.insert(0);
+      map.insert(1);
+      map.insert(2);
+      map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
+      assert(map.size() == 5);
+      assert(*std::next(map.begin(), 0) == 0);
+      assert(*std::next(map.begin(), 1) == 1);
+      assert(*std::next(map.begin(), 2) == 2);
+      assert(*std::next(map.begin(), 3) == 3);
+      assert(*std::next(map.begin(), 4) == 4);
+      assert(std::next(map.begin(), 5) == map.end());
+    }
   }
-#endif
+}
+
+void test() {
+  test_alloc<cpp17_input_iterator<int*>, std::allocator<int> >();
+  test_alloc<cpp17_input_iterator<int*>, min_allocator<int> >();
+}
+
+int main(int, char**) {
+  test();
 
   return 0;
 }


        


More information about the libcxx-commits mailing list