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 |
10 | |
11 | // <map> |
12 | |
13 | // class map |
14 | |
15 | // template <class M> |
16 | // pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); // C++17 |
17 | // template <class M> |
18 | // pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); // C++17 |
19 | // template <class M> |
20 | // iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); // C++17 |
21 | // template <class M> |
22 | // iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); // C++17 |
23 | |
24 | #include <map> |
25 | #include <cassert> |
26 | #include <iterator> |
27 | #include <tuple> |
28 | |
29 | #include "test_macros.h" |
30 | |
31 | class Moveable { |
32 | Moveable(const Moveable&); |
33 | Moveable& operator=(const Moveable&); |
34 | |
35 | int int_; |
36 | double double_; |
37 | |
38 | public: |
39 | Moveable() : int_(0), double_(0) {} |
40 | Moveable(int i, double d) : int_(i), double_(d) {} |
41 | Moveable(Moveable&& x) : int_(x.int_), double_(x.double_) { |
42 | x.int_ = -1; |
43 | x.double_ = -1; |
44 | } |
45 | Moveable& operator=(Moveable&& x) { |
46 | int_ = x.int_; |
47 | x.int_ = -1; |
48 | double_ = x.double_; |
49 | x.double_ = -1; |
50 | return *this; |
51 | } |
52 | |
53 | bool operator==(const Moveable& x) const { return int_ == x.int_ && double_ == x.double_; } |
54 | bool operator<(const Moveable& x) const { return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_); } |
55 | |
56 | int get() const { return int_; } |
57 | bool moved() const { return int_ == -1; } |
58 | }; |
59 | |
60 | int main(int, char**) { |
61 | { // pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); |
62 | typedef std::map<int, Moveable> M; |
63 | typedef std::pair<M::iterator, bool> R; |
64 | M m; |
65 | R r; |
66 | for (int i = 0; i < 20; i += 2) |
67 | m.emplace(args&: i, args: Moveable(i, (double)i)); |
68 | assert(m.size() == 10); |
69 | |
70 | for (int i = 0; i < 20; i += 2) { |
71 | Moveable mv(i + 1, i + 1); |
72 | r = m.insert_or_assign(k: i, obj: std::move(mv)); |
73 | assert(m.size() == 10); |
74 | assert(!r.second); // was not inserted |
75 | assert(mv.moved()); // was moved from |
76 | assert(r.first->first == i); // key |
77 | assert(r.first->second.get() == i + 1); // value |
78 | } |
79 | |
80 | Moveable mv1(5, 5.0); |
81 | r = m.insert_or_assign(k: -1, obj: std::move(mv1)); |
82 | assert(m.size() == 11); |
83 | assert(r.second); // was inserted |
84 | assert(mv1.moved()); // was moved from |
85 | assert(r.first->first == -1); // key |
86 | assert(r.first->second.get() == 5); // value |
87 | |
88 | Moveable mv2(9, 9.0); |
89 | r = m.insert_or_assign(k: 3, obj: std::move(mv2)); |
90 | assert(m.size() == 12); |
91 | assert(r.second); // was inserted |
92 | assert(mv2.moved()); // was moved from |
93 | assert(r.first->first == 3); // key |
94 | assert(r.first->second.get() == 9); // value |
95 | |
96 | Moveable mv3(-1, 5.0); |
97 | r = m.insert_or_assign(k: 117, obj: std::move(mv3)); |
98 | assert(m.size() == 13); |
99 | assert(r.second); // was inserted |
100 | assert(mv3.moved()); // was moved from |
101 | assert(r.first->first == 117); // key |
102 | assert(r.first->second.get() == -1); // value |
103 | } |
104 | { // pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); |
105 | typedef std::map<Moveable, Moveable> M; |
106 | typedef std::pair<M::iterator, bool> R; |
107 | M m; |
108 | R r; |
109 | for (int i = 0; i < 20; i += 2) |
110 | m.emplace(args: Moveable(i, (double)i), args: Moveable(i + 1, (double)i + 1)); |
111 | assert(m.size() == 10); |
112 | |
113 | Moveable mvkey1(2, 2.0); |
114 | Moveable mv1(4, 4.0); |
115 | r = m.insert_or_assign(k: std::move(mvkey1), obj: std::move(mv1)); |
116 | assert(m.size() == 10); |
117 | assert(!r.second); // was not inserted |
118 | assert(!mvkey1.moved()); // was not moved from |
119 | assert(mv1.moved()); // was moved from |
120 | assert(r.first->first == mvkey1); // key |
121 | assert(r.first->second.get() == 4); // value |
122 | |
123 | Moveable mvkey2(3, 3.0); |
124 | Moveable mv2(5, 5.0); |
125 | r = m.try_emplace(k: std::move(mvkey2), args: std::move(mv2)); |
126 | assert(m.size() == 11); |
127 | assert(r.second); // was inserted |
128 | assert(mv2.moved()); // was moved from |
129 | assert(mvkey2.moved()); // was moved from |
130 | assert(r.first->first.get() == 3); // key |
131 | assert(r.first->second.get() == 5); // value |
132 | } |
133 | { // iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); |
134 | typedef std::map<int, Moveable> M; |
135 | M m; |
136 | M::iterator r; |
137 | for (int i = 0; i < 20; i += 2) |
138 | m.emplace(args&: i, args: Moveable(i, (double)i)); |
139 | assert(m.size() == 10); |
140 | M::const_iterator it = m.find(x: 2); |
141 | |
142 | Moveable mv1(3, 3.0); |
143 | const int key1 = 2; |
144 | r = m.insert_or_assign(hint: it, k: key1, obj: std::move(mv1)); |
145 | assert(m.size() == 10); |
146 | assert(mv1.moved()); // was moved from |
147 | assert(r->first == 2); // key |
148 | assert(r->second.get() == 3); // value |
149 | |
150 | Moveable mv2(5, 5.0); |
151 | const int key2 = 3; |
152 | r = m.insert_or_assign(hint: it, k: key2, obj: std::move(mv2)); |
153 | assert(m.size() == 11); |
154 | assert(mv2.moved()); // was moved from |
155 | assert(r->first == 3); // key |
156 | assert(r->second.get() == 5); // value |
157 | |
158 | // wrong hint: begin() |
159 | Moveable mv3(7, 7.0); |
160 | const int key3 = 4; |
161 | r = m.insert_or_assign(hint: m.begin(), k: key3, obj: std::move(mv3)); |
162 | assert(m.size() == 11); |
163 | assert(mv3.moved()); // was moved from |
164 | assert(r->first == 4); // key |
165 | assert(r->second.get() == 7); // value |
166 | |
167 | Moveable mv4(9, 9.0); |
168 | const int key4 = 5; |
169 | r = m.insert_or_assign(hint: m.begin(), k: key4, obj: std::move(mv4)); |
170 | assert(m.size() == 12); |
171 | assert(mv4.moved()); // was moved from |
172 | assert(r->first == 5); // key |
173 | assert(r->second.get() == 9); // value |
174 | |
175 | // wrong hint: end() |
176 | Moveable mv5(11, 11.0); |
177 | const int key5 = 6; |
178 | r = m.insert_or_assign(hint: m.end(), k: key5, obj: std::move(mv5)); |
179 | assert(m.size() == 12); |
180 | assert(mv5.moved()); // was moved from |
181 | assert(r->first == 6); // key |
182 | assert(r->second.get() == 11); // value |
183 | |
184 | Moveable mv6(13, 13.0); |
185 | const int key6 = 7; |
186 | r = m.insert_or_assign(hint: m.end(), k: key6, obj: std::move(mv6)); |
187 | assert(m.size() == 13); |
188 | assert(mv6.moved()); // was moved from |
189 | assert(r->first == 7); // key |
190 | assert(r->second.get() == 13); // value |
191 | |
192 | // wrong hint: third element |
193 | Moveable mv7(15, 15.0); |
194 | const int key7 = 8; |
195 | r = m.insert_or_assign(hint: std::next(x: m.begin(), n: 2), k: key7, obj: std::move(mv7)); |
196 | assert(m.size() == 13); |
197 | assert(mv7.moved()); // was moved from |
198 | assert(r->first == 8); // key |
199 | assert(r->second.get() == 15); // value |
200 | |
201 | Moveable mv8(17, 17.0); |
202 | const int key8 = 9; |
203 | r = m.insert_or_assign(hint: std::next(x: m.begin(), n: 2), k: key8, obj: std::move(mv8)); |
204 | assert(m.size() == 14); |
205 | assert(mv8.moved()); // was moved from |
206 | assert(r->first == 9); // key |
207 | assert(r->second.get() == 17); // value |
208 | } |
209 | { // iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); |
210 | typedef std::map<Moveable, Moveable> M; |
211 | M m; |
212 | M::iterator r; |
213 | for (int i = 0; i < 20; i += 2) |
214 | m.emplace(args: Moveable(i, (double)i), args: Moveable(i + 1, (double)i + 1)); |
215 | assert(m.size() == 10); |
216 | M::const_iterator it = std::next(x: m.cbegin()); |
217 | |
218 | Moveable mvkey1(2, 2.0); |
219 | Moveable mv1(4, 4.0); |
220 | r = m.insert_or_assign(hint: it, k: std::move(mvkey1), obj: std::move(mv1)); |
221 | assert(m.size() == 10); |
222 | assert(mv1.moved()); // was moved from |
223 | assert(!mvkey1.moved()); // was not moved from |
224 | assert(r->first == mvkey1); // key |
225 | assert(r->second.get() == 4); // value |
226 | |
227 | Moveable mvkey2(3, 3.0); |
228 | Moveable mv2(5, 5.0); |
229 | r = m.insert_or_assign(hint: it, k: std::move(mvkey2), obj: std::move(mv2)); |
230 | assert(m.size() == 11); |
231 | assert(mv2.moved()); // was moved from |
232 | assert(mvkey2.moved()); // was moved from |
233 | assert(r->first.get() == 3); // key |
234 | assert(r->second.get() == 5); // value |
235 | |
236 | // wrong hint: begin() |
237 | Moveable mvkey3(6, 6.0); |
238 | Moveable mv3(8, 8.0); |
239 | r = m.insert_or_assign(hint: m.begin(), k: std::move(mvkey3), obj: std::move(mv3)); |
240 | assert(m.size() == 11); |
241 | assert(mv3.moved()); // was moved from |
242 | assert(!mvkey3.moved()); // was not moved from |
243 | assert(r->first == mvkey3); // key |
244 | assert(r->second.get() == 8); // value |
245 | |
246 | Moveable mvkey4(7, 7.0); |
247 | Moveable mv4(9, 9.0); |
248 | r = m.insert_or_assign(hint: m.begin(), k: std::move(mvkey4), obj: std::move(mv4)); |
249 | assert(m.size() == 12); |
250 | assert(mv4.moved()); // was moved from |
251 | assert(mvkey4.moved()); // was moved from |
252 | assert(r->first.get() == 7); // key |
253 | assert(r->second.get() == 9); // value |
254 | |
255 | // wrong hint: end() |
256 | Moveable mvkey5(8, 8.0); |
257 | Moveable mv5(10, 10.0); |
258 | r = m.insert_or_assign(hint: m.end(), k: std::move(mvkey5), obj: std::move(mv5)); |
259 | assert(m.size() == 12); |
260 | assert(mv5.moved()); // was moved from |
261 | assert(!mvkey5.moved()); // was not moved from |
262 | assert(r->first == mvkey5); // key |
263 | assert(r->second.get() == 10); // value |
264 | |
265 | Moveable mvkey6(9, 9.0); |
266 | Moveable mv6(11, 11.0); |
267 | r = m.insert_or_assign(hint: m.end(), k: std::move(mvkey6), obj: std::move(mv6)); |
268 | assert(m.size() == 13); |
269 | assert(mv6.moved()); // was moved from |
270 | assert(mvkey6.moved()); // was moved from |
271 | assert(r->first.get() == 9); // key |
272 | assert(r->second.get() == 11); // value |
273 | |
274 | // wrong hint: third element |
275 | Moveable mvkey7(10, 10.0); |
276 | Moveable mv7(12, 12.0); |
277 | r = m.insert_or_assign(hint: std::next(x: m.begin(), n: 2), k: std::move(mvkey7), obj: std::move(mv7)); |
278 | assert(m.size() == 13); |
279 | assert(mv7.moved()); // was moved from |
280 | assert(!mvkey7.moved()); // was not moved from |
281 | assert(r->first == mvkey7); // key |
282 | assert(r->second.get() == 12); // value |
283 | |
284 | Moveable mvkey8(11, 11.0); |
285 | Moveable mv8(13, 13.0); |
286 | r = m.insert_or_assign(hint: std::next(x: m.begin(), n: 2), k: std::move(mvkey8), obj: std::move(mv8)); |
287 | assert(m.size() == 14); |
288 | assert(mv8.moved()); // was moved from |
289 | assert(mvkey8.moved()); // was moved from |
290 | assert(r->first.get() == 11); // key |
291 | assert(r->second.get() == 13); // value |
292 | } |
293 | |
294 | return 0; |
295 | } |
296 | |