1 //===----------------------------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // REQUIRES: c++experimental 11 // UNSUPPORTED: c++98, c++03 12 13 // <experimental/memory_resource> 14 15 // template <class T> class polymorphic_allocator 16 17 // template <class U, class ...Args> 18 // void polymorphic_allocator<T>::construct(U *, Args &&...) 19 20 #include <experimental/memory_resource> 21 #include <type_traits> 22 #include <cassert> 23 #include <cstdlib> 24 25 #include "test_macros.h" 26 #include "test_memory_resource.hpp" 27 #include "uses_alloc_types.hpp" 28 #include "controlled_allocators.hpp" 29 #include "test_allocator.h" 30 31 namespace ex = std::experimental::pmr; 32 33 template <class T> 34 struct PMATest { 35 TestResource R; 36 ex::polymorphic_allocator<T> A; 37 T* ptr; 38 bool constructed; 39 40 PMATest() : A(&R), ptr(A.allocate(1)), constructed(false) {} 41 42 template <class ...Args> 43 void construct(Args&&... args) { 44 A.construct(ptr, std::forward<Args>(args)...); 45 constructed = true; 46 } 47 48 ~PMATest() { 49 if (constructed) A.destroy(ptr); 50 A.deallocate(ptr, 1); 51 } 52 }; 53 54 template <class T, class ...Args> 55 bool doTest(UsesAllocatorType UAExpect, Args&&... args) 56 { 57 PMATest<T> TH; 58 // UNDER TEST // 59 TH.construct(std::forward<Args>(args)...); 60 return checkConstruct<Args&&...>(*TH.ptr, UAExpect, &TH.R); 61 // ------- // 62 } 63 64 65 template <class T, class ...Args> 66 bool doTestUsesAllocV0(Args&&... args) 67 { 68 PMATest<T> TH; 69 // UNDER TEST // 70 TH.construct(std::forward<Args>(args)...); 71 return checkConstruct<Args&&...>(*TH.ptr, UA_None); 72 // -------- // 73 } 74 75 76 template <class T, class EAlloc, class ...Args> 77 bool doTestUsesAllocV1(EAlloc const& ealloc, Args&&... args) 78 { 79 PMATest<T> TH; 80 // UNDER TEST // 81 TH.construct(std::allocator_arg, ealloc, std::forward<Args>(args)...); 82 return checkConstruct<Args&&...>(*TH.ptr, UA_AllocArg, ealloc); 83 // -------- // 84 } 85 86 template <class T, class EAlloc, class ...Args> 87 bool doTestUsesAllocV2(EAlloc const& ealloc, Args&&... args) 88 { 89 PMATest<T> TH; 90 // UNDER TEST // 91 TH.construct(std::forward<Args>(args)..., ealloc); 92 return checkConstruct<Args&&...>(*TH.ptr, UA_AllocLast, ealloc); 93 // -------- // 94 } 95 96 template <class Alloc, class ...Args> 97 void test_pmr_uses_alloc(Args&&... args) 98 { 99 TestResource R(12435); 100 ex::memory_resource* M = &R; 101 { 102 // NotUsesAllocator provides valid signatures for each uses-allocator 103 // construction but does not supply the required allocator_type typedef. 104 // Test that we can call these constructors manually without 105 // polymorphic_allocator interfering. 106 using T = NotUsesAllocator<Alloc, sizeof...(Args)>; 107 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...)); 108 assert((doTestUsesAllocV1<T>(M, std::forward<Args>(args)...))); 109 assert((doTestUsesAllocV2<T>(M, std::forward<Args>(args)...))); 110 } 111 { 112 // Test T(std::allocator_arg_t, Alloc const&, Args...) construction 113 using T = UsesAllocatorV1<Alloc, sizeof...(Args)>; 114 assert((doTest<T>(UA_AllocArg, std::forward<Args>(args)...))); 115 } 116 { 117 // Test T(Args..., Alloc const&) construction 118 using T = UsesAllocatorV2<Alloc, sizeof...(Args)>; 119 assert((doTest<T>(UA_AllocLast, std::forward<Args>(args)...))); 120 } 121 { 122 // Test that T(std::allocator_arg_t, Alloc const&, Args...) construction 123 // is preferred when T(Args..., Alloc const&) is also available. 124 using T = UsesAllocatorV3<Alloc, sizeof...(Args)>; 125 assert((doTest<T>(UA_AllocArg, std::forward<Args>(args)...))); 126 } 127 } 128 129 // Test that polymorphic_allocator does not prevent us from manually 130 // doing non-pmr uses-allocator construction. 131 template <class Alloc, class AllocObj, class ...Args> 132 void test_non_pmr_uses_alloc(AllocObj const& A, Args&&... args) 133 { 134 { 135 using T = NotUsesAllocator<Alloc, sizeof...(Args)>; 136 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...)); 137 assert((doTestUsesAllocV1<T>(A, std::forward<Args>(args)...))); 138 assert((doTestUsesAllocV2<T>(A, std::forward<Args>(args)...))); 139 } 140 { 141 using T = UsesAllocatorV1<Alloc, sizeof...(Args)>; 142 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...)); 143 assert((doTestUsesAllocV1<T>(A, std::forward<Args>(args)...))); 144 } 145 { 146 using T = UsesAllocatorV2<Alloc, sizeof...(Args)>; 147 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...)); 148 assert((doTestUsesAllocV2<T>(A, std::forward<Args>(args)...))); 149 } 150 { 151 using T = UsesAllocatorV3<Alloc, sizeof...(Args)>; 152 assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...)); 153 assert((doTestUsesAllocV1<T>(A, std::forward<Args>(args)...))); 154 assert((doTestUsesAllocV2<T>(A, std::forward<Args>(args)...))); 155 } 156 } 157 158 int main() 159 { 160 using ET = std::experimental::erased_type; 161 using PMR = ex::memory_resource*; 162 using PMA = ex::polymorphic_allocator<void>; 163 using STDA = std::allocator<char>; 164 using TESTA = test_allocator<char>; 165 166 int value = 42; 167 const int cvalue = 43; 168 { 169 test_pmr_uses_alloc<ET>(); 170 test_pmr_uses_alloc<PMR>(); 171 test_pmr_uses_alloc<PMA>(); 172 test_pmr_uses_alloc<ET>(value); 173 test_pmr_uses_alloc<PMR>(value); 174 test_pmr_uses_alloc<PMA>(value); 175 test_pmr_uses_alloc<ET>(cvalue); 176 test_pmr_uses_alloc<PMR>(cvalue); 177 test_pmr_uses_alloc<PMA>(cvalue); 178 test_pmr_uses_alloc<ET>(cvalue, std::move(value)); 179 test_pmr_uses_alloc<PMR>(cvalue, std::move(value)); 180 test_pmr_uses_alloc<PMA>(cvalue, std::move(value)); 181 } 182 { 183 STDA std_alloc; 184 TESTA test_alloc(42); 185 test_non_pmr_uses_alloc<STDA>(std_alloc); 186 test_non_pmr_uses_alloc<TESTA>(test_alloc); 187 test_non_pmr_uses_alloc<STDA>(std_alloc, value); 188 test_non_pmr_uses_alloc<TESTA>(test_alloc, value); 189 test_non_pmr_uses_alloc<STDA>(std_alloc, cvalue); 190 test_non_pmr_uses_alloc<TESTA>(test_alloc, cvalue); 191 test_non_pmr_uses_alloc<STDA>(std_alloc, cvalue, std::move(value)); 192 test_non_pmr_uses_alloc<TESTA>(test_alloc, cvalue, std::move(value)); 193 } 194 } 195