1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10
11// <flat_map>
12
13#include <flat_map>
14#include <cassert>
15#include <deque>
16
17#include "MinSequenceContainer.h"
18#include "MoveOnly.h"
19#include "min_allocator.h"
20#include "test_macros.h"
21#include "../helpers.h"
22
23// template<class M>
24// pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
25// template<class M>
26// pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
27// template<class M>
28// iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
29// template<class M>
30// iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
31
32// Constraints: is_assignable_v<mapped_type&, M> is true and is_constructible_v<mapped_type, M> is true.
33template <class Map, class K, class M>
34concept CanInsertOrAssign =
35 requires(Map map, K&& k, M&& m) { map.insert_or_assign(std::forward<K>(k), std::forward<M>(m)); };
36
37template <class Map, class K, class M>
38concept CanInsertOrAssignIter = requires(Map map, typename Map::const_iterator iter, K&& k, M&& m) {
39 map.insert_or_assign(iter, std::forward<K>(k), std::forward<M>(m));
40};
41
42template <class From>
43struct ConstructAndAssignFrom {
44 explicit ConstructAndAssignFrom(From);
45 ConstructAndAssignFrom& operator=(From);
46};
47
48template <class From>
49struct ConstructFrom {
50 explicit ConstructFrom(From);
51};
52
53template <class From>
54struct AssignFrom {
55 AssignFrom& operator=(From);
56};
57
58struct V {};
59
60static_assert(CanInsertOrAssign<std::flat_map<int, ConstructAndAssignFrom<V>>, const int&, V>);
61static_assert(!CanInsertOrAssign<std::flat_map<int, ConstructAndAssignFrom<V>>, const int&, int>);
62static_assert(!CanInsertOrAssign<std::flat_map<int, ConstructFrom<V>>, const int&, V>);
63static_assert(!CanInsertOrAssign<std::flat_map<int, AssignFrom<V>>, const int&, V>);
64
65static_assert(CanInsertOrAssign<std::flat_map<int, ConstructAndAssignFrom<V>>, int&&, V>);
66static_assert(!CanInsertOrAssign<std::flat_map<int, ConstructAndAssignFrom<V>>, int&&, int>);
67static_assert(!CanInsertOrAssign<std::flat_map<int, ConstructFrom<V>>, int&&, V>);
68static_assert(!CanInsertOrAssign<std::flat_map<int, AssignFrom<V>>, int&&, V>);
69
70static_assert(CanInsertOrAssignIter<std::flat_map<int, ConstructAndAssignFrom<V>>, const int&, V>);
71static_assert(!CanInsertOrAssignIter<std::flat_map<int, ConstructAndAssignFrom<V>>, const int&, int>);
72static_assert(!CanInsertOrAssignIter<std::flat_map<int, ConstructFrom<V>>, const int&, V>);
73static_assert(!CanInsertOrAssignIter<std::flat_map<int, AssignFrom<V>>, const int&, V>);
74
75static_assert(CanInsertOrAssignIter<std::flat_map<int, ConstructAndAssignFrom<V>>, int&&, V>);
76static_assert(!CanInsertOrAssignIter<std::flat_map<int, ConstructAndAssignFrom<V>>, int&&, int>);
77static_assert(!CanInsertOrAssignIter<std::flat_map<int, ConstructFrom<V>>, int&&, V>);
78static_assert(!CanInsertOrAssignIter<std::flat_map<int, AssignFrom<V>>, int&&, V>);
79
80template <class KeyContainer, class ValueContainer>
81void test_cv_key() {
82 using Key = typename KeyContainer::value_type;
83 using Value = typename ValueContainer::value_type;
84 using M = std::flat_map<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
85 { // pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
86 using R = std::pair<typename M::iterator, bool>;
87 M m;
88 for (int i = 0; i < 20; i += 2)
89 m.emplace(i, Moveable(i, (double)i));
90 assert(m.size() == 10);
91
92 for (int i = 0; i < 20; i += 2) {
93 Moveable mv(i + 1, i + 1);
94 std::same_as<R> decltype(auto) r1 = m.insert_or_assign(i, std::move(mv));
95 assert(m.size() == 10);
96 assert(!r1.second); // was not inserted
97 assert(mv.moved()); // was moved from
98 assert(r1.first->first == i); // key
99 assert(r1.first->second.get() == i + 1); // value
100 }
101
102 Moveable mv1(5, 5.0);
103 std::same_as<R> decltype(auto) r2 = m.insert_or_assign(-1, std::move(mv1));
104 assert(m.size() == 11);
105 assert(r2.second); // was inserted
106 assert(mv1.moved()); // was moved from
107 assert(r2.first->first == -1); // key
108 assert(r2.first->second.get() == 5); // value
109
110 Moveable mv2(9, 9.0);
111 std::same_as<R> decltype(auto) r3 = m.insert_or_assign(3, std::move(mv2));
112 assert(m.size() == 12);
113 assert(r3.second); // was inserted
114 assert(mv2.moved()); // was moved from
115 assert(r3.first->first == 3); // key
116 assert(r3.first->second.get() == 9); // value
117
118 Moveable mv3(-1, 5.0);
119 std::same_as<R> decltype(auto) r4 = m.insert_or_assign(117, std::move(mv3));
120 assert(m.size() == 13);
121 assert(r4.second); // was inserted
122 assert(mv3.moved()); // was moved from
123 assert(r4.first->first == 117); // key
124 assert(r4.first->second.get() == -1); // value
125 }
126
127 { // iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
128 M m;
129 using R = M::iterator;
130 for (int i = 0; i < 20; i += 2)
131 m.emplace(i, Moveable(i, (double)i));
132 assert(m.size() == 10);
133 typename M::const_iterator it = m.find(2);
134
135 Moveable mv1(3, 3.0);
136 std::same_as<R> decltype(auto) r1 = m.insert_or_assign(it, 2, std::move(mv1));
137 assert(m.size() == 10);
138 assert(mv1.moved()); // was moved from
139 assert(r1->first == 2); // key
140 assert(r1->second.get() == 3); // value
141
142 Moveable mv2(5, 5.0);
143 std::same_as<R> decltype(auto) r2 = m.insert_or_assign(it, 3, std::move(mv2));
144 assert(m.size() == 11);
145 assert(mv2.moved()); // was moved from
146 assert(r2->first == 3); // key
147 assert(r2->second.get() == 5); // value
148
149 // wrong hint: begin()
150 Moveable mv3(7, 7.0);
151 std::same_as<R> decltype(auto) r3 = m.insert_or_assign(m.begin(), 4, std::move(mv3));
152 assert(m.size() == 11);
153 assert(mv3.moved()); // was moved from
154 assert(r3->first == 4); // key
155 assert(r3->second.get() == 7); // value
156
157 Moveable mv4(9, 9.0);
158 std::same_as<R> decltype(auto) r4 = m.insert_or_assign(m.begin(), 5, std::move(mv4));
159 assert(m.size() == 12);
160 assert(mv4.moved()); // was moved from
161 assert(r4->first == 5); // key
162 assert(r4->second.get() == 9); // value
163
164 // wrong hint: end()
165 Moveable mv5(11, 11.0);
166 std::same_as<R> decltype(auto) r5 = m.insert_or_assign(m.end(), 6, std::move(mv5));
167 assert(m.size() == 12);
168 assert(mv5.moved()); // was moved from
169 assert(r5->first == 6); // key
170 assert(r5->second.get() == 11); // value
171
172 Moveable mv6(13, 13.0);
173 std::same_as<R> decltype(auto) r6 = m.insert_or_assign(m.end(), 7, std::move(mv6));
174 assert(m.size() == 13);
175 assert(mv6.moved()); // was moved from
176 assert(r6->first == 7); // key
177 assert(r6->second.get() == 13); // value
178
179 // wrong hint: third element
180 Moveable mv7(15, 15.0);
181 std::same_as<R> decltype(auto) r7 = m.insert_or_assign(std::next(m.begin(), 2), 8, std::move(mv7));
182 assert(m.size() == 13);
183 assert(mv7.moved()); // was moved from
184 assert(r7->first == 8); // key
185 assert(r7->second.get() == 15); // value
186
187 Moveable mv8(17, 17.0);
188 std::same_as<R> decltype(auto) r8 = m.insert_or_assign(std::next(m.begin(), 2), 9, std::move(mv8));
189 assert(m.size() == 14);
190 assert(mv8.moved()); // was moved from
191 assert(r8->first == 9); // key
192 assert(r8->second.get() == 17); // value
193 }
194}
195
196template <class KeyContainer, class ValueContainer>
197void test_rv_key() {
198 using Key = typename KeyContainer::value_type;
199 using Value = typename ValueContainer::value_type;
200 using M = std::flat_map<Key, Value, TransparentComparator, KeyContainer, ValueContainer>;
201
202 { // pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
203 using R = std::pair<typename M::iterator, bool>;
204 M m;
205 for (int i = 0; i < 20; i += 2)
206 m.emplace(Moveable(i, (double)i), Moveable(i + 1, (double)i + 1));
207 assert(m.size() == 10);
208
209 Moveable mvkey1(2, 2.0);
210 Moveable mv1(4, 4.0);
211 std::same_as<R> decltype(auto) r1 = m.insert_or_assign(std::move(mvkey1), std::move(mv1));
212 assert(m.size() == 10);
213 assert(!r1.second); // was not inserted
214 assert(!mvkey1.moved()); // was not moved from
215 assert(mv1.moved()); // was moved from
216 assert(r1.first->first == mvkey1); // key
217 assert(r1.first->second.get() == 4); // value
218
219 Moveable mvkey2(3, 3.0);
220 Moveable mv2(5, 5.0);
221 std::same_as<R> decltype(auto) r2 = m.try_emplace(std::move(mvkey2), std::move(mv2));
222 assert(m.size() == 11);
223 assert(r2.second); // was inserted
224 assert(mv2.moved()); // was moved from
225 assert(mvkey2.moved()); // was moved from
226 assert(r2.first->first.get() == 3); // key
227 assert(r2.first->second.get() == 5); // value
228 }
229 { // iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
230 using R = M::iterator;
231 M m;
232 for (int i = 0; i < 20; i += 2)
233 m.emplace(Moveable(i, (double)i), Moveable(i + 1, (double)i + 1));
234 assert(m.size() == 10);
235 typename M::const_iterator it = std::next(m.cbegin());
236
237 Moveable mvkey1(2, 2.0);
238 Moveable mv1(4, 4.0);
239 std::same_as<R> decltype(auto) r1 = m.insert_or_assign(it, std::move(mvkey1), std::move(mv1));
240 assert(m.size() == 10);
241 assert(mv1.moved()); // was moved from
242 assert(!mvkey1.moved()); // was not moved from
243 assert(r1->first == mvkey1); // key
244 assert(r1->second.get() == 4); // value
245
246 Moveable mvkey2(3, 3.0);
247 Moveable mv2(5, 5.0);
248 std::same_as<R> decltype(auto) r2 = m.insert_or_assign(it, std::move(mvkey2), std::move(mv2));
249 assert(m.size() == 11);
250 assert(mv2.moved()); // was moved from
251 assert(mvkey2.moved()); // was moved from
252 assert(r2->first.get() == 3); // key
253 assert(r2->second.get() == 5); // value
254
255 // wrong hint: begin()
256 Moveable mvkey3(6, 6.0);
257 Moveable mv3(8, 8.0);
258 std::same_as<R> decltype(auto) r3 = m.insert_or_assign(m.begin(), std::move(mvkey3), std::move(mv3));
259 assert(m.size() == 11);
260 assert(mv3.moved()); // was moved from
261 assert(!mvkey3.moved()); // was not moved from
262 assert(r3->first == mvkey3); // key
263 assert(r3->second.get() == 8); // value
264
265 Moveable mvkey4(7, 7.0);
266 Moveable mv4(9, 9.0);
267 std::same_as<R> decltype(auto) r4 = m.insert_or_assign(m.begin(), std::move(mvkey4), std::move(mv4));
268 assert(m.size() == 12);
269 assert(mv4.moved()); // was moved from
270 assert(mvkey4.moved()); // was moved from
271 assert(r4->first.get() == 7); // key
272 assert(r4->second.get() == 9); // value
273
274 // wrong hint: end()
275 Moveable mvkey5(8, 8.0);
276 Moveable mv5(10, 10.0);
277 std::same_as<R> decltype(auto) r5 = m.insert_or_assign(m.end(), std::move(mvkey5), std::move(mv5));
278 assert(m.size() == 12);
279 assert(mv5.moved()); // was moved from
280 assert(!mvkey5.moved()); // was not moved from
281 assert(r5->first == mvkey5); // key
282 assert(r5->second.get() == 10); // value
283
284 Moveable mvkey6(9, 9.0);
285 Moveable mv6(11, 11.0);
286 std::same_as<R> decltype(auto) r6 = m.insert_or_assign(m.end(), std::move(mvkey6), std::move(mv6));
287 assert(m.size() == 13);
288 assert(mv6.moved()); // was moved from
289 assert(mvkey6.moved()); // was moved from
290 assert(r6->first.get() == 9); // key
291 assert(r6->second.get() == 11); // value
292
293 // wrong hint: third element
294 Moveable mvkey7(10, 10.0);
295 Moveable mv7(12, 12.0);
296 std::same_as<R> decltype(auto) r7 = m.insert_or_assign(std::next(m.begin(), 2), std::move(mvkey7), std::move(mv7));
297 assert(m.size() == 13);
298 assert(mv7.moved()); // was moved from
299 assert(!mvkey7.moved()); // was not moved from
300 assert(r7->first == mvkey7); // key
301 assert(r7->second.get() == 12); // value
302
303 Moveable mvkey8(11, 11.0);
304 Moveable mv8(13, 13.0);
305 std::same_as<R> decltype(auto) r8 = m.insert_or_assign(std::next(m.begin(), 2), std::move(mvkey8), std::move(mv8));
306 assert(m.size() == 14);
307 assert(mv8.moved()); // was moved from
308 assert(mvkey8.moved()); // was moved from
309 assert(r8->first.get() == 11); // key
310 assert(r8->second.get() == 13); // value
311 }
312}
313
314int main(int, char**) {
315 test_cv_key<std::vector<int>, std::vector<Moveable>>();
316 test_cv_key<std::deque<int>, std::vector<Moveable>>();
317 test_cv_key<MinSequenceContainer<int>, MinSequenceContainer<Moveable>>();
318 test_cv_key<std::vector<int, min_allocator<int>>, std::vector<Moveable, min_allocator<Moveable>>>();
319
320 test_rv_key<std::vector<Moveable>, std::vector<Moveable>>();
321 test_rv_key<std::deque<Moveable>, std::vector<Moveable>>();
322 test_rv_key<MinSequenceContainer<Moveable>, MinSequenceContainer<Moveable>>();
323 test_rv_key<std::vector<Moveable, min_allocator<Moveable>>, std::vector<Moveable, min_allocator<Moveable>>>();
324
325 return 0;
326}
327

source code of libcxx/test/std/containers/container.adaptors/flat.map/flat.map.modifiers/insert_or_assign.pass.cpp