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.get_soccc()) {}
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() const40 constexpr auto get_soccc() const { return soccc_count; }
get_self_soccc() const41 constexpr auto get_self_soccc() const { 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 template <class U>
operator ==(const soccc_allocator<U> & that) const48 constexpr bool operator==(const soccc_allocator<U>& that) const {
49 return soccc_count == that.get_soccc();
50 }
51 };
52
53 template <class CharT>
test()54 TEST_CONSTEXPR_CXX20 bool test() {
55 using S = std::basic_string<CharT, std::char_traits<CharT>, soccc_allocator<CharT>>;
56 {
57 int soccc_lhs = 0;
58 int soccc_rhs = 0;
59 S lhs(soccc_allocator<CharT>{&soccc_lhs});
60 S rhs(soccc_allocator<CharT>{&soccc_rhs});
61 auto r = lhs + rhs;
62 assert(r.get_allocator().get_soccc() == &soccc_lhs);
63 assert(r.get_allocator().get_self_soccc() == 1);
64 assert(soccc_lhs == 1);
65 assert(soccc_rhs == 0);
66 }
67 {
68 int soccc_lhs = 0;
69 int soccc_rhs = 0;
70 S lhs(soccc_allocator<CharT>{&soccc_lhs});
71 S rhs(soccc_allocator<CharT>{&soccc_rhs});
72 auto r = lhs + std::move(rhs);
73 assert(r.get_allocator().get_soccc() == &soccc_rhs);
74 assert(r.get_allocator().get_self_soccc() == 0);
75 assert(soccc_lhs == 0);
76 assert(soccc_rhs == 0);
77 }
78 {
79 int soccc_lhs = 0;
80 int soccc_rhs = 0;
81 S lhs(soccc_allocator<CharT>{&soccc_lhs});
82 S rhs(soccc_allocator<CharT>{&soccc_rhs});
83 auto r = std::move(lhs) + rhs;
84 assert(r.get_allocator().get_soccc() == &soccc_lhs);
85 assert(r.get_allocator().get_self_soccc() == 0);
86 assert(soccc_lhs == 0);
87 assert(soccc_rhs == 0);
88 }
89 {
90 int soccc_lhs = 0;
91 int soccc_rhs = 0;
92 S lhs(soccc_allocator<CharT>{&soccc_lhs});
93 S rhs(soccc_allocator<CharT>{&soccc_rhs});
94 auto r = std::move(lhs) + std::move(rhs);
95 assert(r.get_allocator().get_soccc() == &soccc_lhs);
96 assert(r.get_allocator().get_self_soccc() == 0);
97 assert(soccc_lhs == 0);
98 assert(soccc_rhs == 0);
99 }
100 {
101 int soccc_lhs = 0;
102 int soccc_rhs = 0;
103 S lhs(soccc_allocator<CharT>{&soccc_lhs});
104 S rhs(soccc_allocator<CharT>{&soccc_rhs});
105 auto r = lhs + rhs.data();
106 assert(r.get_allocator().get_soccc() == &soccc_lhs);
107 assert(r.get_allocator().get_self_soccc() == 1);
108 assert(soccc_lhs == 1);
109 assert(soccc_rhs == 0);
110 }
111 {
112 int soccc_lhs = 0;
113 int soccc_rhs = 0;
114 S lhs(soccc_allocator<CharT>{&soccc_lhs});
115 S rhs(soccc_allocator<CharT>{&soccc_rhs});
116 auto r = lhs + rhs[0];
117 assert(r.get_allocator().get_soccc() == &soccc_lhs);
118 assert(r.get_allocator().get_self_soccc() == 1);
119 assert(soccc_lhs == 1);
120 assert(soccc_rhs == 0);
121 }
122 {
123 int soccc_lhs = 0;
124 int soccc_rhs = 0;
125 S lhs(soccc_allocator<CharT>{&soccc_lhs});
126 S rhs(soccc_allocator<CharT>{&soccc_rhs});
127 auto r = std::move(lhs) + rhs.data();
128 assert(r.get_allocator().get_soccc() == &soccc_lhs);
129 assert(r.get_allocator().get_self_soccc() == 0);
130 assert(soccc_lhs == 0);
131 assert(soccc_rhs == 0);
132 }
133 {
134 int soccc_lhs = 0;
135 int soccc_rhs = 0;
136 S lhs(soccc_allocator<CharT>{&soccc_lhs});
137 S rhs(soccc_allocator<CharT>{&soccc_rhs});
138 auto r = std::move(lhs) + rhs[0];
139 assert(r.get_allocator().get_soccc() == &soccc_lhs);
140 assert(r.get_allocator().get_self_soccc() == 0);
141 assert(soccc_lhs == 0);
142 assert(soccc_rhs == 0);
143 }
144 {
145 int soccc_lhs = 0;
146 int soccc_rhs = 0;
147 S lhs(soccc_allocator<CharT>{&soccc_lhs});
148 S rhs(soccc_allocator<CharT>{&soccc_rhs});
149 auto r = lhs.data() + rhs;
150 assert(r.get_allocator().get_soccc() == &soccc_rhs);
151 assert(r.get_allocator().get_self_soccc() == 1);
152 assert(soccc_lhs == 0);
153 assert(soccc_rhs == 1);
154 }
155 {
156 int soccc_lhs = 0;
157 int soccc_rhs = 0;
158 S lhs(soccc_allocator<CharT>{&soccc_lhs});
159 S rhs(soccc_allocator<CharT>{&soccc_rhs});
160 auto r = lhs[0] + rhs;
161 assert(r.get_allocator().get_soccc() == &soccc_rhs);
162 assert(r.get_allocator().get_self_soccc() == 1);
163 assert(soccc_lhs == 0);
164 assert(soccc_rhs == 1);
165 }
166 {
167 int soccc_lhs = 0;
168 int soccc_rhs = 0;
169 S lhs(soccc_allocator<CharT>{&soccc_lhs});
170 S rhs(soccc_allocator<CharT>{&soccc_rhs});
171 auto r = lhs.data() + std::move(rhs);
172 assert(r.get_allocator().get_soccc() == &soccc_rhs);
173 assert(r.get_allocator().get_self_soccc() == 0);
174 assert(soccc_lhs == 0);
175 assert(soccc_rhs == 0);
176 }
177 {
178 int soccc_lhs = 0;
179 int soccc_rhs = 0;
180 S lhs(soccc_allocator<CharT>{&soccc_lhs});
181 S rhs(soccc_allocator<CharT>{&soccc_rhs});
182 auto r = lhs[0] + std::move(rhs);
183 assert(r.get_allocator().get_soccc() == &soccc_rhs);
184 assert(r.get_allocator().get_self_soccc() == 0);
185 assert(soccc_lhs == 0);
186 assert(soccc_rhs == 0);
187 }
188
189 return true;
190 }
191
main(int,char **)192 int main(int, char**) {
193 test<char>();
194 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
195 test<wchar_t>();
196 #endif
197 #if TEST_STD_VER > 17
198 static_assert(test<char>());
199 # ifndef TEST_HAS_NO_WIDE_CHARACTERS
200 static_assert(test<wchar_t>());
201 # endif
202 #endif
203
204 return 0;
205 }
206