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