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_MEMORY_RESOURCE_H 10 #define SUPPORT_TEST_MEMORY_RESOURCE_H 11 12 #include <experimental/memory_resource> 13 #include <experimental/utility> 14 #include <memory> 15 #include <type_traits> 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 // FIXME: This is a hack to allow uses_allocator_types.hpp to work with 26 // erased_type. However we can't define that behavior directly in the header 27 // because it can't include <experimental/memory_resource> 28 template <> 29 struct TransformErasedTypeAlloc<std::experimental::erased_type> { 30 using type = std::experimental::pmr::polymorphic_allocator<int>; 31 }; 32 33 template <class ProviderT, int = 0> 34 class TestResourceImp : public std::experimental::pmr::memory_resource 35 { 36 public: 37 static int resource_alive; 38 static int resource_constructed; 39 static int resource_destructed; 40 41 static void resetStatics() { 42 assert(resource_alive == 0); 43 resource_alive = 0; 44 resource_constructed = 0; 45 resource_destructed = 0; 46 } 47 48 using memory_resource = std::experimental::pmr::memory_resource; 49 using Provider = ProviderT; 50 51 int value; 52 53 explicit TestResourceImp(int val = 0) : value(val) { 54 ++resource_alive; 55 ++resource_constructed; 56 } 57 58 ~TestResourceImp() noexcept { 59 --resource_alive; 60 ++resource_destructed; 61 } 62 63 void reset() { C.reset(); P.reset(); } 64 AllocController& getController() { return C; } 65 66 bool checkAlloc(void* p, std::size_t s, std::size_t a) const 67 { return C.checkAlloc(p, s, a); } 68 69 bool checkDealloc(void* p, std::size_t s, std::size_t a) const 70 { return C.checkDealloc(p, s, a); } 71 72 bool checkIsEqualCalledEq(int n) const { return C.checkIsEqualCalledEq(n); } 73 74 protected: 75 virtual void * do_allocate(std::size_t s, std::size_t a) { 76 if (C.throw_on_alloc) { 77 #ifndef TEST_HAS_NO_EXCEPTIONS 78 throw TestException{}; 79 #else 80 assert(false); 81 #endif 82 } 83 void* ret = P.allocate(s, a); 84 C.countAlloc(ret, s, a); 85 return ret; 86 } 87 88 virtual void do_deallocate(void * p, std::size_t s, std::size_t a) { 89 C.countDealloc(p, s, a); 90 P.deallocate(p, s, a); 91 } 92 93 virtual bool do_is_equal(memory_resource const & other) const noexcept { 94 C.countIsEqual(); 95 TestResourceImp const * o = dynamic_cast<TestResourceImp const *>(&other); 96 return o && o->value == value; 97 } 98 private: 99 mutable AllocController C; 100 mutable Provider P; 101 DISALLOW_COPY(TestResourceImp); 102 }; 103 104 template <class Provider, int N> 105 int TestResourceImp<Provider, N>::resource_alive = 0; 106 107 template <class Provider, int N> 108 int TestResourceImp<Provider, N>::resource_constructed = 0; 109 110 template <class Provider, int N> 111 int TestResourceImp<Provider, N>::resource_destructed = 0; 112 113 114 struct NullProvider { 115 NullProvider() {} 116 void* allocate(size_t, size_t) { return nullptr; } 117 void deallocate(void*, size_t, size_t) {} 118 void reset() {} 119 private: 120 DISALLOW_COPY(NullProvider); 121 }; 122 123 struct NewDeleteProvider { 124 NewDeleteProvider() {} 125 void* allocate(size_t s, size_t) { return ::operator new(s); } 126 void deallocate(void* p, size_t, size_t) { ::operator delete(p); } 127 void reset() {} 128 private: 129 DISALLOW_COPY(NewDeleteProvider); 130 }; 131 132 template <size_t Size = 4096 * 10> // 10 pages worth of memory. 133 struct BufferProvider { 134 char buffer[Size]; 135 void* next = &buffer; 136 size_t space = Size; 137 138 BufferProvider() {} 139 140 void* allocate(size_t s, size_t a) { 141 void* ret = std::align(s, a, 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 153 void deallocate(void*, size_t, size_t) {} 154 155 void reset() { 156 next = &buffer; 157 space = Size; 158 } 159 private: 160 DISALLOW_COPY(BufferProvider); 161 }; 162 163 using NullResource = TestResourceImp<NullProvider, 0>; 164 using NewDeleteResource = TestResourceImp<NewDeleteProvider, 0>; 165 using TestResource = TestResourceImp<BufferProvider<>, 0>; 166 using TestResource1 = TestResourceImp<BufferProvider<>, 1>; 167 using TestResource2 = TestResourceImp<BufferProvider<>, 2>; 168 169 170 #endif /* SUPPORT_TEST_MEMORY_RESOURCE_H */ 171