Skip to content

Commit 7624c61

Browse files
authored
[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
1 parent 3294cdd commit 7624c61

File tree

6 files changed

+402
-93
lines changed

6 files changed

+402
-93
lines changed

libcxx/docs/ReleaseNotes/22.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ Improvements and New Features
5353
- The performance of ``find(key)`` in ``map``, ``set``, ``multimap`` and ``multiset`` has been improved by up to 2.3x
5454
- Some reallocations are now avoided in `std::filesystem::path::lexically_relative`, resulting in a performance
5555
improvement of up to 1.7x.
56-
- The performance of the ``(iterator, iterator)`` constructors of ``multimap`` and ``multiset``
56+
- The performance of the ``(iterator, iterator)`` constructors of ``map``, ``set``, ``multimap`` and ``multiset``
5757
has been improved by up to 3x
58-
- The performance of ``insert(iterator, iterator)`` of ``multimap`` and ``multiset`` has been improved by up to 2.5x
58+
- The performance of ``insert(iterator, iterator)`` of ``map``, ``set``, ``multimap`` and ``multiset`` has been improved
59+
by up to 2.5x
5960
- The performance of ``erase(iterator, iterator)`` in the unordered containers has been improved by up to 1.9x
6061
- The performance of ``map::insert_or_assign`` has been improved by up to 2x
6162

libcxx/include/__tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,58 @@ public:
10251025
_LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(__node_pointer __nd);
10261026
_LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(const_iterator __p, __node_pointer __nd);
10271027

1028+
template <class _InIter, class _Sent>
1029+
_LIBCPP_HIDE_FROM_ABI void __insert_range_unique(_InIter __first, _Sent __last) {
1030+
if (__first == __last)
1031+
return;
1032+
1033+
if (__root() == nullptr) {
1034+
__insert_node_at(
1035+
__end_node(), __end_node()->__left_, static_cast<__node_base_pointer>(__construct_node(*__first).release()));
1036+
++__first;
1037+
}
1038+
1039+
auto __max_node = static_cast<__node_pointer>(std::__tree_max(static_cast<__node_base_pointer>(__root())));
1040+
1041+
using __reference = decltype(*__first);
1042+
1043+
for (; __first != __last; ++__first) {
1044+
std::__try_key_extraction<key_type>(
1045+
[this, &__max_node](const key_type& __key, __reference&& __val) {
1046+
if (value_comp()(__max_node->__get_value(), __key)) { // __key > __max_node
1047+
__node_holder __nd = __construct_node(std::forward<__reference>(__val));
1048+
__insert_node_at(static_cast<__end_node_pointer>(__max_node),
1049+
__max_node->__right_,
1050+
static_cast<__node_base_pointer>(__nd.get()));
1051+
__max_node = __nd.release();
1052+
} else {
1053+
__end_node_pointer __parent;
1054+
__node_base_pointer& __child = __find_equal(__parent, __key);
1055+
if (__child == nullptr) {
1056+
__node_holder __nd = __construct_node(std::forward<__reference>(__val));
1057+
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd.release()));
1058+
}
1059+
}
1060+
},
1061+
[this, &__max_node](__reference&& __val) {
1062+
__node_holder __nd = __construct_node(std::forward<__reference>(__val));
1063+
if (value_comp()(__max_node->__get_value(), __nd->__get_value())) { // __node > __max_node
1064+
__insert_node_at(static_cast<__end_node_pointer>(__max_node),
1065+
__max_node->__right_,
1066+
static_cast<__node_base_pointer>(__nd.get()));
1067+
__max_node = __nd.release();
1068+
} else {
1069+
__end_node_pointer __parent;
1070+
__node_base_pointer& __child = __find_equal(__parent, __nd->__get_value());
1071+
if (__child == nullptr) {
1072+
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd.release()));
1073+
}
1074+
}
1075+
},
1076+
*__first);
1077+
}
1078+
}
1079+
10281080
_LIBCPP_HIDE_FROM_ABI iterator __remove_node_pointer(__node_pointer) _NOEXCEPT;
10291081

10301082
#if _LIBCPP_STD_VER >= 17

libcxx/include/map

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,18 +1089,14 @@ public:
10891089
# endif
10901090

10911091
template <class _InputIterator>
1092-
_LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) {
1093-
for (const_iterator __e = cend(); __f != __l; ++__f)
1094-
insert(__e.__i_, *__f);
1092+
_LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) {
1093+
__tree_.__insert_range_unique(__first, __last);
10951094
}
10961095

10971096
# if _LIBCPP_STD_VER >= 23
10981097
template <_ContainerCompatibleRange<value_type> _Range>
10991098
_LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) {
1100-
const_iterator __end = cend();
1101-
for (auto&& __element : __range) {
1102-
insert(__end.__i_, std::forward<decltype(__element)>(__element));
1103-
}
1099+
__tree_.__insert_range_unique(ranges::begin(__range), ranges::end(__range));
11041100
}
11051101
# endif
11061102

libcxx/include/set

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -742,18 +742,14 @@ public:
742742
}
743743

744744
template <class _InputIterator>
745-
_LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) {
746-
for (const_iterator __e = cend(); __f != __l; ++__f)
747-
__tree_.__emplace_hint_unique(__e, *__f);
745+
_LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) {
746+
__tree_.__insert_range_unique(__first, __last);
748747
}
749748

750749
# if _LIBCPP_STD_VER >= 23
751750
template <_ContainerCompatibleRange<value_type> _Range>
752751
_LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) {
753-
const_iterator __end = cend();
754-
for (auto&& __element : __range) {
755-
__tree_.__emplace_hint_unique(__end, std::forward<decltype(__element)>(__element));
756-
}
752+
__tree_.__insert_range_unique(ranges::begin(__range), ranges::end(__range));
757753
}
758754
# endif
759755

libcxx/test/std/containers/associative/map/map.modifiers/insert_iter_iter.pass.cpp

Lines changed: 175 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,64 +13,188 @@
1313
// template <class InputIterator>
1414
// void insert(InputIterator first, InputIterator last);
1515

16-
#include <map>
16+
#include <array>
1717
#include <cassert>
18+
#include <map>
1819

19-
#include "test_macros.h"
2020
#include "test_iterators.h"
2121
#include "min_allocator.h"
2222

23-
int main(int, char**) {
24-
{
25-
typedef std::map<int, double> M;
26-
typedef std::pair<int, double> P;
27-
P ar[] = {
28-
P(1, 1),
29-
P(1, 1.5),
30-
P(1, 2),
31-
P(2, 1),
32-
P(2, 1.5),
33-
P(2, 2),
34-
P(3, 1),
35-
P(3, 1.5),
36-
P(3, 2),
37-
};
38-
M m;
39-
m.insert(cpp17_input_iterator<P*>(ar), cpp17_input_iterator<P*>(ar + sizeof(ar) / sizeof(ar[0])));
40-
assert(m.size() == 3);
41-
assert(m.begin()->first == 1);
42-
assert(m.begin()->second == 1);
43-
assert(std::next(m.begin())->first == 2);
44-
assert(std::next(m.begin())->second == 1);
45-
assert(std::next(m.begin(), 2)->first == 3);
46-
assert(std::next(m.begin(), 2)->second == 1);
23+
template <class Iter, class Alloc>
24+
void test_alloc() {
25+
{ // Check that an empty range works correctly
26+
{ // Without elements in the container
27+
using Map = std::map<int, int, std::less<int>, Alloc>;
28+
29+
std::array<std::pair<const int, int>, 0> arr;
30+
31+
Map map;
32+
map.insert(Iter(arr.data()), Iter(arr.data() + arr.size()));
33+
assert(map.size() == 0);
34+
assert(map.begin() == map.end());
35+
}
36+
{ // With 1 element in the container
37+
using Map = std::map<int, int, std::less<int>, Alloc>;
38+
using Pair = std::pair<const int, int>;
39+
40+
std::array<Pair, 0> arr;
41+
42+
Map map;
43+
map.insert(Pair(0, 0));
44+
map.insert(Iter(arr.data()), Iter(arr.data() + arr.size()));
45+
assert(map.size() == 1);
46+
assert(*std::next(map.begin(), 0) == Pair(0, 0));
47+
assert(std::next(map.begin(), 1) == map.end());
48+
}
49+
{ // With multiple elements in the container
50+
using Map = std::map<int, int, std::less<int>, Alloc>;
51+
using Pair = std::pair<const int, int>;
52+
53+
std::array<Pair, 0> arr;
54+
55+
Map map;
56+
map.insert(Pair(0, 0));
57+
map.insert(Pair(1, 1));
58+
map.insert(Pair(2, 2));
59+
map.insert(Iter(arr.data()), Iter(arr.data() + arr.size()));
60+
assert(map.size() == 3);
61+
assert(*std::next(map.begin(), 0) == Pair(0, 0));
62+
assert(*std::next(map.begin(), 1) == Pair(1, 1));
63+
assert(*std::next(map.begin(), 2) == Pair(2, 2));
64+
assert(std::next(map.begin(), 3) == map.end());
65+
}
4766
}
48-
#if TEST_STD_VER >= 11
49-
{
50-
typedef std::map<int, double, std::less<int>, min_allocator<std::pair<const int, double>>> M;
51-
typedef std::pair<int, double> P;
52-
P ar[] = {
53-
P(1, 1),
54-
P(1, 1.5),
55-
P(1, 2),
56-
P(2, 1),
57-
P(2, 1.5),
58-
P(2, 2),
59-
P(3, 1),
60-
P(3, 1.5),
61-
P(3, 2),
62-
};
63-
M m;
64-
m.insert(cpp17_input_iterator<P*>(ar), cpp17_input_iterator<P*>(ar + sizeof(ar) / sizeof(ar[0])));
65-
assert(m.size() == 3);
66-
assert(m.begin()->first == 1);
67-
assert(m.begin()->second == 1);
68-
assert(std::next(m.begin())->first == 2);
69-
assert(std::next(m.begin())->second == 1);
70-
assert(std::next(m.begin(), 2)->first == 3);
71-
assert(std::next(m.begin(), 2)->second == 1);
67+
{ // Check that 1 element is inserted correctly
68+
{ // Without elements in the container
69+
using Map = std::map<int, int, std::less<int>, Alloc>;
70+
using Pair = std::pair<const int, int>;
71+
72+
Pair arr[] = {Pair(1, 1)};
73+
74+
Map map;
75+
map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
76+
assert(map.size() == 1);
77+
assert(*std::next(map.begin(), 0) == Pair(1, 1));
78+
assert(std::next(map.begin(), 1) == map.end());
79+
}
80+
{ // With 1 element in the container - a different key
81+
using Map = std::map<int, int, std::less<int>, Alloc>;
82+
using Pair = std::pair<const int, int>;
83+
84+
Pair arr[] = {Pair(1, 1)};
85+
86+
Map map;
87+
map.insert(Pair(0, 0));
88+
map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
89+
assert(map.size() == 2);
90+
assert(*std::next(map.begin(), 0) == Pair(0, 0));
91+
assert(*std::next(map.begin(), 1) == Pair(1, 1));
92+
assert(std::next(map.begin(), 2) == map.end());
93+
}
94+
{ // With 1 element in the container - the same key
95+
using Map = std::map<int, int, std::less<int>, Alloc>;
96+
using Pair = std::pair<const int, int>;
97+
98+
Pair arr[] = {Pair(1, 1)};
99+
100+
Map map;
101+
map.insert(Pair(1, 2));
102+
map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
103+
assert(map.size() == 1);
104+
assert(*std::next(map.begin(), 0) == Pair(1, 2));
105+
assert(std::next(map.begin(), 1) == map.end());
106+
}
107+
{ // With multiple elements in the container
108+
using Map = std::map<int, int, std::less<int>, Alloc>;
109+
using Pair = std::pair<const int, int>;
110+
111+
Pair arr[] = {Pair(1, 1)};
112+
113+
Map map;
114+
map.insert(Pair(0, 0));
115+
map.insert(Pair(1, 1));
116+
map.insert(Pair(2, 2));
117+
map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
118+
assert(map.size() == 3);
119+
assert(*std::next(map.begin(), 0) == Pair(0, 0));
120+
assert(*std::next(map.begin(), 1) == Pair(1, 1));
121+
assert(*std::next(map.begin(), 2) == Pair(2, 2));
122+
assert(std::next(map.begin(), 3) == map.end());
123+
}
72124
}
73-
#endif
125+
{ // Check that multiple elements are inserted correctly
126+
{ // Without elements in the container
127+
using Map = std::map<int, int, std::less<int>, Alloc>;
128+
using Pair = std::pair<const int, int>;
129+
130+
Pair arr[] = {Pair(1, 1), Pair(1, 1), Pair(3, 3)};
131+
132+
Map map;
133+
map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
134+
assert(map.size() == 2);
135+
assert(*std::next(map.begin(), 0) == Pair(1, 1));
136+
assert(*std::next(map.begin(), 1) == Pair(3, 3));
137+
assert(std::next(map.begin(), 2) == map.end());
138+
}
139+
{ // With 1 element in the container - a different key
140+
using Map = std::map<int, int, std::less<int>, Alloc>;
141+
using Pair = std::pair<const int, int>;
142+
143+
Pair arr[] = {Pair(1, 1), Pair(1, 1), Pair(3, 3)};
144+
145+
Map map;
146+
map.insert(Pair(0, 0));
147+
map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
148+
assert(map.size() == 3);
149+
assert(*std::next(map.begin(), 0) == Pair(0, 0));
150+
assert(*std::next(map.begin(), 1) == Pair(1, 1));
151+
assert(*std::next(map.begin(), 2) == Pair(3, 3));
152+
assert(std::next(map.begin(), 3) == map.end());
153+
}
154+
{ // With 1 element in the container - the same key
155+
using Map = std::map<int, int, std::less<int>, Alloc>;
156+
using Pair = std::pair<const int, int>;
157+
158+
Pair arr[] = {Pair(1, 1), Pair(2, 2), Pair(3, 3)};
159+
160+
Map map;
161+
map.insert(Pair(1, 1));
162+
map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
163+
assert(map.size() == 3);
164+
assert(*std::next(map.begin(), 0) == Pair(1, 1));
165+
assert(*std::next(map.begin(), 1) == Pair(2, 2));
166+
assert(*std::next(map.begin(), 2) == Pair(3, 3));
167+
assert(std::next(map.begin(), 3) == map.end());
168+
}
169+
{ // With multiple elements in the container
170+
using Map = std::map<int, int, std::less<int>, Alloc>;
171+
using Pair = std::pair<const int, int>;
172+
173+
Pair arr[] = {Pair(1, 1), Pair(3, 3), Pair(4, 4)};
174+
175+
Map map;
176+
map.insert(Pair(0, 0));
177+
map.insert(Pair(1, 1));
178+
map.insert(Pair(2, 2));
179+
map.insert(Iter(std::begin(arr)), Iter(std::end(arr)));
180+
assert(map.size() == 5);
181+
assert(*std::next(map.begin(), 0) == Pair(0, 0));
182+
assert(*std::next(map.begin(), 1) == Pair(1, 1));
183+
assert(*std::next(map.begin(), 2) == Pair(2, 2));
184+
assert(*std::next(map.begin(), 3) == Pair(3, 3));
185+
assert(*std::next(map.begin(), 4) == Pair(4, 4));
186+
assert(std::next(map.begin(), 5) == map.end());
187+
}
188+
}
189+
}
190+
191+
void test() {
192+
test_alloc<cpp17_input_iterator<std::pair<const int, int>*>, std::allocator<std::pair<const int, int> > >();
193+
test_alloc<cpp17_input_iterator<std::pair<const int, int>*>, min_allocator<std::pair<const int, int> > >();
194+
}
195+
196+
int main(int, char**) {
197+
test();
74198

75199
return 0;
76200
}

0 commit comments

Comments
 (0)