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 // 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