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