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