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 // test_memory_resource requires RTTI for dynamic_cast
12 // UNSUPPORTED: no-rtti
13
14 // Aligned allocation is required by std::experimental::pmr, but it was not provided
15 // before macosx10.13 and as a result we get linker errors when deploying to older than
16 // macosx10.13.
17 // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}}
18
19 // <experimental/memory_resource>
20
21 // template <class T> class polymorphic_allocator
22
23 // template <class U, class ...Args>
24 // void polymorphic_allocator<T>::construct(U *, Args &&...)
25
26 #include <experimental/memory_resource>
27 #include <type_traits>
28 #include <cassert>
29 #include <cstdlib>
30
31 #include "test_macros.h"
32 #include "test_memory_resource.h"
33 #include "uses_alloc_types.h"
34 #include "controlled_allocators.h"
35 #include "test_allocator.h"
36
37 namespace ex = std::experimental::pmr;
38
39 template <class T>
40 struct PMATest {
41 TestResource R;
42 ex::polymorphic_allocator<T> A;
43 T* ptr;
44 bool constructed;
45
PMATestPMATest46 PMATest() : A(&R), ptr(A.allocate(1)), constructed(false) {}
47
48 template <class ...Args>
constructPMATest49 void construct(Args&&... args) {
50 A.construct(ptr, std::forward<Args>(args)...);
51 constructed = true;
52 }
53
~PMATestPMATest54 ~PMATest() {
55 if (constructed) A.destroy(ptr);
56 A.deallocate(ptr, 1);
57 }
58 };
59
60 template <class T, class ...Args>
doTest(UsesAllocatorType UAExpect,Args &&...args)61 bool doTest(UsesAllocatorType UAExpect, Args&&... args)
62 {
63 PMATest<T> TH;
64 // UNDER TEST //
65 TH.construct(std::forward<Args>(args)...);
66 return checkConstruct<Args&&...>(*TH.ptr, UAExpect, &TH.R);
67 // ------- //
68 }
69
70
71 template <class T, class ...Args>
doTestUsesAllocV0(Args &&...args)72 bool doTestUsesAllocV0(Args&&... args)
73 {
74 PMATest<T> TH;
75 // UNDER TEST //
76 TH.construct(std::forward<Args>(args)...);
77 return checkConstruct<Args&&...>(*TH.ptr, UA_None);
78 // -------- //
79 }
80
81
82 template <class T, class EAlloc, class ...Args>
doTestUsesAllocV1(EAlloc const & ealloc,Args &&...args)83 bool doTestUsesAllocV1(EAlloc const& ealloc, Args&&... args)
84 {
85 PMATest<T> TH;
86 // UNDER TEST //
87 TH.construct(std::allocator_arg, ealloc, std::forward<Args>(args)...);
88 return checkConstruct<Args&&...>(*TH.ptr, UA_AllocArg, ealloc);
89 // -------- //
90 }
91
92 template <class T, class EAlloc, class ...Args>
doTestUsesAllocV2(EAlloc const & ealloc,Args &&...args)93 bool doTestUsesAllocV2(EAlloc const& ealloc, Args&&... args)
94 {
95 PMATest<T> TH;
96 // UNDER TEST //
97 TH.construct(std::forward<Args>(args)..., ealloc);
98 return checkConstruct<Args&&...>(*TH.ptr, UA_AllocLast, ealloc);
99 // -------- //
100 }
101
102 template <class Alloc, class ...Args>
test_pmr_uses_alloc(Args &&...args)103 void test_pmr_uses_alloc(Args&&... args)
104 {
105 TestResource R(12435);
106 ex::memory_resource* M = &R;
107 {
108 // NotUsesAllocator provides valid signatures for each uses-allocator
109 // construction but does not supply the required allocator_type typedef.
110 // Test that we can call these constructors manually without
111 // polymorphic_allocator interfering.
112 using T = NotUsesAllocator<Alloc, sizeof...(Args)>;
113 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
114 assert((doTestUsesAllocV1<T>(M, std::forward<Args>(args)...)));
115 assert((doTestUsesAllocV2<T>(M, std::forward<Args>(args)...)));
116 }
117 {
118 // Test T(std::allocator_arg_t, Alloc const&, Args...) construction
119 using T = UsesAllocatorV1<Alloc, sizeof...(Args)>;
120 assert((doTest<T>(UA_AllocArg, std::forward<Args>(args)...)));
121 }
122 {
123 // Test T(Args..., Alloc const&) construction
124 using T = UsesAllocatorV2<Alloc, sizeof...(Args)>;
125 assert((doTest<T>(UA_AllocLast, std::forward<Args>(args)...)));
126 }
127 {
128 // Test that T(std::allocator_arg_t, Alloc const&, Args...) construction
129 // is preferred when T(Args..., Alloc const&) is also available.
130 using T = UsesAllocatorV3<Alloc, sizeof...(Args)>;
131 assert((doTest<T>(UA_AllocArg, std::forward<Args>(args)...)));
132 }
133 }
134
135 template <class Alloc, class ...Args>
test_pmr_not_uses_alloc(Args &&...args)136 void test_pmr_not_uses_alloc(Args&&... args)
137 {
138 TestResource R(12435);
139 ex::memory_resource* M = &R;
140 {
141 // NotUsesAllocator provides valid signatures for each uses-allocator
142 // construction but does not supply the required allocator_type typedef.
143 // Test that we can call these constructors manually without
144 // polymorphic_allocator interfering.
145 using T = NotUsesAllocator<Alloc, sizeof...(Args)>;
146 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
147 assert((doTestUsesAllocV1<T>(M, std::forward<Args>(args)...)));
148 assert((doTestUsesAllocV2<T>(M, std::forward<Args>(args)...)));
149 }
150 {
151 // Test T(std::allocator_arg_t, Alloc const&, Args...) construction
152 using T = UsesAllocatorV1<Alloc, sizeof...(Args)>;
153 assert((doTest<T>(UA_None, std::forward<Args>(args)...)));
154 }
155 {
156 // Test T(Args..., Alloc const&) construction
157 using T = UsesAllocatorV2<Alloc, sizeof...(Args)>;
158 assert((doTest<T>(UA_None, std::forward<Args>(args)...)));
159 }
160 {
161 // Test that T(std::allocator_arg_t, Alloc const&, Args...) construction
162 // is preferred when T(Args..., Alloc const&) is also available.
163 using T = UsesAllocatorV3<Alloc, sizeof...(Args)>;
164 assert((doTest<T>(UA_None, std::forward<Args>(args)...)));
165 }
166 }
167
168 // Test that polymorphic_allocator does not prevent us from manually
169 // doing non-pmr uses-allocator construction.
170 template <class Alloc, class AllocObj, class ...Args>
test_non_pmr_uses_alloc(AllocObj const & A,Args &&...args)171 void test_non_pmr_uses_alloc(AllocObj const& A, Args&&... args)
172 {
173 {
174 using T = NotUsesAllocator<Alloc, sizeof...(Args)>;
175 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
176 assert((doTestUsesAllocV1<T>(A, std::forward<Args>(args)...)));
177 assert((doTestUsesAllocV2<T>(A, std::forward<Args>(args)...)));
178 }
179 {
180 using T = UsesAllocatorV1<Alloc, sizeof...(Args)>;
181 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
182 assert((doTestUsesAllocV1<T>(A, std::forward<Args>(args)...)));
183 }
184 {
185 using T = UsesAllocatorV2<Alloc, sizeof...(Args)>;
186 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
187 assert((doTestUsesAllocV2<T>(A, std::forward<Args>(args)...)));
188 }
189 {
190 using T = UsesAllocatorV3<Alloc, sizeof...(Args)>;
191 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
192 assert((doTestUsesAllocV1<T>(A, std::forward<Args>(args)...)));
193 assert((doTestUsesAllocV2<T>(A, std::forward<Args>(args)...)));
194 }
195 }
196
main(int,char **)197 int main(int, char**)
198 {
199 using ET = std::experimental::erased_type;
200 using PMR = ex::memory_resource*;
201 using PMA = ex::polymorphic_allocator<void>;
202 using STDA = std::allocator<char>;
203 using TESTA = test_allocator<char>;
204
205 int value = 42;
206 const int cvalue = 43;
207 {
208 test_pmr_uses_alloc<ET>();
209 test_pmr_not_uses_alloc<PMR>();
210 test_pmr_uses_alloc<PMA>();
211 test_pmr_uses_alloc<ET>(value);
212 test_pmr_not_uses_alloc<PMR>(value);
213 test_pmr_uses_alloc<PMA>(value);
214 test_pmr_uses_alloc<ET>(cvalue);
215 test_pmr_not_uses_alloc<PMR>(cvalue);
216 test_pmr_uses_alloc<PMA>(cvalue);
217 test_pmr_uses_alloc<ET>(cvalue, std::move(value));
218 test_pmr_not_uses_alloc<PMR>(cvalue, std::move(value));
219 test_pmr_uses_alloc<PMA>(cvalue, std::move(value));
220 }
221 {
222 STDA std_alloc;
223 TESTA test_alloc(42);
224 test_non_pmr_uses_alloc<STDA>(std_alloc);
225 test_non_pmr_uses_alloc<TESTA>(test_alloc);
226 test_non_pmr_uses_alloc<STDA>(std_alloc, value);
227 test_non_pmr_uses_alloc<TESTA>(test_alloc, value);
228 test_non_pmr_uses_alloc<STDA>(std_alloc, cvalue);
229 test_non_pmr_uses_alloc<TESTA>(test_alloc, cvalue);
230 test_non_pmr_uses_alloc<STDA>(std_alloc, cvalue, std::move(value));
231 test_non_pmr_uses_alloc<TESTA>(test_alloc, cvalue, std::move(value));
232 }
233
234 return 0;
235 }
236