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>
29template <>
30struct TransformErasedTypeAlloc<std::experimental::erased_type> {
31  using type = std::experimental::pmr::memory_resource*;
32};
33
34template <class ProviderT, int = 0>
35class TestResourceImp : public std::experimental::pmr::memory_resource
36{
37public:
38    static int resource_alive;
39    static int resource_constructed;
40    static int resource_destructed;
41
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
54    explicit TestResourceImp(int val = 0) : value(val) {
55        ++resource_alive;
56        ++resource_constructed;
57    }
58
59    ~TestResourceImp() noexcept {
60        --resource_alive;
61        ++resource_destructed;
62    }
63
64    void reset() { C.reset(); P.reset(); }
65    AllocController& getController() { return C; }
66
67    bool checkAlloc(void* p, std::size_t s, std::size_t a) const
68      { return C.checkAlloc(p, s, a); }
69
70    bool checkDealloc(void* p, std::size_t s, std::size_t a) const
71      { return C.checkDealloc(p, s, a); }
72
73    bool checkIsEqualCalledEq(int n) const { return C.checkIsEqualCalledEq(n); }
74
75protected:
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
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
94    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    }
99private:
100    mutable AllocController C;
101    mutable Provider P;
102    DISALLOW_COPY(TestResourceImp);
103};
104
105template <class Provider, int N>
106int TestResourceImp<Provider, N>::resource_alive = 0;
107
108template <class Provider, int N>
109int TestResourceImp<Provider, N>::resource_constructed = 0;
110
111template <class Provider, int N>
112int TestResourceImp<Provider, N>::resource_destructed = 0;
113
114
115struct NullProvider {
116    NullProvider() {}
117    void* allocate(size_t, size_t) { return nullptr; }
118    void deallocate(void*, size_t, size_t) {}
119    void reset() {}
120private:
121    DISALLOW_COPY(NullProvider);
122};
123
124struct NewDeleteProvider {
125    NewDeleteProvider() {}
126    void* allocate(size_t s, size_t) { return ::operator new(s); }
127    void deallocate(void* p, size_t, size_t) { ::operator delete(p); }
128    void reset() {}
129private:
130    DISALLOW_COPY(NewDeleteProvider);
131};
132
133template <size_t Size = 4096 * 10> // 10 pages worth of memory.
134struct BufferProvider {
135    char buffer[Size];
136    void* next = &buffer;
137    size_t space = Size;
138
139    BufferProvider() {}
140
141    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
154    void deallocate(void*, size_t, size_t) {}
155
156    void reset() {
157        next = &buffer;
158        space = Size;
159    }
160private:
161    DISALLOW_COPY(BufferProvider);
162};
163
164using NullResource = TestResourceImp<NullProvider, 0>;
165using NewDeleteResource = TestResourceImp<NewDeleteProvider, 0>;
166using TestResource  = TestResourceImp<BufferProvider<>, 0>;
167using TestResource1 = TestResourceImp<BufferProvider<>, 1>;
168using TestResource2 = TestResourceImp<BufferProvider<>, 2>;
169
170
171#endif /* SUPPORT_TEST_MEMORY_RESOURCE_HPP */
172