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