xref: /llvm-project/libcxx/test/support/test_std_memory_resource.h (revision fb855eb941b6d740cc6560297d0b4d3201dcaf9f)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef SUPPORT_TEST_STD_MEMORY_RESOURCE_H
10 #define SUPPORT_TEST_STD_MEMORY_RESOURCE_H
11 
12 #include <memory>
13 #include <memory_resource>
14 #include <type_traits>
15 #include <utility>
16 #include <cstddef>
17 #include <cstdlib>
18 #include <cstring>
19 #include <cstdint>
20 #include <cassert>
21 #include "test_macros.h"
22 #include "controlled_allocators.h"
23 #include "uses_alloc_types.h"
24 
25 template <class ProviderT, int = 0>
26 class TestResourceImp : public std::pmr::memory_resource {
27 public:
28   static int resource_alive;
29   static int resource_constructed;
30   static int resource_destructed;
31 
resetStatics()32   static void resetStatics() {
33     assert(resource_alive == 0);
34     resource_alive       = 0;
35     resource_constructed = 0;
36     resource_destructed  = 0;
37   }
38 
39   using memory_resource = std::pmr::memory_resource;
40   using Provider        = ProviderT;
41 
42   int value;
43 
value(val)44   explicit TestResourceImp(int val = 0) : value(val) {
45     ++resource_alive;
46     ++resource_constructed;
47   }
48 
~TestResourceImp()49   ~TestResourceImp() noexcept {
50     --resource_alive;
51     ++resource_destructed;
52   }
53 
reset()54   void reset() {
55     C.reset();
56     P.reset();
57   }
getController()58   AllocController& getController() { return C; }
59 
checkAlloc(void * p,std::size_t s,std::size_t a)60   bool checkAlloc(void* p, std::size_t s, std::size_t a) const { return C.checkAlloc(p, s, a); }
61 
checkDealloc(void * p,std::size_t s,std::size_t a)62   bool checkDealloc(void* p, std::size_t s, std::size_t a) const { return C.checkDealloc(p, s, a); }
63 
checkIsEqualCalledEq(int n)64   bool checkIsEqualCalledEq(int n) const { return C.checkIsEqualCalledEq(n); }
65 
66 protected:
do_allocate(std::size_t s,std::size_t a)67   virtual void* do_allocate(std::size_t s, std::size_t a) {
68     if (C.throw_on_alloc) {
69 #ifndef TEST_HAS_NO_EXCEPTIONS
70       throw TestException{};
71 #else
72       assert(false);
73 #endif
74     }
75     void* ret = P.allocate(s, a);
76     C.countAlloc(ret, s, a);
77     return ret;
78   }
79 
do_deallocate(void * p,std::size_t s,std::size_t a)80   virtual void do_deallocate(void* p, std::size_t s, std::size_t a) {
81     C.countDealloc(p, s, a);
82     P.deallocate(p, s, a);
83   }
84 
do_is_equal(memory_resource const & other)85   virtual bool do_is_equal(memory_resource const& other) const noexcept {
86     C.countIsEqual();
87     TestResourceImp const* o = dynamic_cast<TestResourceImp const*>(&other);
88     return o && o->value == value;
89   }
90 
91 private:
92   mutable AllocController C;
93   mutable Provider P;
94   DISALLOW_COPY(TestResourceImp);
95 };
96 
97 template <class Provider, int N>
98 int TestResourceImp<Provider, N>::resource_alive = 0;
99 
100 template <class Provider, int N>
101 int TestResourceImp<Provider, N>::resource_constructed = 0;
102 
103 template <class Provider, int N>
104 int TestResourceImp<Provider, N>::resource_destructed = 0;
105 
106 struct NullProvider {
NullProviderNullProvider107   NullProvider() {}
allocateNullProvider108   void* allocate(std::size_t, size_t) {
109 #ifndef TEST_HAS_NO_EXCEPTIONS
110     throw std::runtime_error("");
111 #else
112     std::abort();
113 #endif
114   }
deallocateNullProvider115   void deallocate(void*, std::size_t, size_t) {}
resetNullProvider116   void reset() {}
117 
118 private:
119   DISALLOW_COPY(NullProvider);
120 };
121 
122 struct NewDeleteProvider {
NewDeleteProviderNewDeleteProvider123   NewDeleteProvider() {}
allocateNewDeleteProvider124   void* allocate(std::size_t s, size_t) { return ::operator new(s); }
deallocateNewDeleteProvider125   void deallocate(void* p, std::size_t, size_t) { ::operator delete(p); }
resetNewDeleteProvider126   void reset() {}
127 
128 private:
129   DISALLOW_COPY(NewDeleteProvider);
130 };
131 
132 template <std::size_t Size = 4096 * 10> // 10 pages worth of memory.
133 struct BufferProvider {
134   char buffer[Size];
135   void* next   = &buffer;
136   std::size_t space = Size;
137 
BufferProviderBufferProvider138   BufferProvider() {}
139 
allocateBufferProvider140   void* allocate(std::size_t s, size_t a) {
141     void* ret = std::align(a, s, next, space);
142     if (ret == nullptr) {
143 #ifndef TEST_HAS_NO_EXCEPTIONS
144       throw std::bad_alloc();
145 #else
146       assert(false);
147 #endif
148     }
149 
150     return ret;
151   }
152 
deallocateBufferProvider153   void deallocate(void*, std::size_t, size_t) {}
154 
resetBufferProvider155   void reset() {
156     next  = &buffer;
157     space = Size;
158   }
159 
160 private:
161   DISALLOW_COPY(BufferProvider);
162 };
163 
164 using NullResource      = TestResourceImp<NullProvider, 0>;
165 using NewDeleteResource = TestResourceImp<NewDeleteProvider, 0>;
166 using TestResource      = TestResourceImp<BufferProvider<>, 0>;
167 using TestResource1     = TestResourceImp<BufferProvider<>, 1>;
168 using TestResource2     = TestResourceImp<BufferProvider<>, 2>;
169 
170 #endif /* SUPPORT_TEST_STD_MEMORY_RESOURCE_H */
171