1
2// Copyright (C) 2022-2023 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#include "../helpers/equivalent.hpp"
7#include "../helpers/invariants.hpp"
8#include "../helpers/random_values.hpp"
9#include "../helpers/test.hpp"
10#include "../helpers/tracker.hpp"
11#include "../helpers/unordered.hpp"
12#include "../objects/cxx11_allocator.hpp"
13#include "../objects/test.hpp"
14
15#include <boost/core/ignore_unused.hpp>
16#include <iterator>
17
18#if defined(BOOST_MSVC)
19#pragma warning(disable : 4127) // conditional expression is constant
20#endif
21
22namespace move_tests {
23 test::seed_t initialize_seed(98624);
24#define BOOST_UNORDERED_TEST_MOVING 1
25
26 template <class T> T empty(T*) { return T(); }
27
28 template <class T>
29 T create(test::random_values<T> const& v, test::object_count& count)
30 {
31 T x(v.begin(), v.end());
32 count = test::global_object_count;
33 return x;
34 }
35
36 template <class T>
37 T create(test::random_values<T> const& v, test::object_count& count,
38 typename T::hasher hf, typename T::key_equal eq,
39 typename T::allocator_type al, float mlf)
40 {
41 T x(0, hf, eq, al);
42 x.max_load_factor(mlf);
43 x.insert(v.begin(), v.end());
44 count = test::global_object_count;
45 return x;
46 }
47
48 template <class T> T const& get_key(T const& t) { return t; }
49
50 template <class K, class V> K const& get_key(std::pair<K const, V> const& kv)
51 {
52 return kv.first;
53 }
54
55 template <class T> T const& get_value(T const& t) { return t; }
56
57 template <class K, class V>
58 K const& get_value(std::pair<K const, V> const& kv)
59 {
60 return kv.second;
61 }
62
63 template <class T>
64 static void insert_range(T& y, test::random_values<T> const& v)
65 {
66 y.insert(v.begin(), v.end());
67 BOOST_TEST_EQ(y.size(),
68 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
69 }
70
71 template <class T>
72 static void insert_single(T& y, test::random_values<T> const& v)
73 {
74 y.insert(*v.begin());
75 BOOST_TEST_EQ(y.size(),
76 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
77 }
78
79 template <class T>
80 static void insert_single_hint(T& y, test::random_values<T> const& v)
81 {
82 y.insert(y.end(), *v.begin());
83 BOOST_TEST_EQ(y.size(),
84 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
85 }
86
87 template <class T> struct insert_or_assign_invoker
88 {
89 void operator()(T&, test::random_values<T> const&) {}
90 };
91
92 template <class Key, class T, class Hash, class KeyEqual, class Allocator>
93 struct insert_or_assign_invoker<
94 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
95 {
96 void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
97 test::random_values<
98 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
99 {
100 typedef typename boost::unordered_map<Key, T, Hash, KeyEqual,
101 Allocator>::size_type size_type;
102
103 y.insert_or_assign(get_key(*v.begin()), get_value(*v.begin()));
104 BOOST_TEST_EQ(
105 y.size(), static_cast<size_type>(std::distance(y.begin(), y.end())));
106 }
107 };
108
109 template <class T>
110 static void insert_or_assign(T& y, test::random_values<T> const& v)
111 {
112 insert_or_assign_invoker<T>()(y, v);
113 }
114
115 template <class T> struct insert_or_assign_hint_invoker
116 {
117 void operator()(T&, test::random_values<T> const&) {}
118 };
119
120 template <class Key, class T, class Hash, class KeyEqual, class Allocator>
121 struct insert_or_assign_hint_invoker<
122 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
123 {
124 void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
125 test::random_values<
126 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
127 {
128 typedef typename boost::unordered_map<Key, T, Hash, KeyEqual,
129 Allocator>::size_type size_type;
130 y.insert_or_assign(y.end(), get_key(*v.begin()), get_value(*v.begin()));
131 BOOST_TEST_EQ(
132 y.size(), static_cast<size_type>(std::distance(y.begin(), y.end())));
133 }
134 };
135
136 template <class T>
137 static void insert_or_assign_hint(T& y, test::random_values<T> const& v)
138 {
139 insert_or_assign_hint_invoker<T>()(y, v);
140 }
141
142 template <class T> struct try_emplace_invoker
143 {
144 void operator()(T&, test::random_values<T> const&) {}
145 };
146
147 template <class Key, class T, class Hash, class KeyEqual, class Allocator>
148 struct try_emplace_invoker<
149 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
150 {
151 void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
152 test::random_values<
153 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
154 {
155 typedef typename boost::unordered_map<Key, T, Hash, KeyEqual,
156 Allocator>::size_type size_type;
157 y.try_emplace(get_key(*v.begin()), get_value(*v.begin()));
158 BOOST_TEST_EQ(
159 y.size(), static_cast<size_type>(std::distance(y.begin(), y.end())));
160 }
161 };
162
163 template <class T>
164 static void try_emplace(T& y, test::random_values<T> const& v)
165 {
166 try_emplace_invoker<T>()(y, v);
167 }
168
169 template <class T> struct try_emplace_hint_invoker
170 {
171 void operator()(T&, test::random_values<T> const&) {}
172 };
173
174 template <class Key, class T, class Hash, class KeyEqual, class Allocator>
175 struct try_emplace_hint_invoker<
176 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
177 {
178 void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
179 test::random_values<
180 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
181 {
182 typedef typename boost::unordered_map<Key, T, Hash, KeyEqual,
183 Allocator>::size_type size_type;
184 y.try_emplace(y.end(), get_key(*v.begin()), get_value(*v.begin()));
185 BOOST_TEST_EQ(
186 y.size(), static_cast<size_type>(std::distance(y.begin(), y.end())));
187 }
188 };
189
190 template <class T>
191 static void try_emplace_hint(T& y, test::random_values<T> const& v)
192 {
193 try_emplace_hint_invoker<T>()(y, v);
194 }
195
196 template <class T> struct at_invoker
197 {
198 void operator()(T&, test::random_values<T> const&) {}
199 };
200
201 template <class Key, class T, class Hash, class KeyEqual, class Allocator>
202 struct at_invoker<boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
203 {
204 void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
205 test::random_values<
206 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
207 {
208 BOOST_TRY { y.at(get_key(*v.begin())); }
209 BOOST_CATCH(...) {}
210 BOOST_CATCH_END
211 }
212 };
213
214 template <class T> static void at(T& y, test::random_values<T> const& v)
215 {
216 at_invoker<T>()(y, v);
217 }
218
219 template <class T> struct index_operator_invoker
220 {
221 void operator()(T&, test::random_values<T> const&) {}
222 };
223
224 template <class Key, class T, class Hash, class KeyEqual, class Allocator>
225 struct index_operator_invoker<
226 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> >
227 {
228 void operator()(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& y,
229 test::random_values<
230 boost::unordered_map<Key, T, Hash, KeyEqual, Allocator> > const& v)
231 {
232 typedef typename boost::unordered_map<Key, T, Hash, KeyEqual,
233 Allocator>::size_type size_type;
234 y[get_key(*v.begin())] = get_value(*v.begin());
235 BOOST_TEST_EQ(
236 y.size(), static_cast<size_type>(std::distance(y.begin(), y.end())));
237 }
238 };
239
240 template <class T>
241 static void index_operator(T& y, test::random_values<T> const& v)
242 {
243 index_operator_invoker<T>()(y, v);
244 }
245
246 template <class T> static void clear(T& y, test::random_values<T> const&)
247 {
248 y.clear();
249 BOOST_TEST(y.empty());
250 BOOST_TEST_EQ(y.size(),
251 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
252 }
253
254 template <class T> static void capacity(T& y, test::random_values<T> const&)
255 {
256 (void)y.empty();
257 (void)y.size();
258 (void)y.max_size();
259 (void)y.load_factor();
260 (void)y.max_load_factor();
261 (void)y.hash_function();
262 (void)y.key_eq();
263 (void)y.get_allocator();
264 }
265
266 template <class T> static void iterators(T& y, test::random_values<T> const&)
267 {
268 BOOST_TEST_EQ(y.size(),
269 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
270 }
271
272 template <class T>
273 static void erase_range(T& y, test::random_values<T> const&)
274 {
275 y.erase(y.begin(), y.end());
276 BOOST_TEST(y.empty());
277 BOOST_TEST_EQ(y.size(),
278 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
279 }
280
281 template <class T>
282 static void erase_key(T& y, test::random_values<T> const& v)
283 {
284 y.erase(get_key(*v.begin()));
285 BOOST_TEST_EQ(y.size(),
286 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
287 }
288
289 template <class T> static void lookup(T& y, test::random_values<T> const& v)
290 {
291 (void)y.count(get_key(*v.begin()));
292 (void)y.find(get_key(*v.begin()));
293 (void)y.contains(get_key(*v.begin()));
294 (void)y.equal_range(get_key(*v.begin()));
295 }
296
297 template <class T> static void reserve(T& y, test::random_values<T> const&)
298 {
299 y.reserve(1337);
300 BOOST_TEST_GT(y.bucket_count(), 1337u);
301 BOOST_TEST_EQ(y.size(),
302 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
303 }
304
305 template <class T>
306 static void copy_assignment(T& y, test::random_values<T> const& v)
307 {
308 T x(v.begin(), v.end());
309 y = x;
310 BOOST_TEST_EQ(y.size(), x.size());
311 BOOST_TEST_EQ(y.size(),
312 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
313 }
314
315 template <class T>
316 static void move_assignment(T& y, test::random_values<T> const& v)
317 {
318 T x(v.begin(), v.end());
319 std::size_t const size = x.size();
320 y = std::move(x);
321 BOOST_TEST_GE(y.size(), size);
322 BOOST_TEST_EQ(y.size(),
323 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
324 }
325
326 template <class T> static void equal(T& y, test::random_values<T> const& v)
327 {
328 T x(v.begin(), v.end());
329 (void)(y == x);
330 BOOST_TEST_EQ(y.size(),
331 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
332 }
333
334#ifndef BOOST_UNORDERED_FOA_TESTS
335 template <class T> static void extract(T& y, test::random_values<T> const& v)
336 {
337 (void)y.extract(get_key(*v.begin()));
338 BOOST_TEST_EQ(y.size(),
339 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
340 }
341#endif
342
343 template <class T> static void merge(T& y, test::random_values<T> const& v)
344 {
345 T x(v.begin(), v.end());
346 if (y.get_allocator() == x.get_allocator()) {
347 y.merge(x);
348 }
349 BOOST_TEST_EQ(y.size(),
350 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
351 }
352
353 template <class X> bool pred(X const&) { return true; }
354
355 template <class T>
356 static void erase_with_pred(T& y, test::random_values<T> const&)
357 {
358 erase_if(y, pred<typename T::value_type>);
359 BOOST_TEST_EQ(y.size(),
360 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
361 }
362
363 template <class T>
364 static void container_swap(T& y, test::random_values<T> const& v)
365 {
366 T x(v.begin(), v.end());
367 if (boost::allocator_propagate_on_container_swap<
368 typename T::allocator_type>::type::value ||
369 x.get_allocator() == y.get_allocator()) {
370 y.swap(x);
371 }
372 BOOST_TEST_EQ(y.size(),
373 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
374 }
375
376#ifndef BOOST_UNORDERED_FOA_TESTS
377 template <class T> static void buckets(T& y, test::random_values<T> const& v)
378 {
379 (void)y.begin(0);
380 (void)y.end(0);
381 (void)y.bucket_count();
382 (void)y.max_bucket_count();
383 (void)y.bucket_size(0);
384 (void)y.bucket(get_key(*v.begin()));
385 }
386#endif
387
388 template <class T>
389 static void double_move_construct(T& y, test::random_values<T> const&)
390 {
391 T x = std::move(y);
392 x.clear();
393 BOOST_TEST_EQ(y.size(),
394 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
395 BOOST_TEST_EQ(x.size(),
396 static_cast<typename T::size_type>(std::distance(x.begin(), x.end())));
397 }
398
399 template <class T>
400 static void double_move_assign(T& y, test::random_values<T> const&)
401 {
402 T x;
403 x = std::move(y);
404 x.clear();
405 BOOST_TEST_EQ(y.size(),
406 static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
407 BOOST_TEST_EQ(x.size(),
408 static_cast<typename T::size_type>(std::distance(x.begin(), x.end())));
409 }
410
411 template <class T>
412 static void post_move_tests(T* ptr, test::random_generator const& generator)
413 {
414 // clang-format off
415 void (*fps[])(T&, test::random_values<T> const&) = {
416 insert_range<T>,
417 insert_single<T>,
418 insert_single_hint<T>,
419 insert_or_assign<T>,
420 insert_or_assign_hint<T>,
421 try_emplace<T>,
422 try_emplace_hint<T>,
423 at<T>,
424 index_operator<T>,
425 clear<T>,
426 capacity<T>,
427 iterators<T>,
428 erase_range<T>,
429 erase_key<T>,
430 lookup<T>,
431 reserve<T>,
432 copy_assignment<T>,
433 move_assignment<T>,
434 equal<T>,
435 #ifndef BOOST_UNORDERED_FOA_TESTS
436 extract<T>,
437 buckets<T>,
438 #endif
439 merge<T>,
440 erase_with_pred<T>,
441 container_swap<T>,
442 double_move_construct<T>,
443 double_move_assign<T>
444 };
445 // clang-format on
446
447 std::size_t const len = (sizeof(fps) / sizeof(*(fps)));
448
449 for (std::size_t i = 0; i < len; ++i) {
450 test::check_instances check_;
451
452 test::random_values<T> const v(1000, generator);
453 test::object_count count;
454 T y(create(v, count));
455
456 unsigned num_allocs = test::detail::tracker.count_allocations;
457 (void)num_allocs;
458
459 T x(std::move(y));
460
461 BOOST_TEST(y.empty());
462 BOOST_TEST(y.begin() == y.end());
463
464#ifdef BOOST_UNORDERED_FOA_TESTS
465 {
466 using allocator_type = typename T::allocator_type;
467 using value_type =
468 typename boost::allocator_value_type<allocator_type>::type;
469 using pointer = typename boost::allocator_pointer<allocator_type>::type;
470 if (std::is_same<pointer, value_type*>::value) {
471 BOOST_TEST_EQ(y.bucket_count(), 0u);
472 BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs);
473 }
474 }
475#else
476 BOOST_TEST_EQ(y.bucket_count(), 0u);
477 BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs);
478#endif
479
480 fps[i](y, v);
481
482 test::check_container(x, v);
483 test::check_equivalent_keys(x);
484 }
485
486 for (std::size_t i = 0; i < len; ++i) {
487 typename T::hasher hf(1);
488 typename T::key_equal eq(1);
489 typename T::allocator_type al1(1);
490 typename T::allocator_type al2(2);
491
492 test::check_instances check_;
493
494 test::random_values<T> v(1000, generator);
495 test::object_count count;
496 T y(v.begin(), v.end(), 0, hf, eq, al1);
497 T x(std::move(y), al2);
498
499#ifdef BOOST_UNORDERED_FOA_TESTS
500 BOOST_TEST(y.empty());
501 BOOST_TEST(y.begin() == y.end());
502#else
503 BOOST_TEST_NOT(y.empty());
504 BOOST_TEST(y.begin() != y.end());
505#endif
506
507 fps[i](y, v);
508
509 test::check_container(x, v);
510 test::check_equivalent_keys(x);
511 }
512
513 for (std::size_t i = 0; i < len; ++i) {
514 test::check_instances check_;
515
516 test::random_values<T> v(1000, generator);
517 test::object_count count;
518 T y(create(v, count));
519
520 unsigned num_allocs = test::detail::tracker.count_allocations;
521 (void)num_allocs;
522
523 T x(empty(ptr));
524 x = std::move(y);
525
526 BOOST_TEST(y.empty());
527 BOOST_TEST(y.begin() == y.end());
528
529#ifdef BOOST_UNORDERED_FOA_TESTS
530 {
531 using allocator_type = typename T::allocator_type;
532 using value_type =
533 typename boost::allocator_value_type<allocator_type>::type;
534 using pointer = typename boost::allocator_pointer<allocator_type>::type;
535 if (std::is_same<pointer, value_type*>::value) {
536 BOOST_TEST_EQ(y.bucket_count(), 0u);
537 BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs);
538 }
539 }
540#else
541 BOOST_TEST_EQ(y.bucket_count(), 0u);
542 BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs);
543#endif
544
545 fps[i](y, v);
546
547 test::check_container(x, v);
548 test::check_equivalent_keys(x);
549 }
550
551 for (std::size_t i = 0; i < len; ++i) {
552 typename T::hasher hf(1);
553 typename T::key_equal eq(1);
554 typename T::allocator_type al1(1);
555 typename T::allocator_type al2(2);
556
557 test::check_instances check_;
558
559 test::random_values<T> v(1000, generator);
560 test::object_count count;
561 T y(v.begin(), v.end(), 0, hf, eq, al1);
562
563 unsigned num_allocs = test::detail::tracker.count_allocations;
564 (void)num_allocs;
565
566 T x(al2);
567 x = std::move(y);
568
569 bool b = boost::allocator_propagate_on_container_move_assignment<
570 typename T::allocator_type>::type::value;
571 if (b) {
572 BOOST_TEST(y.empty());
573 BOOST_TEST(y.begin() == y.end());
574 BOOST_TEST_EQ(y.bucket_count(), 0u);
575 BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs);
576 } else {
577#ifdef BOOST_UNORDERED_FOA_TESTS
578 BOOST_TEST(y.empty());
579 BOOST_TEST(y.begin() == y.end());
580#else
581 BOOST_TEST_NOT(y.empty());
582 BOOST_TEST(y.begin() != y.end());
583#endif
584 }
585
586 fps[i](y, v);
587
588 test::check_container(x, v);
589 test::check_equivalent_keys(x);
590 }
591 }
592
593 using test::default_generator;
594 using test::generate_collisions;
595 using test::limited_range;
596
597#ifdef BOOST_UNORDERED_FOA_TESTS
598 boost::unordered_flat_map<test::object, test::object, test::hash,
599 test::equal_to,
600 std::allocator<std::pair<test::object const, test::object> > >*
601 test_map_std_alloc;
602
603 boost::unordered_flat_set<test::object, test::hash, test::equal_to,
604 test::allocator2<test::object> >* test_set;
605 boost::unordered_flat_map<test::object, test::object, test::hash,
606 test::equal_to,
607 test::allocator1<std::pair<test::object const, test::object> > >* test_map;
608
609 boost::unordered_flat_set<test::object, test::hash, test::equal_to,
610 test::cxx11_allocator<test::object, test::propagate_move> >*
611 test_set_prop_move;
612 boost::unordered_flat_map<test::object, test::object, test::hash,
613 test::equal_to,
614 test::cxx11_allocator<std::pair<test::object const, test::object>,
615 test::propagate_move> >* test_map_prop_move;
616
617 boost::unordered_flat_set<test::object, test::hash, test::equal_to,
618 test::cxx11_allocator<test::object, test::no_propagate_move> >*
619 test_set_no_prop_move;
620 boost::unordered_flat_map<test::object, test::object, test::hash,
621 test::equal_to,
622 test::cxx11_allocator<std::pair<test::object const, test::object>,
623 test::no_propagate_move> >* test_map_no_prop_move;
624
625 boost::unordered_node_set<test::object, test::hash, test::equal_to,
626 test::allocator2<test::object> >* test_node_set;
627 boost::unordered_node_map<test::object, test::object, test::hash,
628 test::equal_to,
629 test::allocator1<std::pair<test::object const, test::object> > >*
630 test_node_map;
631
632 boost::unordered_node_set<test::object, test::hash, test::equal_to,
633 test::cxx11_allocator<test::object, test::propagate_move> >*
634 test_node_set_prop_move;
635 boost::unordered_node_map<test::object, test::object, test::hash,
636 test::equal_to,
637 test::cxx11_allocator<std::pair<test::object const, test::object>,
638 test::propagate_move> >* test_node_map_prop_move;
639
640 boost::unordered_node_set<test::object, test::hash, test::equal_to,
641 test::cxx11_allocator<test::object, test::no_propagate_move> >*
642 test_node_set_no_prop_move;
643 boost::unordered_node_map<test::object, test::object, test::hash,
644 test::equal_to,
645 test::cxx11_allocator<std::pair<test::object const, test::object>,
646 test::no_propagate_move> >* test_node_map_no_prop_move;
647
648 // clang-format off
649 UNORDERED_TEST(post_move_tests,
650 ((test_set)(test_map)(test_set_prop_move)(test_map_prop_move)
651 (test_set_no_prop_move)(test_map_no_prop_move)
652 (test_node_set)(test_node_map)
653 (test_node_set_prop_move)(test_node_map_prop_move)
654 (test_node_set_no_prop_move)(test_node_map_no_prop_move))(
655 (default_generator)(generate_collisions)(limited_range)))
656// clang-format on
657#else
658 boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
659 std::allocator<std::pair<test::object const, test::object> > >*
660 test_map_std_alloc;
661
662 boost::unordered_set<test::object, test::hash, test::equal_to,
663 test::allocator2<test::object> >* test_set;
664 boost::unordered_multiset<test::object, test::hash, test::equal_to,
665 test::allocator1<test::object> >* test_multiset;
666 boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
667 test::allocator1<std::pair<test::object const, test::object> > >* test_map;
668 boost::unordered_multimap<test::object, test::object, test::hash,
669 test::equal_to,
670 test::allocator2<std::pair<test::object const, test::object> > >*
671 test_multimap;
672
673 boost::unordered_set<test::object, test::hash, test::equal_to,
674 test::cxx11_allocator<test::object, test::propagate_move> >*
675 test_set_prop_move;
676 boost::unordered_multiset<test::object, test::hash, test::equal_to,
677 test::cxx11_allocator<test::object, test::propagate_move> >*
678 test_multiset_prop_move;
679 boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
680 test::cxx11_allocator<std::pair<test::object const, test::object>,
681 test::propagate_move> >* test_map_prop_move;
682 boost::unordered_multimap<test::object, test::object, test::hash,
683 test::equal_to,
684 test::cxx11_allocator<std::pair<test::object const, test::object>,
685 test::propagate_move> >* test_multimap_prop_move;
686
687 boost::unordered_set<test::object, test::hash, test::equal_to,
688 test::cxx11_allocator<test::object, test::no_propagate_move> >*
689 test_set_no_prop_move;
690 boost::unordered_multiset<test::object, test::hash, test::equal_to,
691 test::cxx11_allocator<test::object, test::no_propagate_move> >*
692 test_multiset_no_prop_move;
693 boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
694 test::cxx11_allocator<std::pair<test::object const, test::object>,
695 test::no_propagate_move> >* test_map_no_prop_move;
696 boost::unordered_multimap<test::object, test::object, test::hash,
697 test::equal_to,
698 test::cxx11_allocator<std::pair<test::object const, test::object>,
699 test::no_propagate_move> >* test_multimap_no_prop_move;
700
701 // clang-format off
702 UNORDERED_TEST(post_move_tests,
703 ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_move)(
704 test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)(
705 test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(
706 test_multimap_no_prop_move))(
707 (default_generator)(generate_collisions)(limited_range)))
708// clang-format on
709#endif
710} // namespace move_tests
711
712RUN_TESTS()
713

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