1257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier//===----------------------------------------------------------------------===//
2257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier//
3257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier//                     The LLVM Compiler Infrastructure
4257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier//
5257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier// This file is dual licensed under the MIT and the University of Illinois Open
6257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier// Source Licenses. See LICENSE.TXT for details.
7257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier//
8257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier//===----------------------------------------------------------------------===//
9257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
10257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#ifndef SUPPORT_TEST_MEMORY_RESOURCE_HPP
11257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#define SUPPORT_TEST_MEMORY_RESOURCE_HPP
12257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
13257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#include <experimental/memory_resource>
14e386ad3090e7979c26c97a9a717624f8fc69d8f4Eric Fiselier#include <experimental/utility>
15257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#include <memory>
16257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#include <type_traits>
17257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#include <cstddef>
18257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#include <cstdlib>
19257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#include <cstring>
202aad5d548c2b02bd8e07394a484ae857436c5b03Eric Fiselier#include <cstdint>
21257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#include <cassert>
22257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#include "test_macros.h"
23e386ad3090e7979c26c97a9a717624f8fc69d8f4Eric Fiselier#include "controlled_allocators.hpp"
24e386ad3090e7979c26c97a9a717624f8fc69d8f4Eric Fiselier#include "uses_alloc_types.hpp"
25e386ad3090e7979c26c97a9a717624f8fc69d8f4Eric Fiselier
26e386ad3090e7979c26c97a9a717624f8fc69d8f4Eric Fiselier// FIXME: This is a hack to allow uses_allocator_types.hpp to work with
27e386ad3090e7979c26c97a9a717624f8fc69d8f4Eric Fiselier// erased_type. However we can't define that behavior directly in the header
2816e2ba19dfffdcf9bba202eb8a27fd79e3d15303Stephan T. Lavavej// because it can't include <experimental/memory_resource>
29e386ad3090e7979c26c97a9a717624f8fc69d8f4Eric Fiseliertemplate <>
30e386ad3090e7979c26c97a9a717624f8fc69d8f4Eric Fiselierstruct TransformErasedTypeAlloc<std::experimental::erased_type> {
31e386ad3090e7979c26c97a9a717624f8fc69d8f4Eric Fiselier  using type = std::experimental::pmr::memory_resource*;
32257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier};
33257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
34257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiseliertemplate <class ProviderT, int = 0>
35257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierclass TestResourceImp : public std::experimental::pmr::memory_resource
36257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier{
37257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierpublic:
38257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    static int resource_alive;
39257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    static int resource_constructed;
40257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    static int resource_destructed;
41257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
42257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    static void resetStatics() {
43257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        assert(resource_alive == 0);
44257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        resource_alive = 0;
45257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        resource_constructed = 0;
46257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        resource_destructed = 0;
47257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    }
48257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
49257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    using memory_resource = std::experimental::pmr::memory_resource;
50257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    using Provider = ProviderT;
51257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
52257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    int value;
53257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
54257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    explicit TestResourceImp(int val = 0) : value(val) {
55257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        ++resource_alive;
56257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        ++resource_constructed;
57257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    }
58257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
59257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    ~TestResourceImp() noexcept {
60257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        --resource_alive;
61257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        ++resource_destructed;
62257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    }
63257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
64257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void reset() { C.reset(); P.reset(); }
65257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    AllocController& getController() { return C; }
66257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
67257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    bool checkAlloc(void* p, std::size_t s, std::size_t a) const
68257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier      { return C.checkAlloc(p, s, a); }
69257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
70257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    bool checkDealloc(void* p, std::size_t s, std::size_t a) const
71257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier      { return C.checkDealloc(p, s, a); }
72257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
73257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    bool checkIsEqualCalledEq(int n) const { return C.checkIsEqualCalledEq(n); }
74257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
75257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierprotected:
76257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    virtual void * do_allocate(std::size_t s, std::size_t a) {
77257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        if (C.throw_on_alloc) {
78257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#ifndef TEST_HAS_NO_EXCEPTIONS
79257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier            throw TestException{};
80257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#else
81257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier            assert(false);
82257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#endif
83257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        }
84257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        void* ret = P.allocate(s, a);
85257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        C.countAlloc(ret, s, a);
86257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        return ret;
87257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    }
88257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
89257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    virtual void do_deallocate(void * p, std::size_t s, std::size_t a) {
90257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        C.countDealloc(p, s, a);
91257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        P.deallocate(p, s, a);
92257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    }
93257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
94257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    virtual bool do_is_equal(memory_resource const & other) const noexcept {
95257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        C.countIsEqual();
96257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        TestResourceImp const * o = dynamic_cast<TestResourceImp const *>(&other);
97257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        return o && o->value == value;
98257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    }
99257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierprivate:
100257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    mutable AllocController C;
101257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    mutable Provider P;
102257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    DISALLOW_COPY(TestResourceImp);
103257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier};
104257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
105257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiseliertemplate <class Provider, int N>
106257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierint TestResourceImp<Provider, N>::resource_alive = 0;
107257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
108257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiseliertemplate <class Provider, int N>
109257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierint TestResourceImp<Provider, N>::resource_constructed = 0;
110257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
111257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiseliertemplate <class Provider, int N>
112257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierint TestResourceImp<Provider, N>::resource_destructed = 0;
113257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
114257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
115257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierstruct NullProvider {
116257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    NullProvider() {}
117257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void* allocate(size_t, size_t) { return nullptr; }
118257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void deallocate(void*, size_t, size_t) {}
119257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void reset() {}
120257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierprivate:
121257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    DISALLOW_COPY(NullProvider);
122257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier};
123257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
124257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierstruct NewDeleteProvider {
125257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    NewDeleteProvider() {}
126257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void* allocate(size_t s, size_t) { return ::operator new(s); }
127257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void deallocate(void* p, size_t, size_t) { ::operator delete(p); }
128257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void reset() {}
129257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierprivate:
130257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    DISALLOW_COPY(NewDeleteProvider);
131257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier};
132257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
133257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiseliertemplate <size_t Size = 4096 * 10> // 10 pages worth of memory.
134257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierstruct BufferProvider {
135257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    char buffer[Size];
136257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void* next = &buffer;
137257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    size_t space = Size;
138257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
139257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    BufferProvider() {}
140257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
141257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void* allocate(size_t s, size_t a) {
142257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        void* ret = std::align(s, a, next, space);
143257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        if (ret == nullptr) {
144257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#ifndef TEST_HAS_NO_EXCEPTIONS
145257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier            throw std::bad_alloc();
146257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#else
147257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier            assert(false);
148257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#endif
149257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        }
150257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
151257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        return ret;
152257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    }
153257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
154257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void deallocate(void*, size_t, size_t) {}
155257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
156257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    void reset() {
157257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        next = &buffer;
158257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier        space = Size;
159257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    }
160257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierprivate:
161257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier    DISALLOW_COPY(BufferProvider);
162257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier};
163257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
164257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierusing NullResource = TestResourceImp<NullProvider, 0>;
165257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierusing NewDeleteResource = TestResourceImp<NewDeleteProvider, 0>;
166257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierusing TestResource  = TestResourceImp<BufferProvider<>, 0>;
167257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierusing TestResource1 = TestResourceImp<BufferProvider<>, 1>;
168257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselierusing TestResource2 = TestResourceImp<BufferProvider<>, 2>;
169257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
170257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier
171257fd699fd62d09908944845fba04c4a9ab8d03bEric Fiselier#endif /* SUPPORT_TEST_MEMORY_RESOURCE_HPP */
172