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