Home | History | Annotate | Download | only in memory.polymorphic.allocator.mem
      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