xref: /llvm-project/libcxx/test/support/controlled_allocators.h (revision fb855eb941b6d740cc6560297d0b4d3201dcaf9f)
1cc89063bSNico Weber //===----------------------------------------------------------------------===//
2cc89063bSNico Weber //
3cc89063bSNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4cc89063bSNico Weber // See https://llvm.org/LICENSE.txt for license information.
5cc89063bSNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cc89063bSNico Weber //
7cc89063bSNico Weber //===----------------------------------------------------------------------===//
8cc89063bSNico Weber 
9cc89063bSNico Weber #ifndef SUPPORT_CONTROLLED_ALLOCATORS_H
10cc89063bSNico Weber #define SUPPORT_CONTROLLED_ALLOCATORS_H
11cc89063bSNico Weber 
12cc89063bSNico Weber #include <memory>
13cc89063bSNico Weber #include <type_traits>
14cc89063bSNico Weber #include <cstddef>
15cc89063bSNico Weber #include <cstdlib>
16cc89063bSNico Weber #include <cstring>
17cc89063bSNico Weber #include <cstdint>
18cc89063bSNico Weber #include <cassert>
19d5e26775SNikolas Klauser #include <new>
20d5e26775SNikolas Klauser 
21cc89063bSNico Weber #include "test_macros.h"
22cc89063bSNico Weber #include "type_id.h"
23cc89063bSNico Weber 
24cc89063bSNico Weber #if TEST_STD_VER < 11
25cc89063bSNico Weber #error This header requires C++11 or greater
26cc89063bSNico Weber #endif
27cc89063bSNico Weber 
28cc89063bSNico Weber struct AllocController;
29cc89063bSNico Weber     // 'AllocController' is a concrete type that instruments and controls the
30cc89063bSNico Weber     // behavior of test allocators.
31cc89063bSNico Weber 
32*fb855eb9SMark de Wever template <class T, std::size_t ID = 0>
33cc89063bSNico Weber class CountingAllocator;
34cc89063bSNico Weber     // 'CountingAllocator' is an basic implementation of the 'Allocator'
35cc89063bSNico Weber     // requirements that use the 'AllocController' interface.
36cc89063bSNico Weber 
37cc89063bSNico Weber template <class T>
38cc89063bSNico Weber class MinAlignAllocator;
39cc89063bSNico Weber     // 'MinAlignAllocator' is an instrumented test type which implements the
40cc89063bSNico Weber     // 'Allocator' requirements. 'MinAlignAllocator' ensures that it *never*
41cc89063bSNico Weber     // returns a pointer to over-aligned storage. For example
42cc89063bSNico Weber     // 'MinAlignPointer<char>{}.allocate(...)' will never a 2-byte aligned
43cc89063bSNico Weber     // pointer.
44cc89063bSNico Weber 
45cc89063bSNico Weber template <class T>
46cc89063bSNico Weber class NullAllocator;
47cc89063bSNico Weber     // 'NullAllocator' is an instrumented test type which implements the
48cc89063bSNico Weber     // 'Allocator' requirements except that 'allocator' and 'deallocate' are
49cc89063bSNico Weber     // nops.
50cc89063bSNico Weber 
51cc89063bSNico Weber 
52cc89063bSNico Weber #define DISALLOW_COPY(Type) \
53cc89063bSNico Weber   Type(Type const&) = delete; \
54cc89063bSNico Weber   Type& operator=(Type const&) = delete
55cc89063bSNico Weber 
56cc89063bSNico Weber constexpr std::size_t MaxAlignV = alignof(std::max_align_t);
57cc89063bSNico Weber 
58cc89063bSNico Weber struct TestException {};
59cc89063bSNico Weber 
60cc89063bSNico Weber struct AllocController {
61cc89063bSNico Weber     int copy_constructed = 0;
62cc89063bSNico Weber     int move_constructed = 0;
63cc89063bSNico Weber 
64cc89063bSNico Weber     int alive = 0;
65cc89063bSNico Weber     int alloc_count = 0;
66cc89063bSNico Weber     int dealloc_count = 0;
67cc89063bSNico Weber     int is_equal_count = 0;
68cc89063bSNico Weber 
69cc89063bSNico Weber     std::size_t alive_size;
70cc89063bSNico Weber     std::size_t allocated_size;
71cc89063bSNico Weber     std::size_t deallocated_size;
72cc89063bSNico Weber 
73cc89063bSNico Weber     std::size_t last_size = 0;
74cc89063bSNico Weber     std::size_t last_align = 0;
75cc89063bSNico Weber     void * last_pointer = 0;
76cc89063bSNico Weber 
77cc89063bSNico Weber     std::size_t last_alloc_size = 0;
78cc89063bSNico Weber     std::size_t last_alloc_align = 0;
79cc89063bSNico Weber     void * last_alloc_pointer = nullptr;
80cc89063bSNico Weber 
81cc89063bSNico Weber     std::size_t last_dealloc_size = 0;
82cc89063bSNico Weber     std::size_t last_dealloc_align = 0;
83cc89063bSNico Weber     void * last_dealloc_pointer = nullptr;
84cc89063bSNico Weber 
85cc89063bSNico Weber     bool throw_on_alloc = false;
86cc89063bSNico Weber 
87cc89063bSNico Weber     int construct_called = 0;
88cc89063bSNico Weber     void *last_construct_pointer = nullptr;
89cc89063bSNico Weber     TypeID const* last_construct_alloc = nullptr;
90cc89063bSNico Weber     TypeID const* last_construct_type = nullptr;
91cc89063bSNico Weber     TypeID const* last_construct_args = nullptr;
92cc89063bSNico Weber 
93cc89063bSNico Weber     int destroy_called = 0;
94cc89063bSNico Weber     void *last_destroy_pointer = nullptr;
95cc89063bSNico Weber     TypeID const* last_destroy_alloc = nullptr;
96cc89063bSNico Weber     TypeID const* last_destroy_type = nullptr;
97cc89063bSNico Weber 
98cc89063bSNico Weber     AllocController() = default;
99cc89063bSNico Weber 
countAllocAllocController100*fb855eb9SMark de Wever     void countAlloc(void* p, std::size_t s, size_t a) {
101cc89063bSNico Weber         ++alive;
102cc89063bSNico Weber         ++alloc_count;
103cc89063bSNico Weber         alive_size += s;
104cc89063bSNico Weber         allocated_size += s;
105cc89063bSNico Weber         last_pointer = last_alloc_pointer = p;
106cc89063bSNico Weber         last_size = last_alloc_size = s;
107cc89063bSNico Weber         last_align = last_alloc_align = a;
108cc89063bSNico Weber     }
109cc89063bSNico Weber 
countDeallocAllocController110*fb855eb9SMark de Wever     void countDealloc(void* p, std::size_t s, size_t a) {
111cc89063bSNico Weber         --alive;
112cc89063bSNico Weber         ++dealloc_count;
113cc89063bSNico Weber         alive_size -= s;
114cc89063bSNico Weber         deallocated_size += s;
115cc89063bSNico Weber         last_pointer = last_dealloc_pointer = p;
116cc89063bSNico Weber         last_size = last_dealloc_size = s;
117cc89063bSNico Weber         last_align = last_dealloc_align = a;
118cc89063bSNico Weber     }
119cc89063bSNico Weber 
120cc89063bSNico Weber     template <class ...Args, class Alloc, class Tp>
countConstructAllocController121cc89063bSNico Weber     void countConstruct(Alloc const&, Tp *p) {
122cc89063bSNico Weber       ++construct_called;
123cc89063bSNico Weber       last_construct_pointer = p;
124cc89063bSNico Weber       last_construct_alloc = &makeTypeID<Alloc>();
125cc89063bSNico Weber       last_construct_type = &makeTypeID<Tp>();
126cc89063bSNico Weber       last_construct_args = &makeArgumentID<Args...>();
127cc89063bSNico Weber     }
128cc89063bSNico Weber 
129cc89063bSNico Weber     template <class Alloc, class Tp>
countDestroyAllocController130cc89063bSNico Weber     void countDestroy(Alloc const&, Tp *p) {
131cc89063bSNico Weber       ++destroy_called;
132cc89063bSNico Weber       last_destroy_alloc = &makeTypeID<Alloc>();
133cc89063bSNico Weber       last_destroy_type = &makeTypeID<Tp>();
134cc89063bSNico Weber       last_destroy_pointer = p;
135cc89063bSNico Weber     }
136cc89063bSNico Weber 
resetAllocController137cc89063bSNico Weber     void reset() { std::memset(this, 0, sizeof(*this)); }
resetConstructDestroyAllocController138cc89063bSNico Weber     void resetConstructDestroy() {
139cc89063bSNico Weber       construct_called = 0;
140cc89063bSNico Weber       last_construct_pointer = nullptr;
141cc89063bSNico Weber       last_construct_alloc = last_construct_args = last_construct_type = nullptr;
142cc89063bSNico Weber       destroy_called = 0;
143cc89063bSNico Weber       last_destroy_alloc = nullptr;
144cc89063bSNico Weber       last_destroy_pointer = nullptr;
145cc89063bSNico Weber     }
146cc89063bSNico Weber public:
checkAllocAllocController147*fb855eb9SMark de Wever     bool checkAlloc(void* p, std::size_t s, size_t a) const {
148cc89063bSNico Weber         return p == last_alloc_pointer &&
149cc89063bSNico Weber                s == last_alloc_size &&
150cc89063bSNico Weber                a == last_alloc_align;
151cc89063bSNico Weber     }
152cc89063bSNico Weber 
checkAllocAllocController153*fb855eb9SMark de Wever     bool checkAlloc(void* p, std::size_t s) const {
154cc89063bSNico Weber         return p == last_alloc_pointer &&
155cc89063bSNico Weber                s == last_alloc_size;
156cc89063bSNico Weber     }
157cc89063bSNico Weber 
checkAllocAtLeastAllocController158*fb855eb9SMark de Wever     bool checkAllocAtLeast(void* p, std::size_t s, size_t a) const {
159cc89063bSNico Weber         return p == last_alloc_pointer &&
160cc89063bSNico Weber                s <= last_alloc_size &&
161cc89063bSNico Weber                a <= last_alloc_align;
162cc89063bSNico Weber     }
163cc89063bSNico Weber 
checkAllocAtLeastAllocController164*fb855eb9SMark de Wever     bool checkAllocAtLeast(void* p, std::size_t s) const {
165cc89063bSNico Weber         return p == last_alloc_pointer &&
166cc89063bSNico Weber                s <= last_alloc_size;
167cc89063bSNico Weber     }
168cc89063bSNico Weber 
checkDeallocAllocController169*fb855eb9SMark de Wever     bool checkDealloc(void* p, std::size_t s, size_t a) const {
170cc89063bSNico Weber         return p == last_dealloc_pointer &&
171cc89063bSNico Weber                s == last_dealloc_size &&
172cc89063bSNico Weber                a == last_dealloc_align;
173cc89063bSNico Weber     }
174cc89063bSNico Weber 
checkDeallocAllocController175*fb855eb9SMark de Wever     bool checkDealloc(void* p, std::size_t s) const {
176cc89063bSNico Weber         return p == last_dealloc_pointer &&
177cc89063bSNico Weber                s == last_dealloc_size;
178cc89063bSNico Weber     }
179cc89063bSNico Weber 
checkDeallocMatchesAllocAllocController180cc89063bSNico Weber     bool checkDeallocMatchesAlloc() const {
181cc89063bSNico Weber         return last_dealloc_pointer == last_alloc_pointer &&
182cc89063bSNico Weber                last_dealloc_size == last_alloc_size &&
183cc89063bSNico Weber                last_dealloc_align == last_alloc_align;
184cc89063bSNico Weber     }
185cc89063bSNico Weber 
186cc89063bSNico Weber     template <class ...Args, class Alloc, class Tp>
checkConstructAllocController187cc89063bSNico Weber     bool checkConstruct(Alloc const&, Tp *p) const {
188cc89063bSNico Weber         auto expectAlloc = &makeTypeID<Alloc>();
189cc89063bSNico Weber         auto expectTp = &makeTypeID<Tp>();
190cc89063bSNico Weber         auto expectArgs = &makeArgumentID<Args...>();
191e7cee55cSLouis Dionne         if (last_construct_pointer != p)
192e7cee55cSLouis Dionne             return false;
193e7cee55cSLouis Dionne         if (last_construct_alloc != expectAlloc)
194e7cee55cSLouis Dionne             return false;
195e7cee55cSLouis Dionne         if (last_construct_type != expectTp)
196e7cee55cSLouis Dionne             return false;
197e7cee55cSLouis Dionne         if (last_construct_args != expectArgs)
198e7cee55cSLouis Dionne             return false;
199e7cee55cSLouis Dionne         return true;
200cc89063bSNico Weber     }
201cc89063bSNico Weber 
202cc89063bSNico Weber     template <class Alloc, class Tp>
checkDestroyAllocController203cc89063bSNico Weber     bool checkDestroy(Alloc const&, Tp *p) const {
204cc89063bSNico Weber       return last_destroy_pointer == p &&
205cc89063bSNico Weber           last_destroy_alloc == &makeTypeID<Alloc>() &&
206cc89063bSNico Weber           last_destroy_type == &makeTypeID<Tp>();
207cc89063bSNico Weber     }
208cc89063bSNico Weber 
checkDestroyMatchesConstructAllocController209cc89063bSNico Weber     bool checkDestroyMatchesConstruct() const {
210cc89063bSNico Weber       return last_destroy_pointer == last_construct_pointer &&
211cc89063bSNico Weber           last_destroy_type == last_construct_type;
212cc89063bSNico Weber     }
213cc89063bSNico Weber 
countIsEqualAllocController214cc89063bSNico Weber     void countIsEqual() {
215cc89063bSNico Weber         ++is_equal_count;
216cc89063bSNico Weber     }
217cc89063bSNico Weber 
checkIsEqualCalledEqAllocController218cc89063bSNico Weber     bool checkIsEqualCalledEq(int n) const {
219cc89063bSNico Weber         return is_equal_count == n;
220cc89063bSNico Weber     }
221cc89063bSNico Weber private:
222cc89063bSNico Weber   DISALLOW_COPY(AllocController);
223cc89063bSNico Weber };
224cc89063bSNico Weber 
225*fb855eb9SMark de Wever template <class T, std::size_t ID>
226cc89063bSNico Weber class CountingAllocator
227cc89063bSNico Weber {
228cc89063bSNico Weber public:
229cc89063bSNico Weber     typedef T value_type;
230cc89063bSNico Weber     typedef T* pointer;
231cc89063bSNico Weber 
232cc89063bSNico Weber     template <class U>
233cc89063bSNico Weber     struct rebind { using other = CountingAllocator<U, ID>; };
234cc89063bSNico Weber 
235cc89063bSNico Weber     CountingAllocator() = delete;
CountingAllocator(AllocController & PP)236cc89063bSNico Weber     explicit CountingAllocator(AllocController& PP) : P(&PP) {}
237cc89063bSNico Weber 
CountingAllocator(CountingAllocator const & other)238cc89063bSNico Weber     CountingAllocator(CountingAllocator const& other) : P(other.P) {
239cc89063bSNico Weber         P->copy_constructed += 1;
240cc89063bSNico Weber     }
241cc89063bSNico Weber 
CountingAllocator(CountingAllocator && other)242cc89063bSNico Weber     CountingAllocator(CountingAllocator&& other) : P(other.P) {
243cc89063bSNico Weber         P->move_constructed += 1;
244cc89063bSNico Weber     }
245cc89063bSNico Weber 
246cc89063bSNico Weber     template <class U>
CountingAllocator(CountingAllocator<U,ID> const & other)247cc89063bSNico Weber     CountingAllocator(CountingAllocator<U, ID> const& other) TEST_NOEXCEPT : P(other.P) {
248cc89063bSNico Weber         P->copy_constructed += 1;
249cc89063bSNico Weber     }
250cc89063bSNico Weber 
251cc89063bSNico Weber     template <class U>
CountingAllocator(CountingAllocator<U,ID> && other)252cc89063bSNico Weber     CountingAllocator(CountingAllocator<U, ID>&& other) TEST_NOEXCEPT : P(other.P) {
253cc89063bSNico Weber         P->move_constructed += 1;
254cc89063bSNico Weber     }
255cc89063bSNico Weber 
allocate(std::size_t n)256cc89063bSNico Weber     T* allocate(std::size_t n)
257cc89063bSNico Weber     {
258cc89063bSNico Weber         void* ret = ::operator new(n*sizeof(T));
259cc89063bSNico Weber         P->countAlloc(ret, n*sizeof(T), alignof(T));
260cc89063bSNico Weber         return static_cast<T*>(ret);
261cc89063bSNico Weber     }
262cc89063bSNico Weber 
deallocate(T * p,std::size_t n)263cc89063bSNico Weber     void deallocate(T* p, std::size_t n)
264cc89063bSNico Weber     {
265cc89063bSNico Weber         void* vp = static_cast<void*>(p);
266cc89063bSNico Weber         P->countDealloc(vp, n*sizeof(T), alignof(T));
267cc89063bSNico Weber         ::operator delete(vp);
268cc89063bSNico Weber     }
269cc89063bSNico Weber 
270cc89063bSNico Weber     template <class U, class ...Args>
construct(U * p,Args &&...args)271cc89063bSNico Weber     void construct(U *p, Args&&... args) {
272cc89063bSNico Weber       ::new ((void*)p) U(std::forward<Args>(args)...);
273cc89063bSNico Weber       P->countConstruct<Args&&...>(*this, p);
274cc89063bSNico Weber     }
275cc89063bSNico Weber 
276cc89063bSNico Weber     template <class U>
destroy(U * p)277cc89063bSNico Weber     void destroy(U* p) {
278cc89063bSNico Weber       p->~U();
279cc89063bSNico Weber       P->countDestroy(*this, p);
280cc89063bSNico Weber     }
281cc89063bSNico Weber 
getController()282cc89063bSNico Weber     AllocController& getController() const { return *P; }
283cc89063bSNico Weber 
284cc89063bSNico Weber private:
285*fb855eb9SMark de Wever     template <class Tp, std::size_t XID> friend class CountingAllocator;
286cc89063bSNico Weber     AllocController *P;
287cc89063bSNico Weber };
288cc89063bSNico Weber 
289cc89063bSNico Weber 
290*fb855eb9SMark de Wever template <std::size_t ID>
291cc89063bSNico Weber class CountingAllocator<void, ID>
292cc89063bSNico Weber {
293cc89063bSNico Weber public:
294cc89063bSNico Weber     typedef void* pointer;
295cc89063bSNico Weber     typedef const void* const_pointer;
296cc89063bSNico Weber     typedef void value_type;
297cc89063bSNico Weber 
298cc89063bSNico Weber     template <class U>
299cc89063bSNico Weber     struct rebind { using other = CountingAllocator<U, ID>; };
300cc89063bSNico Weber 
301cc89063bSNico Weber     CountingAllocator() = delete;
CountingAllocator(AllocController & PP)302cc89063bSNico Weber     explicit CountingAllocator(AllocController& PP) : P(&PP) {}
303cc89063bSNico Weber 
CountingAllocator(CountingAllocator const & other)304cc89063bSNico Weber     CountingAllocator(CountingAllocator const& other) : P(other.P) {
305cc89063bSNico Weber         P->copy_constructed += 1;
306cc89063bSNico Weber     }
307cc89063bSNico Weber 
CountingAllocator(CountingAllocator && other)308cc89063bSNico Weber     CountingAllocator(CountingAllocator&& other) : P(other.P) {
309cc89063bSNico Weber         P->move_constructed += 1;
310cc89063bSNico Weber     }
311cc89063bSNico Weber 
312cc89063bSNico Weber     template <class U>
CountingAllocator(CountingAllocator<U,ID> const & other)313cc89063bSNico Weber     CountingAllocator(CountingAllocator<U, ID> const& other) TEST_NOEXCEPT : P(other.P) {
314cc89063bSNico Weber         P->copy_constructed += 1;
315cc89063bSNico Weber     }
316cc89063bSNico Weber 
317cc89063bSNico Weber     template <class U>
CountingAllocator(CountingAllocator<U,ID> && other)318cc89063bSNico Weber     CountingAllocator(CountingAllocator<U, ID>&& other) TEST_NOEXCEPT : P(other.P) {
319cc89063bSNico Weber         P->move_constructed += 1;
320cc89063bSNico Weber     }
321cc89063bSNico Weber 
322cc89063bSNico Weber     void construct(...) = delete;
323cc89063bSNico Weber     void destroy(void*) = delete;
324cc89063bSNico Weber 
getController()325cc89063bSNico Weber     AllocController& getController() const { return *P; }
326cc89063bSNico Weber 
327cc89063bSNico Weber private:
328*fb855eb9SMark de Wever     template <class Tp, std::size_t> friend class CountingAllocator;
329cc89063bSNico Weber     AllocController *P;
330cc89063bSNico Weber };
331cc89063bSNico Weber 
332*fb855eb9SMark de Wever template <class T, class U, std::size_t ID>
333cc89063bSNico Weber inline bool operator==(CountingAllocator<T, ID> const& x,
334cc89063bSNico Weber                        CountingAllocator<U, ID> const& y) {
335cc89063bSNico Weber     return &x.getController() == &y.getController();
336cc89063bSNico Weber }
337cc89063bSNico Weber 
338*fb855eb9SMark de Wever template <class T, class U, std::size_t ID>
339cc89063bSNico Weber inline bool operator!=(CountingAllocator<T, ID> const& x,
340cc89063bSNico Weber                        CountingAllocator<U, ID> const& y) {
341cc89063bSNico Weber     return !(x == y);
342cc89063bSNico Weber }
343cc89063bSNico Weber 
344cc89063bSNico Weber template <class T>
345cc89063bSNico Weber class MinAlignedAllocator
346cc89063bSNico Weber {
347cc89063bSNico Weber public:
348cc89063bSNico Weber     typedef T value_type;
349cc89063bSNico Weber     typedef T* pointer;
350cc89063bSNico Weber 
351cc89063bSNico Weber     MinAlignedAllocator() = delete;
352cc89063bSNico Weber 
MinAlignedAllocator(AllocController & R)353cc89063bSNico Weber     explicit MinAlignedAllocator(AllocController& R) : P(&R) {}
354cc89063bSNico Weber 
MinAlignedAllocator(MinAlignedAllocator const & other)355cc89063bSNico Weber     MinAlignedAllocator(MinAlignedAllocator const& other) : P(other.P) {
356cc89063bSNico Weber         P->copy_constructed += 1;
357cc89063bSNico Weber     }
358cc89063bSNico Weber 
MinAlignedAllocator(MinAlignedAllocator && other)359cc89063bSNico Weber     MinAlignedAllocator(MinAlignedAllocator&& other) : P(other.P) {
360cc89063bSNico Weber         P->move_constructed += 1;
361cc89063bSNico Weber     }
362cc89063bSNico Weber 
363cc89063bSNico Weber     template <class U>
MinAlignedAllocator(MinAlignedAllocator<U> const & other)364cc89063bSNico Weber     MinAlignedAllocator(MinAlignedAllocator<U> const& other) TEST_NOEXCEPT : P(other.P) {
365cc89063bSNico Weber         P->copy_constructed += 1;
366cc89063bSNico Weber     }
367cc89063bSNico Weber 
368cc89063bSNico Weber     template <class U>
MinAlignedAllocator(MinAlignedAllocator<U> && other)369cc89063bSNico Weber     MinAlignedAllocator(MinAlignedAllocator<U>&& other) TEST_NOEXCEPT : P(other.P) {
370cc89063bSNico Weber         P->move_constructed += 1;
371cc89063bSNico Weber     }
372cc89063bSNico Weber 
allocate(std::size_t n)373cc89063bSNico Weber     T* allocate(std::size_t n) {
374cc89063bSNico Weber         char* aligned_ptr = (char*)::operator new(alloc_size(n*sizeof(T)));
375cc89063bSNico Weber         assert(is_max_aligned(aligned_ptr));
376cc89063bSNico Weber 
377cc89063bSNico Weber         char* unaligned_ptr = aligned_ptr + alignof(T);
378cc89063bSNico Weber         assert(is_min_aligned(unaligned_ptr));
379cc89063bSNico Weber 
380cc89063bSNico Weber         P->countAlloc(unaligned_ptr, n * sizeof(T), alignof(T));
381cc89063bSNico Weber 
382cc89063bSNico Weber         return ((T*)unaligned_ptr);
383cc89063bSNico Weber     }
384cc89063bSNico Weber 
deallocate(T * p,std::size_t n)385cc89063bSNico Weber     void deallocate(T* p, std::size_t n) {
386cc89063bSNico Weber         assert(is_min_aligned(p));
387cc89063bSNico Weber 
388cc89063bSNico Weber         char* aligned_ptr = ((char*)p) - alignof(T);
389cc89063bSNico Weber         assert(is_max_aligned(aligned_ptr));
390cc89063bSNico Weber 
391cc89063bSNico Weber         P->countDealloc(p, n*sizeof(T), alignof(T));
392cc89063bSNico Weber 
393cc89063bSNico Weber         return ::operator delete(static_cast<void*>(aligned_ptr));
394cc89063bSNico Weber     }
395cc89063bSNico Weber 
396cc89063bSNico Weber     template <class U, class ...Args>
construct(U * p,Args &&...args)397cc89063bSNico Weber     void construct(U *p, Args&&... args) {
398cc89063bSNico Weber       auto *c = ::new ((void*)p) U(std::forward<Args>(args)...);
399cc89063bSNico Weber       P->countConstruct<Args&&...>(*this, p);
400cc89063bSNico Weber     }
401cc89063bSNico Weber 
402cc89063bSNico Weber     template <class U>
destroy(U * p)403cc89063bSNico Weber     void destroy(U* p) {
404cc89063bSNico Weber       p->~U();
405cc89063bSNico Weber       P->countDestroy(*this, p);
406cc89063bSNico Weber     }
407cc89063bSNico Weber 
getController()408cc89063bSNico Weber     AllocController& getController() const { return *P; }
409cc89063bSNico Weber 
410cc89063bSNico Weber private:
411cc89063bSNico Weber     static const std::size_t BlockSize = alignof(std::max_align_t);
412cc89063bSNico Weber 
alloc_size(std::size_t s)413cc89063bSNico Weber     static std::size_t alloc_size(std::size_t s) {
414cc89063bSNico Weber         std::size_t bytes = (s + BlockSize - 1) & ~(BlockSize - 1);
415cc89063bSNico Weber         bytes += BlockSize;
416cc89063bSNico Weber         assert(bytes % BlockSize == 0);
417cc89063bSNico Weber         return bytes;
418cc89063bSNico Weber     }
419cc89063bSNico Weber 
is_max_aligned(void * p)420cc89063bSNico Weber     static bool is_max_aligned(void* p) {
421cc89063bSNico Weber         return reinterpret_cast<std::uintptr_t>(p) % BlockSize == 0;
422cc89063bSNico Weber     }
423cc89063bSNico Weber 
is_min_aligned(void * p)424cc89063bSNico Weber     static bool is_min_aligned(void* p) {
425cc89063bSNico Weber         if (alignof(T) == BlockSize) {
426cc89063bSNico Weber             return is_max_aligned(p);
427cc89063bSNico Weber         } else {
428cc89063bSNico Weber             return reinterpret_cast<std::uintptr_t>(p) % BlockSize == alignof(T);
429cc89063bSNico Weber         }
430cc89063bSNico Weber     }
431cc89063bSNico Weber 
432cc89063bSNico Weber     template <class Tp> friend class MinAlignedAllocator;
433cc89063bSNico Weber     mutable AllocController *P;
434cc89063bSNico Weber };
435cc89063bSNico Weber 
436cc89063bSNico Weber 
437cc89063bSNico Weber template <class T, class U>
438cc89063bSNico Weber inline bool operator==(MinAlignedAllocator<T> const& x,
439cc89063bSNico Weber                        MinAlignedAllocator<U> const& y) {
440cc89063bSNico Weber     return &x.getController() == &y.getController();
441cc89063bSNico Weber }
442cc89063bSNico Weber 
443cc89063bSNico Weber template <class T, class U>
444cc89063bSNico Weber inline bool operator!=(MinAlignedAllocator<T> const& x,
445cc89063bSNico Weber                        MinAlignedAllocator<U> const& y) {
446cc89063bSNico Weber     return !(x == y);
447cc89063bSNico Weber }
448cc89063bSNico Weber 
449cc89063bSNico Weber template <class T>
450cc89063bSNico Weber class NullAllocator
451cc89063bSNico Weber {
452cc89063bSNico Weber public:
453cc89063bSNico Weber     typedef T value_type;
454cc89063bSNico Weber     typedef T* pointer;
455cc89063bSNico Weber     NullAllocator() = delete;
NullAllocator(AllocController & PP)456cc89063bSNico Weber     explicit NullAllocator(AllocController& PP) : P(&PP) {}
457cc89063bSNico Weber 
NullAllocator(NullAllocator const & other)458cc89063bSNico Weber     NullAllocator(NullAllocator const& other) : P(other.P) {
459cc89063bSNico Weber         P->copy_constructed += 1;
460cc89063bSNico Weber     }
461cc89063bSNico Weber 
NullAllocator(NullAllocator && other)462cc89063bSNico Weber     NullAllocator(NullAllocator&& other) : P(other.P) {
463cc89063bSNico Weber         P->move_constructed += 1;
464cc89063bSNico Weber     }
465cc89063bSNico Weber 
466cc89063bSNico Weber     template <class U>
NullAllocator(NullAllocator<U> const & other)467cc89063bSNico Weber     NullAllocator(NullAllocator<U> const& other) TEST_NOEXCEPT : P(other.P) {
468cc89063bSNico Weber         P->copy_constructed += 1;
469cc89063bSNico Weber     }
470cc89063bSNico Weber 
471cc89063bSNico Weber     template <class U>
NullAllocator(NullAllocator<U> && other)472cc89063bSNico Weber     NullAllocator(NullAllocator<U>&& other) TEST_NOEXCEPT : P(other.P) {
473cc89063bSNico Weber         P->move_constructed += 1;
474cc89063bSNico Weber     }
475cc89063bSNico Weber 
allocate(std::size_t n)476cc89063bSNico Weber     T* allocate(std::size_t n)
477cc89063bSNico Weber     {
478cc89063bSNico Weber         P->countAlloc(nullptr, n*sizeof(T), alignof(T));
479cc89063bSNico Weber         return nullptr;
480cc89063bSNico Weber     }
481cc89063bSNico Weber 
deallocate(T * p,std::size_t n)482cc89063bSNico Weber     void deallocate(T* p, std::size_t n)
483cc89063bSNico Weber     {
484cc89063bSNico Weber         void* vp = static_cast<void*>(p);
485cc89063bSNico Weber         P->countDealloc(vp, n*sizeof(T), alignof(T));
486cc89063bSNico Weber     }
487cc89063bSNico Weber 
getController()488cc89063bSNico Weber     AllocController& getController() const { return *P; }
489cc89063bSNico Weber 
490cc89063bSNico Weber private:
491cc89063bSNico Weber     template <class Tp> friend class NullAllocator;
492cc89063bSNico Weber     AllocController *P;
493cc89063bSNico Weber };
494cc89063bSNico Weber 
495cc89063bSNico Weber template <class T, class U>
496cc89063bSNico Weber inline bool operator==(NullAllocator<T> const& x,
497cc89063bSNico Weber                        NullAllocator<U> const& y) {
498cc89063bSNico Weber     return &x.getController() == &y.getController();
499cc89063bSNico Weber }
500cc89063bSNico Weber 
501cc89063bSNico Weber template <class T, class U>
502cc89063bSNico Weber inline bool operator!=(NullAllocator<T> const& x,
503cc89063bSNico Weber                        NullAllocator<U> const& y) {
504cc89063bSNico Weber     return !(x == y);
505cc89063bSNico Weber }
506cc89063bSNico Weber 
507cc89063bSNico Weber 
508cc89063bSNico Weber #endif /* SUPPORT_CONTROLLED_ALLOCATORS_H */
509