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 #ifndef SUPPORT_TEST_MEMORY_RESOURCE_HPP 11 #define SUPPORT_TEST_MEMORY_RESOURCE_HPP 12 13 #include <experimental/memory_resource> 14 #include <experimental/utility> 15 #include <memory> 16 #include <type_traits> 17 #include <cstddef> 18 #include <cstdlib> 19 #include <cstring> 20 #include <cstdint> 21 #include <cassert> 22 #include "test_macros.h" 23 #include "controlled_allocators.hpp" 24 #include "uses_alloc_types.hpp" 25 26 // FIXME: This is a hack to allow uses_allocator_types.hpp to work with 27 // erased_type. However we can't define that behavior directly in the header 28 // because it can't include <experimental/memory_resource> 29 template <> 30 struct TransformErasedTypeAlloc<std::experimental::erased_type> { 31 using type = std::experimental::pmr::polymorphic_allocator<int>; 32 }; 33 34 template <class ProviderT, int = 0> 35 class TestResourceImp : public std::experimental::pmr::memory_resource 36 { 37 public: 38 static int resource_alive; 39 static int resource_constructed; 40 static int resource_destructed; 41 resetStatics()42 static void resetStatics() { 43 assert(resource_alive == 0); 44 resource_alive = 0; 45 resource_constructed = 0; 46 resource_destructed = 0; 47 } 48 49 using memory_resource = std::experimental::pmr::memory_resource; 50 using Provider = ProviderT; 51 52 int value; 53 TestResourceImp(int val=0)54 explicit TestResourceImp(int val = 0) : value(val) { 55 ++resource_alive; 56 ++resource_constructed; 57 } 58 ~TestResourceImp()59 ~TestResourceImp() noexcept { 60 --resource_alive; 61 ++resource_destructed; 62 } 63 reset()64 void reset() { C.reset(); P.reset(); } getController()65 AllocController& getController() { return C; } 66 checkAlloc(void * p,std::size_t s,std::size_t a) const67 bool checkAlloc(void* p, std::size_t s, std::size_t a) const 68 { return C.checkAlloc(p, s, a); } 69 checkDealloc(void * p,std::size_t s,std::size_t a) const70 bool checkDealloc(void* p, std::size_t s, std::size_t a) const 71 { return C.checkDealloc(p, s, a); } 72 checkIsEqualCalledEq(int n) const73 bool checkIsEqualCalledEq(int n) const { return C.checkIsEqualCalledEq(n); } 74 75 protected: do_allocate(std::size_t s,std::size_t a)76 virtual void * do_allocate(std::size_t s, std::size_t a) { 77 if (C.throw_on_alloc) { 78 #ifndef TEST_HAS_NO_EXCEPTIONS 79 throw TestException{}; 80 #else 81 assert(false); 82 #endif 83 } 84 void* ret = P.allocate(s, a); 85 C.countAlloc(ret, s, a); 86 return ret; 87 } 88 do_deallocate(void * p,std::size_t s,std::size_t a)89 virtual void do_deallocate(void * p, std::size_t s, std::size_t a) { 90 C.countDealloc(p, s, a); 91 P.deallocate(p, s, a); 92 } 93 do_is_equal(memory_resource const & other) const94 virtual bool do_is_equal(memory_resource const & other) const noexcept { 95 C.countIsEqual(); 96 TestResourceImp const * o = dynamic_cast<TestResourceImp const *>(&other); 97 return o && o->value == value; 98 } 99 private: 100 mutable AllocController C; 101 mutable Provider P; 102 DISALLOW_COPY(TestResourceImp); 103 }; 104 105 template <class Provider, int N> 106 int TestResourceImp<Provider, N>::resource_alive = 0; 107 108 template <class Provider, int N> 109 int TestResourceImp<Provider, N>::resource_constructed = 0; 110 111 template <class Provider, int N> 112 int TestResourceImp<Provider, N>::resource_destructed = 0; 113 114 115 struct NullProvider { NullProviderNullProvider116 NullProvider() {} allocateNullProvider117 void* allocate(size_t, size_t) { return nullptr; } deallocateNullProvider118 void deallocate(void*, size_t, size_t) {} resetNullProvider119 void reset() {} 120 private: 121 DISALLOW_COPY(NullProvider); 122 }; 123 124 struct NewDeleteProvider { NewDeleteProviderNewDeleteProvider125 NewDeleteProvider() {} allocateNewDeleteProvider126 void* allocate(size_t s, size_t) { return ::operator new(s); } deallocateNewDeleteProvider127 void deallocate(void* p, size_t, size_t) { ::operator delete(p); } resetNewDeleteProvider128 void reset() {} 129 private: 130 DISALLOW_COPY(NewDeleteProvider); 131 }; 132 133 template <size_t Size = 4096 * 10> // 10 pages worth of memory. 134 struct BufferProvider { 135 char buffer[Size]; 136 void* next = &buffer; 137 size_t space = Size; 138 BufferProviderBufferProvider139 BufferProvider() {} 140 allocateBufferProvider141 void* allocate(size_t s, size_t a) { 142 void* ret = std::align(s, a, next, space); 143 if (ret == nullptr) { 144 #ifndef TEST_HAS_NO_EXCEPTIONS 145 throw std::bad_alloc(); 146 #else 147 assert(false); 148 #endif 149 } 150 151 return ret; 152 } 153 deallocateBufferProvider154 void deallocate(void*, size_t, size_t) {} 155 resetBufferProvider156 void reset() { 157 next = &buffer; 158 space = Size; 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 171 #endif /* SUPPORT_TEST_MEMORY_RESOURCE_HPP */ 172