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
10 
11 // C++2a[container.requirements.general]p8
12 //   Move constructors obtain an allocator by move construction from the allocator
13 //   belonging to the container being moved. Such move construction of the
14 //   allocator shall not exit via an exception.
15 
16 #include <vector>
17 #include <deque>
18 #include <list>
19 #include <forward_list>
20 #include <set>
21 #include <map>
22 #include <unordered_map>
23 #include <unordered_set>
24 
25 #include "test_macros.h"
26 #include "test_allocator.h"
27 
28 template <class C>
29 void test(int expected_num_allocs = 1) {
30   test_allocator_statistics alloc_stats;
31   {
32     alloc_stats.clear();
33     using AllocT = typename C::allocator_type;
34     C v(AllocT(42, 101, &alloc_stats));
35 
36     assert(alloc_stats.count == expected_num_allocs);
37 
38     const int num_stored_allocs = alloc_stats.count;
39     {
40       const AllocT& a = v.get_allocator();
41       assert(alloc_stats.count == 1 + num_stored_allocs);
42       assert(a.get_data() == 42);
43       assert(a.get_id() == 101);
44     }
45     assert(alloc_stats.count == num_stored_allocs);
46     alloc_stats.clear_ctor_counters();
47 
48     C v2 = std::move(v);
49     assert(alloc_stats.count == num_stored_allocs * 2);
50     assert(alloc_stats.copied == 0);
51     assert(alloc_stats.moved == num_stored_allocs);
52     {
53       const AllocT& a1 = v.get_allocator();
54       assert(a1.get_id() == test_alloc_base::moved_value);
55       assert(a1.get_data() == 42);
56 
57       const AllocT& a2 = v2.get_allocator();
58       assert(a2.get_id() == 101);
59       assert(a2.get_data() == 42);
60 
61       assert(a1 == a2);
62     }
63   }
64 }
65 
66 int main(int, char**) {
67   { // test sequence containers
68     test<std::vector<int, test_allocator<int> > >();
69     test<std::vector<bool, test_allocator<bool> > >();
70     test<std::list<int, test_allocator<int> > >();
71     test<std::forward_list<int, test_allocator<int> > >();
72 
73     // libc++ stores two allocators in deque
74 #ifdef _LIBCPP_VERSION
75     int stored_allocators = 2;
76 #else
77     int stored_allocators = 1;
78 #endif
79     test<std::deque<int, test_allocator<int> > >(stored_allocators);
80   }
81   { // test associative containers
82     test<std::set<int, std::less<int>, test_allocator<int> > >();
83     test<std::multiset<int, std::less<int>, test_allocator<int> > >();
84 
85     using KV = std::pair<const int, int>;
86     test<std::map<int, int, std::less<int>, test_allocator<KV> > >();
87     test<std::multimap<int, int, std::less<int>, test_allocator<KV> > >();
88   }
89   { // test unordered containers
90     // libc++ stores two allocators in the unordered containers.
91 #ifdef _LIBCPP_VERSION
92     int stored_allocators = 2;
93 #else
94     int stored_allocators = 1;
95 #endif
96     test<std::unordered_set<int, std::hash<int>, std::equal_to<int>,
97                             test_allocator<int> > >(stored_allocators);
98     test<std::unordered_multiset<int, std::hash<int>, std::equal_to<int>,
99                                  test_allocator<int> > >(stored_allocators);
100 
101     using KV = std::pair<const int, int>;
102     test<std::unordered_map<int, int, std::hash<int>, std::equal_to<int>,
103                             test_allocator<KV> > >(stored_allocators);
104     test<std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>,
105                                  test_allocator<KV> > >(stored_allocators);
106   }
107 
108   return 0;
109 }
110