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