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 U1, class U2, class ...Args1, class ...Args2> 17 // void polymorphic_allocator<T>::construct(pair<T1, T2>*, piecewise_construct_t 18 // tuple<Args1...> x, tuple<Args2...>) 19 20 // The stardard specifiers a tranformation to uses-allocator construction as 21 // follows: 22 // - If uses_allocator_v<T1,memory_resource*> is false and 23 // is_constructible_v<T,Args1...> is true, then xprime is x. 24 // - Otherwise, if uses_allocator_v<T1,memory_resource*> is true and 25 // is_constructible_v<T1,allocator_arg_t,memory_resource*,Args1...> is true, 26 // then xprime is 27 // tuple_cat(make_tuple(allocator_arg, this->resource()), std::move(x)). 28 // - Otherwise, if uses_allocator_v<T1,memory_resource*> is true and 29 // is_constructible_v<T1,Args1...,memory_resource*> is true, then xprime is 30 // tuple_cat(std::move(x), make_tuple(this->resource())). 31 // - Otherwise the program is ill formed. 32 // 33 // The use of "xprime = tuple_cat(..., std::move(x), ...)" causes all of the 34 // objects in 'x' to be copied into 'xprime'. If 'x' contains any types which 35 // are stored by value this causes an unessary copy to occur. To prevent this 36 // libc++ changes this call into 37 // "xprime = forward_as_tuple(..., std::get<Idx>(std::move(x))..., ...)". 38 // 'xprime' contains references to the values in 'x' instead of copying them. 39 40 // This test checks the number of copies incurred to the elements in 41 // 'tuple<Args1...>' and 'tuple<Args2...>'. 42 43 #include <experimental/memory_resource> 44 #include <type_traits> 45 #include <utility> 46 #include <tuple> 47 #include <cassert> 48 #include <cstdlib> 49 #include "test_memory_resource.hpp" 50 51 namespace ex = std::experimental::pmr; 52 53 template <class T> 54 struct TestHarness { 55 TestResource R; 56 ex::memory_resource * M = &R; 57 ex::polymorphic_allocator<T> A = M; 58 bool constructed = false; 59 T * ptr; 60 61 TestHarness() : ptr(A.allocate(1)) {} 62 63 template <class ...Args> 64 void construct(Args&&... args) { 65 A.construct(ptr, std::forward<Args>(args)...); 66 constructed = true; 67 } 68 69 ~TestHarness() { 70 if (constructed) A.destroy(ptr); 71 A.deallocate(ptr, 1); 72 } 73 }; 74 75 struct CountCopies { 76 int count; 77 CountCopies() : count(0) {} 78 CountCopies(CountCopies const& o) : count(o.count + 1) {} 79 }; 80 81 struct CountCopiesAllocV1 { 82 typedef ex::memory_resource* allocator_type; 83 allocator_type alloc; 84 int count; 85 CountCopiesAllocV1() : alloc(nullptr), count(0) {} 86 CountCopiesAllocV1(std::allocator_arg_t, allocator_type const& a, 87 CountCopiesAllocV1 const& o) : alloc(a), count(o.count + 1) 88 {} 89 90 CountCopiesAllocV1(CountCopiesAllocV1 const& o) : count(o.count + 1) {} 91 }; 92 93 94 struct CountCopiesAllocV2 { 95 typedef ex::memory_resource* allocator_type; 96 allocator_type alloc; 97 int count; 98 CountCopiesAllocV2() : alloc(nullptr), count(0) {} 99 CountCopiesAllocV2(CountCopiesAllocV2 const& o, allocator_type const& a) 100 : alloc(a), count(o.count + 1) 101 { } 102 103 CountCopiesAllocV2(CountCopiesAllocV2 const& o) : count(o.count + 1) {} 104 }; 105 106 107 int main() 108 { 109 using PMR = ex::memory_resource*; 110 using PMA = ex::polymorphic_allocator<char>; 111 112 { 113 using T = CountCopies; 114 using U = CountCopiesAllocV1; 115 using P = std::pair<T, U>; 116 using TH = TestHarness<P>; 117 118 std::tuple<T> t1; 119 std::tuple<U> t2; 120 121 TestHarness<P> h; 122 h.construct(std::piecewise_construct, t1, t2); 123 P const& p = *h.ptr; 124 assert(p.first.count == 2); 125 assert(p.second.count == 2); 126 assert(p.second.alloc == h.M); 127 } 128 { 129 using T = CountCopiesAllocV1; 130 using U = CountCopiesAllocV2; 131 using P = std::pair<T, U>; 132 using TH = TestHarness<P>; 133 134 std::tuple<T> t1; 135 std::tuple<U> t2; 136 137 TestHarness<P> h; 138 h.construct(std::piecewise_construct, std::move(t1), std::move(t2)); 139 P const& p = *h.ptr; 140 assert(p.first.count == 2); 141 assert(p.first.alloc == h.M); 142 assert(p.second.count == 2); 143 assert(p.second.alloc == h.M); 144 } 145 { 146 using T = CountCopiesAllocV2; 147 using U = CountCopiesAllocV1; 148 using P = std::pair<T, U>; 149 using TH = TestHarness<P>; 150 151 std::tuple<T> t1; 152 std::tuple<U> t2; 153 154 TestHarness<P> h; 155 h.construct(std::piecewise_construct, std::move(t1), std::move(t2)); 156 P const& p = *h.ptr; 157 assert(p.first.count == 2); 158 assert(p.first.alloc == h.M); 159 assert(p.second.count == 2); 160 assert(p.second.alloc == h.M); 161 } 162 { 163 using T = CountCopiesAllocV2; 164 using U = CountCopies; 165 using P = std::pair<T, U>; 166 using TH = TestHarness<P>; 167 168 std::tuple<T> t1; 169 std::tuple<U> t2; 170 171 TestHarness<P> h; 172 h.construct(std::piecewise_construct, t1, t2); 173 P const& p = *h.ptr; 174 assert(p.first.count == 2); 175 assert(p.first.alloc == h.M); 176 assert(p.second.count == 2); 177 } 178 } 179