1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef SUPPORT_TEST_MEMORY_RESOURCE_H
10 #define SUPPORT_TEST_MEMORY_RESOURCE_H
12 #include <experimental/memory_resource>
13 #include <experimental/utility>
15 #include <type_traits>
21 #include "test_macros.h"
22 #include "controlled_allocators.h"
23 #include "uses_alloc_types.h"
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>
29 struct TransformErasedTypeAlloc
<std::experimental::erased_type
> {
30 using type
= std::experimental::pmr::polymorphic_allocator
<int>;
33 template <class ProviderT
, int = 0>
34 class TestResourceImp
: public std::experimental::pmr::memory_resource
37 static int resource_alive
;
38 static int resource_constructed
;
39 static int resource_destructed
;
41 static void resetStatics() {
42 assert(resource_alive
== 0);
44 resource_constructed
= 0;
45 resource_destructed
= 0;
48 using memory_resource
= std::experimental::pmr::memory_resource
;
49 using Provider
= ProviderT
;
53 explicit TestResourceImp(int val
= 0) : value(val
) {
55 ++resource_constructed
;
58 ~TestResourceImp() noexcept
{
60 ++resource_destructed
;
63 void reset() { C
.reset(); P
.reset(); }
64 AllocController
& getController() { return C
; }
66 bool checkAlloc(void* p
, std::size_t s
, std::size_t a
) const
67 { return C
.checkAlloc(p
, s
, a
); }
69 bool checkDealloc(void* p
, std::size_t s
, std::size_t a
) const
70 { return C
.checkDealloc(p
, s
, a
); }
72 bool checkIsEqualCalledEq(int n
) const { return C
.checkIsEqualCalledEq(n
); }
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
{};
83 void* ret
= P
.allocate(s
, a
);
84 C
.countAlloc(ret
, s
, a
);
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
);
93 virtual bool do_is_equal(memory_resource
const & other
) const noexcept
{
95 TestResourceImp
const * o
= dynamic_cast<TestResourceImp
const *>(&other
);
96 return o
&& o
->value
== value
;
99 mutable AllocController C
;
101 DISALLOW_COPY(TestResourceImp
);
104 template <class Provider
, int N
>
105 int TestResourceImp
<Provider
, N
>::resource_alive
= 0;
107 template <class Provider
, int N
>
108 int TestResourceImp
<Provider
, N
>::resource_constructed
= 0;
110 template <class Provider
, int N
>
111 int TestResourceImp
<Provider
, N
>::resource_destructed
= 0;
114 struct NullProvider
{
116 void* allocate(size_t, size_t) { return nullptr; }
117 void deallocate(void*, size_t, size_t) {}
120 DISALLOW_COPY(NullProvider
);
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
); }
129 DISALLOW_COPY(NewDeleteProvider
);
132 template <size_t Size
= 4096 * 10> // 10 pages worth of memory.
133 struct BufferProvider
{
135 void* next
= &buffer
;
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();
153 void deallocate(void*, size_t, size_t) {}
160 DISALLOW_COPY(BufferProvider
);
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>;
170 #endif /* SUPPORT_TEST_MEMORY_RESOURCE_H */