1
2// Copyright 2022 Christian Mazakas.
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
5
6#if !defined(BOOST_UNORDERED_FOA_TESTS)
7#error "This test is only for the FOA-style conatiners"
8#endif
9
10#include "../helpers/test.hpp"
11#include "../helpers/unordered.hpp"
12
13#include <boost/config.hpp>
14
15struct move_only
16{
17 int x_ = -1;
18
19 move_only() = default;
20 move_only(int x) : x_{x} {}
21 move_only(move_only const&) = delete;
22 move_only(move_only&&) = default;
23
24 friend bool operator==(move_only const& lhs, move_only const& rhs)
25 {
26 return lhs.x_ == rhs.x_;
27 }
28};
29
30namespace std {
31
32 template <> struct hash<move_only>
33 {
34 std::size_t operator()(move_only const& mo) const noexcept
35 {
36 return std::hash<int>()(mo.x_);
37 }
38 };
39
40} // namespace std
41
42#ifndef BOOST_UNORDERED_NO_INIT_TYPE_TESTS
43
44struct immovable
45{
46 int x_ = -1;
47
48 immovable() = default;
49 immovable(int x) : x_{x} {}
50 immovable(immovable const&) = delete;
51 immovable(immovable&&) = delete;
52
53 friend bool operator==(immovable const& lhs, immovable const& rhs)
54 {
55 return lhs.x_ == rhs.x_;
56 }
57};
58
59namespace std {
60
61 template <> struct hash<immovable>
62 {
63 std::size_t operator()(immovable const& im) const noexcept
64 {
65 return std::hash<int>()(im.x_);
66 }
67 };
68
69} // namespace std
70
71#endif
72
73struct raii_tracker
74{
75 static unsigned move_constructs;
76 static unsigned copy_constructs;
77
78 int x_ = -1;
79
80 static void reset_counts()
81 {
82 move_constructs = 0;
83 copy_constructs = 0;
84 }
85
86 raii_tracker() {}
87 raii_tracker(int x) : x_{x} {}
88 raii_tracker(raii_tracker const& rhs) : x_{rhs.x_} { ++copy_constructs; }
89
90 raii_tracker(raii_tracker&& rhs) noexcept : x_{rhs.x_}
91 {
92 rhs.x_ = -1;
93
94 ++move_constructs;
95 }
96
97 friend bool operator==(raii_tracker const& lhs, raii_tracker const& rhs)
98 {
99 return lhs.x_ == rhs.x_;
100 }
101};
102
103namespace std {
104
105 template <> struct hash<raii_tracker>
106 {
107 std::size_t operator()(raii_tracker const& rt) const noexcept
108 {
109 return std::hash<int>()(rt.x_);
110 }
111 };
112
113} // namespace std
114
115unsigned raii_tracker::move_constructs = 0;
116unsigned raii_tracker::copy_constructs = 0;
117
118static void test_move_only()
119{
120 int const v = 128;
121
122 boost::unordered_flat_map<move_only, int, std::hash<move_only> > map;
123
124 using init_type = decltype(map)::init_type;
125 static_assert(std::is_same<std::pair<move_only, int>, init_type>::value, "");
126
127 map.insert(value: std::make_pair(x: move_only(1), y: v));
128 map.insert(value: {move_only(2), v});
129
130 BOOST_TEST_EQ(map.size(), 2u);
131
132 map.rehash(n: 1024);
133 BOOST_TEST_GE(map.bucket_count(), 1024u);
134}
135
136static void test_insert_tracking()
137{
138 raii_tracker::reset_counts();
139
140 BOOST_TEST_EQ(raii_tracker::copy_constructs, 0u);
141 BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
142
143 boost::unordered_flat_map<raii_tracker, raii_tracker,
144 std::hash<raii_tracker> >
145 map;
146
147 {
148 std::pair<raii_tracker, raii_tracker> value{1, 2};
149
150 map.insert(value);
151
152 BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
153 BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
154 }
155
156 {
157 std::pair<raii_tracker, raii_tracker> value{2, 3};
158
159 map.insert(value: std::move(value));
160
161 BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
162 BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
163 }
164
165 {
166 std::pair<raii_tracker const, raii_tracker> value{3, 4};
167
168 map.insert(value);
169
170 BOOST_TEST_EQ(raii_tracker::copy_constructs, 4u);
171 BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
172 }
173
174 {
175 std::pair<raii_tracker const, raii_tracker> value{4, 5};
176
177 map.insert(value: std::move(value));
178
179 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
180 BOOST_TEST_EQ(raii_tracker::move_constructs, 3u);
181 }
182
183 {
184 map.insert(value: std::make_pair(x: 5, y: 6));
185 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
186 BOOST_TEST_EQ(raii_tracker::move_constructs, 5u);
187 }
188
189 {
190 map.insert(value: {6, 7});
191 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
192 BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
193 }
194
195 BOOST_TEST_EQ(map.size(), 6u);
196
197 map.rehash(n: 1024);
198 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
199 BOOST_TEST_EQ(raii_tracker::move_constructs, 7u + 2u * map.size());
200}
201
202static void test_insert_hint_tracking()
203{
204 raii_tracker::reset_counts();
205
206 BOOST_TEST_EQ(raii_tracker::copy_constructs, 0u);
207 BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
208
209 boost::unordered_flat_map<raii_tracker, raii_tracker,
210 std::hash<raii_tracker> >
211 map;
212
213 {
214 std::pair<raii_tracker, raii_tracker> value{1, 2};
215
216 map.insert(map.begin(), value);
217
218 BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
219 BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
220 }
221
222 {
223 std::pair<raii_tracker, raii_tracker> value{2, 3};
224
225 map.insert(value: std::move(value));
226
227 BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
228 BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
229 }
230
231 {
232 std::pair<raii_tracker const, raii_tracker> value{3, 4};
233
234 map.insert(map.begin(), value);
235
236 BOOST_TEST_EQ(raii_tracker::copy_constructs, 4u);
237 BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
238 }
239
240 {
241 std::pair<raii_tracker const, raii_tracker> value{4, 5};
242
243 map.insert(map.begin(), value: std::move(value));
244
245 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
246 BOOST_TEST_EQ(raii_tracker::move_constructs, 3u);
247 }
248
249 {
250 map.insert(map.begin(), value: std::make_pair(x: 5, y: 6));
251 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
252 BOOST_TEST_EQ(raii_tracker::move_constructs, 5u);
253 }
254
255 {
256 map.insert(map.begin(), value: {6, 7});
257 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
258 BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
259 }
260
261 BOOST_TEST_EQ(map.size(), 6u);
262
263 map.rehash(n: 1024);
264 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
265 BOOST_TEST_EQ(raii_tracker::move_constructs, 7u + 2u * map.size());
266}
267
268static void test_immovable()
269{
270#ifndef BOOST_UNORDERED_NO_INIT_TYPE_TESTS
271 int const v = 128;
272
273 boost::unordered_node_map<immovable, int, std::hash<immovable> > map;
274
275 using init_type = decltype(map)::init_type;
276 static_assert(std::is_same<std::pair<immovable, int>, init_type>::value, "");
277
278 map.emplace(args: 1, args: v);
279 map.emplace(args: 2, args: v);
280
281 BOOST_TEST_EQ(map.size(), 2u);
282
283 map.rehash(n: 1024);
284 BOOST_TEST_GE(map.bucket_count(), 1024u);
285#endif
286}
287
288static void test_insert_node_tracking()
289{
290 raii_tracker::reset_counts();
291
292 BOOST_TEST_EQ(raii_tracker::copy_constructs, 0u);
293 BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
294
295 boost::unordered_node_map<raii_tracker, raii_tracker,
296 std::hash<raii_tracker> >
297 map;
298
299 {
300 std::pair<raii_tracker, raii_tracker> value{1, 2};
301
302 map.insert(value);
303
304 BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
305 BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
306 }
307
308 {
309 std::pair<raii_tracker, raii_tracker> value{2, 3};
310
311 map.insert(value: std::move(value));
312
313 BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
314 BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
315 }
316
317 {
318 std::pair<raii_tracker const, raii_tracker> value{3, 4};
319
320 map.insert(value);
321
322 BOOST_TEST_EQ(raii_tracker::copy_constructs, 4u);
323 BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
324 }
325
326 {
327 std::pair<raii_tracker const, raii_tracker> value{4, 5};
328
329 map.insert(value: std::move(value));
330
331 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
332 BOOST_TEST_EQ(raii_tracker::move_constructs, 3u);
333 }
334
335 {
336 map.insert(value: std::make_pair(x: 5, y: 6));
337 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
338 BOOST_TEST_EQ(raii_tracker::move_constructs, 5u);
339 }
340
341 {
342 map.insert(value: {6, 7});
343 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
344 BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
345 }
346
347 BOOST_TEST_EQ(map.size(), 6u);
348
349 map.rehash(n: 1024);
350 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
351 BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
352}
353
354static void test_insert_hint_node_tracking()
355{
356 raii_tracker::reset_counts();
357
358 BOOST_TEST_EQ(raii_tracker::copy_constructs, 0u);
359 BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
360
361 boost::unordered_node_map<raii_tracker, raii_tracker,
362 std::hash<raii_tracker> >
363 map;
364
365 {
366 std::pair<raii_tracker, raii_tracker> value{1, 2};
367
368 map.insert(map.begin(), value);
369
370 BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
371 BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
372 }
373
374 {
375 std::pair<raii_tracker, raii_tracker> value{2, 3};
376
377 map.insert(value: std::move(value));
378
379 BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
380 BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
381 }
382
383 {
384 std::pair<raii_tracker const, raii_tracker> value{3, 4};
385
386 map.insert(map.begin(), value);
387
388 BOOST_TEST_EQ(raii_tracker::copy_constructs, 4u);
389 BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
390 }
391
392 {
393 std::pair<raii_tracker const, raii_tracker> value{4, 5};
394
395 map.insert(map.begin(), value: std::move(value));
396
397 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
398 BOOST_TEST_EQ(raii_tracker::move_constructs, 3u);
399 }
400
401 {
402 map.insert(map.begin(), value: std::make_pair(x: 5, y: 6));
403 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
404 BOOST_TEST_EQ(raii_tracker::move_constructs, 5u);
405 }
406
407 {
408 map.insert(map.begin(), value: {6, 7});
409 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
410 BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
411 }
412
413 BOOST_TEST_EQ(map.size(), 6u);
414
415 map.rehash(n: 1024);
416 BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
417 BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
418}
419
420int main()
421{
422 test_move_only();
423 test_insert_tracking();
424 test_insert_hint_tracking();
425
426 test_immovable();
427 test_insert_node_tracking();
428 test_insert_hint_node_tracking();
429
430 return boost::report_errors();
431}
432

source code of boost/libs/unordered/test/unordered/init_type_insert_tests.cpp