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
10
11 // This test ensures that we properly propagate allocators, per https://wg21.link/p1165r1
12
13 #include <cassert>
14 #include <string>
15
16 #include "test_macros.h"
17
18 template <class T>
19 class soccc_allocator {
20 int* soccc_count;
21 int self_soccc_count;
22
23 public:
24 using value_type = T;
25
soccc_allocator(int * soccc_count_,int self_coccc_count_=0)26 constexpr explicit soccc_allocator(int* soccc_count_, int self_coccc_count_ = 0)
27 : soccc_count(soccc_count_), self_soccc_count(self_coccc_count_) {}
28
29 template <class U>
soccc_allocator(const soccc_allocator<U> & a)30 constexpr soccc_allocator(const soccc_allocator<U>& a) : soccc_count(a.soccc_count) {}
31
allocate(std::size_t n)32 constexpr T* allocate(std::size_t n) { return std::allocator<T>().allocate(n); }
deallocate(T * p,std::size_t s)33 constexpr void deallocate(T* p, std::size_t s) { std::allocator<T>().deallocate(p, s); }
34
select_on_container_copy_construction() const35 constexpr soccc_allocator select_on_container_copy_construction() const {
36 *soccc_count += 1;
37 return soccc_allocator(soccc_count, self_soccc_count + 1);
38 }
39
get_soccc()40 constexpr auto get_soccc() { return soccc_count; }
get_self_soccc()41 constexpr auto get_self_soccc() { return self_soccc_count; }
42
43 typedef std::true_type propagate_on_container_copy_assignment;
44 typedef std::true_type propagate_on_container_move_assignment;
45 typedef std::true_type propagate_on_container_swap;
46 };
47
48 template <class CharT>
test()49 TEST_CONSTEXPR_CXX20 bool test() {
50 using S = std::basic_string<CharT, std::char_traits<CharT>, soccc_allocator<CharT>>;
51 {
52 int soccc_lhs = 0;
53 int soccc_rhs = 0;
54 S lhs(soccc_allocator<CharT>{&soccc_lhs});
55 S rhs(soccc_allocator<CharT>{&soccc_rhs});
56 auto r = lhs + rhs;
57 assert(r.get_allocator().get_soccc() == &soccc_lhs);
58 assert(r.get_allocator().get_self_soccc() == 1);
59 assert(soccc_lhs == 1);
60 assert(soccc_rhs == 0);
61 }
62 {
63 int soccc_lhs = 0;
64 int soccc_rhs = 0;
65 S lhs(soccc_allocator<CharT>{&soccc_lhs});
66 S rhs(soccc_allocator<CharT>{&soccc_rhs});
67 auto r = lhs + std::move(rhs);
68 assert(r.get_allocator().get_soccc() == &soccc_rhs);
69 assert(r.get_allocator().get_self_soccc() == 0);
70 assert(soccc_lhs == 0);
71 assert(soccc_rhs == 0);
72 }
73 {
74 int soccc_lhs = 0;
75 int soccc_rhs = 0;
76 S lhs(soccc_allocator<CharT>{&soccc_lhs});
77 S rhs(soccc_allocator<CharT>{&soccc_rhs});
78 auto r = std::move(lhs) + rhs;
79 assert(r.get_allocator().get_soccc() == &soccc_lhs);
80 assert(r.get_allocator().get_self_soccc() == 0);
81 assert(soccc_lhs == 0);
82 assert(soccc_rhs == 0);
83 }
84 {
85 int soccc_lhs = 0;
86 int soccc_rhs = 0;
87 S lhs(soccc_allocator<CharT>{&soccc_lhs});
88 S rhs(soccc_allocator<CharT>{&soccc_rhs});
89 auto r = std::move(lhs) + std::move(rhs);
90 assert(r.get_allocator().get_soccc() == &soccc_lhs);
91 assert(r.get_allocator().get_self_soccc() == 0);
92 assert(soccc_lhs == 0);
93 assert(soccc_rhs == 0);
94 }
95 {
96 int soccc_lhs = 0;
97 int soccc_rhs = 0;
98 S lhs(soccc_allocator<CharT>{&soccc_lhs});
99 S rhs(soccc_allocator<CharT>{&soccc_rhs});
100 auto r = lhs + rhs.data();
101 assert(r.get_allocator().get_soccc() == &soccc_lhs);
102 assert(r.get_allocator().get_self_soccc() == 1);
103 assert(soccc_lhs == 1);
104 assert(soccc_rhs == 0);
105 }
106 {
107 int soccc_lhs = 0;
108 int soccc_rhs = 0;
109 S lhs(soccc_allocator<CharT>{&soccc_lhs});
110 S rhs(soccc_allocator<CharT>{&soccc_rhs});
111 auto r = lhs + rhs[0];
112 assert(r.get_allocator().get_soccc() == &soccc_lhs);
113 assert(r.get_allocator().get_self_soccc() == 1);
114 assert(soccc_lhs == 1);
115 assert(soccc_rhs == 0);
116 }
117 {
118 int soccc_lhs = 0;
119 int soccc_rhs = 0;
120 S lhs(soccc_allocator<CharT>{&soccc_lhs});
121 S rhs(soccc_allocator<CharT>{&soccc_rhs});
122 auto r = std::move(lhs) + rhs.data();
123 assert(r.get_allocator().get_soccc() == &soccc_lhs);
124 assert(r.get_allocator().get_self_soccc() == 0);
125 assert(soccc_lhs == 0);
126 assert(soccc_rhs == 0);
127 }
128 {
129 int soccc_lhs = 0;
130 int soccc_rhs = 0;
131 S lhs(soccc_allocator<CharT>{&soccc_lhs});
132 S rhs(soccc_allocator<CharT>{&soccc_rhs});
133 auto r = std::move(lhs) + rhs[0];
134 assert(r.get_allocator().get_soccc() == &soccc_lhs);
135 assert(r.get_allocator().get_self_soccc() == 0);
136 assert(soccc_lhs == 0);
137 assert(soccc_rhs == 0);
138 }
139 {
140 int soccc_lhs = 0;
141 int soccc_rhs = 0;
142 S lhs(soccc_allocator<CharT>{&soccc_lhs});
143 S rhs(soccc_allocator<CharT>{&soccc_rhs});
144 auto r = lhs.data() + rhs;
145 assert(r.get_allocator().get_soccc() == &soccc_rhs);
146 assert(r.get_allocator().get_self_soccc() == 1);
147 assert(soccc_lhs == 0);
148 assert(soccc_rhs == 1);
149 }
150 {
151 int soccc_lhs = 0;
152 int soccc_rhs = 0;
153 S lhs(soccc_allocator<CharT>{&soccc_lhs});
154 S rhs(soccc_allocator<CharT>{&soccc_rhs});
155 auto r = lhs[0] + rhs;
156 assert(r.get_allocator().get_soccc() == &soccc_rhs);
157 assert(r.get_allocator().get_self_soccc() == 1);
158 assert(soccc_lhs == 0);
159 assert(soccc_rhs == 1);
160 }
161 {
162 int soccc_lhs = 0;
163 int soccc_rhs = 0;
164 S lhs(soccc_allocator<CharT>{&soccc_lhs});
165 S rhs(soccc_allocator<CharT>{&soccc_rhs});
166 auto r = lhs.data() + std::move(rhs);
167 assert(r.get_allocator().get_soccc() == &soccc_rhs);
168 assert(r.get_allocator().get_self_soccc() == 0);
169 assert(soccc_lhs == 0);
170 assert(soccc_rhs == 0);
171 }
172 {
173 int soccc_lhs = 0;
174 int soccc_rhs = 0;
175 S lhs(soccc_allocator<CharT>{&soccc_lhs});
176 S rhs(soccc_allocator<CharT>{&soccc_rhs});
177 auto r = lhs[0] + std::move(rhs);
178 assert(r.get_allocator().get_soccc() == &soccc_rhs);
179 assert(r.get_allocator().get_self_soccc() == 0);
180 assert(soccc_lhs == 0);
181 assert(soccc_rhs == 0);
182 }
183
184 return true;
185 }
186
main(int,char **)187 int main(int, char**) {
188 test<char>();
189 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
190 test<wchar_t>();
191 #endif
192 #if TEST_STD_VER > 17
193 static_assert(test<char>());
194 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
195 static_assert(test<wchar_t>());
196 #endif
197 #endif
198
199 return 0;
200 }
201