xref: /llvm-project/libcxx/test/support/min_allocator.h (revision 71315698c91d0cda054b903da0594ca6f072c350)
1 //===----------------------------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef MIN_ALLOCATOR_H
10 #define MIN_ALLOCATOR_H
11 
12 #include <cassert>
13 #include <climits>
14 #include <cstddef>
15 #include <cstdlib>
16 #include <iterator>
17 #include <memory>
18 #include <new>
19 #include <type_traits>
20 #include <cstring>
21 
22 #include "test_macros.h"
23 
24 template <class T>
25 class bare_allocator
26 {
27 public:
28     typedef T value_type;
29 
30     bare_allocator() TEST_NOEXCEPT {}
31 
32     template <class U>
33     bare_allocator(bare_allocator<U>) TEST_NOEXCEPT {}
34 
35     T* allocate(std::size_t n)
36     {
37         return static_cast<T*>(::operator new(n*sizeof(T)));
38     }
39 
40     void deallocate(T* p, std::size_t)
41     {
42         return ::operator delete(static_cast<void*>(p));
43     }
44 
45     friend bool operator==(bare_allocator, bare_allocator) {return true;}
46     friend bool operator!=(bare_allocator x, bare_allocator y) {return !(x == y);}
47 };
48 
49 
50 template <class T>
51 class no_default_allocator
52 {
53 #if TEST_STD_VER >= 11
54     no_default_allocator() = delete;
55 #else
56     no_default_allocator();
57 #endif
58     struct construct_tag {};
59     explicit no_default_allocator(construct_tag) {}
60 
61 public:
62     static no_default_allocator create() {
63       construct_tag tag;
64       return no_default_allocator(tag);
65     }
66 
67 public:
68     typedef T value_type;
69 
70     template <class U>
71     no_default_allocator(no_default_allocator<U>) TEST_NOEXCEPT {}
72 
73     T* allocate(std::size_t n)
74     {
75         return static_cast<T*>(::operator new(n*sizeof(T)));
76     }
77 
78     void deallocate(T* p, std::size_t)
79     {
80         return ::operator delete(static_cast<void*>(p));
81     }
82 
83     friend bool operator==(no_default_allocator, no_default_allocator) {return true;}
84     friend bool operator!=(no_default_allocator x, no_default_allocator y) {return !(x == y);}
85 };
86 
87 struct malloc_allocator_base {
88     static std::size_t outstanding_bytes;
89     static std::size_t alloc_count;
90     static std::size_t dealloc_count;
91     static bool disable_default_constructor;
92 
93     static std::size_t outstanding_alloc() {
94       assert(alloc_count >= dealloc_count);
95       return (alloc_count - dealloc_count);
96     }
97 
98     static void reset() {
99         assert(outstanding_alloc() == 0);
100         disable_default_constructor = false;
101         outstanding_bytes = 0;
102         alloc_count = 0;
103         dealloc_count = 0;
104     }
105 };
106 
107 size_t malloc_allocator_base::outstanding_bytes = 0;
108 size_t malloc_allocator_base::alloc_count = 0;
109 size_t malloc_allocator_base::dealloc_count = 0;
110 bool malloc_allocator_base::disable_default_constructor = false;
111 
112 
113 template <class T>
114 class malloc_allocator : public malloc_allocator_base
115 {
116 public:
117     typedef T value_type;
118 
119     malloc_allocator() TEST_NOEXCEPT { assert(!disable_default_constructor); }
120 
121     template <class U>
122     malloc_allocator(malloc_allocator<U>) TEST_NOEXCEPT {}
123 
124     T* allocate(std::size_t n)
125     {
126         const std::size_t nbytes = n*sizeof(T);
127         ++alloc_count;
128         outstanding_bytes += nbytes;
129         return static_cast<T*>(std::malloc(nbytes));
130     }
131 
132     void deallocate(T* p, std::size_t n)
133     {
134         const std::size_t nbytes = n*sizeof(T);
135         ++dealloc_count;
136         outstanding_bytes -= nbytes;
137         std::free(static_cast<void*>(p));
138     }
139 
140     friend bool operator==(malloc_allocator, malloc_allocator) {return true;}
141     friend bool operator!=(malloc_allocator x, malloc_allocator y) {return !(x == y);}
142 };
143 
144 template <class T>
145 struct cpp03_allocator : bare_allocator<T>
146 {
147     typedef T value_type;
148     typedef value_type* pointer;
149 
150     static bool construct_called;
151 
152     // Returned value is not used but it's not prohibited.
153     pointer construct(pointer p, const value_type& val)
154     {
155         ::new(p) value_type(val);
156         construct_called = true;
157         return p;
158     }
159 
160     std::size_t max_size() const
161     {
162         return UINT_MAX / sizeof(T);
163     }
164 };
165 template <class T> bool cpp03_allocator<T>::construct_called = false;
166 
167 template <class T>
168 struct cpp03_overload_allocator : bare_allocator<T>
169 {
170     typedef T value_type;
171     typedef value_type* pointer;
172 
173     static bool construct_called;
174 
175     void construct(pointer p, const value_type& val)
176     {
177         construct(p, val, std::is_class<T>());
178     }
179     void construct(pointer p, const value_type& val, std::true_type)
180     {
181         ::new(p) value_type(val);
182         construct_called = true;
183     }
184     void construct(pointer p, const value_type& val, std::false_type)
185     {
186         ::new(p) value_type(val);
187         construct_called = true;
188     }
189 
190     std::size_t max_size() const
191     {
192         return UINT_MAX / sizeof(T);
193     }
194 };
195 template <class T> bool cpp03_overload_allocator<T>::construct_called = false;
196 
197 template <class T, class = std::integral_constant<std::size_t, 0> > class min_pointer;
198 template <class T, class ID> class min_pointer<const T, ID>;
199 template <class ID> class min_pointer<void, ID>;
200 template <class ID> class min_pointer<const void, ID>;
201 template <class T> class min_allocator;
202 
203 template <class ID>
204 class min_pointer<const void, ID>
205 {
206     const void* ptr_;
207 public:
208     min_pointer() TEST_NOEXCEPT = default;
209     min_pointer(std::nullptr_t) TEST_NOEXCEPT : ptr_(nullptr) {}
210     template <class T>
211     min_pointer(min_pointer<T, ID> p) TEST_NOEXCEPT : ptr_(p.ptr_) {}
212 
213     explicit operator bool() const {return ptr_ != nullptr;}
214 
215     friend bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;}
216     friend bool operator!=(min_pointer x, min_pointer y) {return !(x == y);}
217     template <class U, class XID> friend class min_pointer;
218 };
219 
220 template <class ID>
221 class min_pointer<void, ID>
222 {
223     void* ptr_;
224 public:
225     min_pointer() TEST_NOEXCEPT = default;
226     TEST_CONSTEXPR_CXX14 min_pointer(std::nullptr_t) TEST_NOEXCEPT : ptr_(nullptr) {}
227     template <class T,
228               class = typename std::enable_if
229                        <
230                             !std::is_const<T>::value
231                        >::type
232              >
233     TEST_CONSTEXPR_CXX14 min_pointer(min_pointer<T, ID> p) TEST_NOEXCEPT : ptr_(p.ptr_) {}
234 
235     TEST_CONSTEXPR_CXX14 explicit operator bool() const {return ptr_ != nullptr;}
236 
237     TEST_CONSTEXPR_CXX14 friend bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;}
238     TEST_CONSTEXPR_CXX14 friend bool operator!=(min_pointer x, min_pointer y) {return !(x == y);}
239     template <class U, class XID> friend class min_pointer;
240 };
241 
242 template <class T, class ID>
243 class min_pointer
244 {
245     T* ptr_;
246 
247     TEST_CONSTEXPR_CXX14 explicit min_pointer(T* p) TEST_NOEXCEPT : ptr_(p) {}
248 public:
249     min_pointer() TEST_NOEXCEPT = default;
250     TEST_CONSTEXPR_CXX14 min_pointer(std::nullptr_t) TEST_NOEXCEPT : ptr_(nullptr) {}
251     TEST_CONSTEXPR_CXX14 explicit min_pointer(min_pointer<void, ID> p) TEST_NOEXCEPT : ptr_(static_cast<T*>(p.ptr_)) {}
252 
253     TEST_CONSTEXPR_CXX14 explicit operator bool() const {return ptr_ != nullptr;}
254 
255     typedef std::ptrdiff_t difference_type;
256     typedef T& reference;
257     typedef T* pointer;
258     typedef T value_type;
259     typedef std::random_access_iterator_tag iterator_category;
260 
261     TEST_CONSTEXPR_CXX14 reference operator*() const {return *ptr_;}
262     TEST_CONSTEXPR_CXX14 pointer operator->() const {return ptr_;}
263 
264     TEST_CONSTEXPR_CXX14 min_pointer& operator++() {++ptr_; return *this;}
265     TEST_CONSTEXPR_CXX14 min_pointer operator++(int) {min_pointer tmp(*this); ++ptr_; return tmp;}
266 
267     TEST_CONSTEXPR_CXX14 min_pointer& operator--() {--ptr_; return *this;}
268     TEST_CONSTEXPR_CXX14 min_pointer operator--(int) {min_pointer tmp(*this); --ptr_; return tmp;}
269 
270     TEST_CONSTEXPR_CXX14 min_pointer& operator+=(difference_type n) {ptr_ += n; return *this;}
271     TEST_CONSTEXPR_CXX14 min_pointer& operator-=(difference_type n) {ptr_ -= n; return *this;}
272 
273     TEST_CONSTEXPR_CXX14 min_pointer operator+(difference_type n) const
274     {
275         min_pointer tmp(*this);
276         tmp += n;
277         return tmp;
278     }
279 
280     friend TEST_CONSTEXPR_CXX14 min_pointer operator+(difference_type n, min_pointer x)
281     {
282         return x + n;
283     }
284 
285     TEST_CONSTEXPR_CXX14 min_pointer operator-(difference_type n) const
286     {
287         min_pointer tmp(*this);
288         tmp -= n;
289         return tmp;
290     }
291 
292     friend TEST_CONSTEXPR_CXX14 difference_type operator-(min_pointer x, min_pointer y)
293     {
294         return x.ptr_ - y.ptr_;
295     }
296 
297     TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return ptr_[n];}
298 
299     friend TEST_CONSTEXPR_CXX14 bool operator< (min_pointer x, min_pointer y) {return x.ptr_ < y.ptr_;}
300     friend TEST_CONSTEXPR_CXX14 bool operator> (min_pointer x, min_pointer y) {return y < x;}
301     friend TEST_CONSTEXPR_CXX14 bool operator<=(min_pointer x, min_pointer y) {return !(y < x);}
302     friend TEST_CONSTEXPR_CXX14 bool operator>=(min_pointer x, min_pointer y) {return !(x < y);}
303 
304     static TEST_CONSTEXPR_CXX14 min_pointer pointer_to(T& t) {return min_pointer(std::addressof(t));}
305 
306     friend TEST_CONSTEXPR_CXX14 bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;}
307     friend TEST_CONSTEXPR_CXX14 bool operator!=(min_pointer x, min_pointer y) {return !(x == y);}
308     template <class U, class XID> friend class min_pointer;
309     template <class U> friend class min_allocator;
310 };
311 
312 template <class T, class ID>
313 class min_pointer<const T, ID>
314 {
315     const T* ptr_;
316 
317     TEST_CONSTEXPR_CXX14 explicit min_pointer(const T* p) : ptr_(p) {}
318 public:
319     min_pointer() TEST_NOEXCEPT = default;
320     TEST_CONSTEXPR_CXX14 min_pointer(std::nullptr_t) : ptr_(nullptr) {}
321     TEST_CONSTEXPR_CXX14 min_pointer(min_pointer<T, ID> p) : ptr_(p.ptr_) {}
322     TEST_CONSTEXPR_CXX14 explicit min_pointer(min_pointer<const void, ID> p) : ptr_(static_cast<const T*>(p.ptr_)) {}
323 
324     TEST_CONSTEXPR_CXX14 explicit operator bool() const {return ptr_ != nullptr;}
325 
326     typedef std::ptrdiff_t difference_type;
327     typedef const T& reference;
328     typedef const T* pointer;
329     typedef const T value_type;
330     typedef std::random_access_iterator_tag iterator_category;
331 
332     TEST_CONSTEXPR_CXX14 reference operator*() const {return *ptr_;}
333     TEST_CONSTEXPR_CXX14 pointer operator->() const {return ptr_;}
334 
335     TEST_CONSTEXPR_CXX14 min_pointer& operator++() {++ptr_; return *this;}
336     TEST_CONSTEXPR_CXX14 min_pointer operator++(int) {min_pointer tmp(*this); ++ptr_; return tmp;}
337 
338     TEST_CONSTEXPR_CXX14 min_pointer& operator--() {--ptr_; return *this;}
339     TEST_CONSTEXPR_CXX14 min_pointer operator--(int) {min_pointer tmp(*this); --ptr_; return tmp;}
340 
341     TEST_CONSTEXPR_CXX14 min_pointer& operator+=(difference_type n) {ptr_ += n; return *this;}
342     TEST_CONSTEXPR_CXX14 min_pointer& operator-=(difference_type n) {ptr_ -= n; return *this;}
343 
344     TEST_CONSTEXPR_CXX14 min_pointer operator+(difference_type n) const
345     {
346         min_pointer tmp(*this);
347         tmp += n;
348         return tmp;
349     }
350 
351     friend TEST_CONSTEXPR_CXX14 min_pointer operator+(difference_type n, min_pointer x)
352     {
353         return x + n;
354     }
355 
356     TEST_CONSTEXPR_CXX14 min_pointer operator-(difference_type n) const
357     {
358         min_pointer tmp(*this);
359         tmp -= n;
360         return tmp;
361     }
362 
363     friend TEST_CONSTEXPR_CXX14 difference_type operator-(min_pointer x, min_pointer y)
364     {
365         return x.ptr_ - y.ptr_;
366     }
367 
368     TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return ptr_[n];}
369 
370     friend TEST_CONSTEXPR_CXX14 bool operator< (min_pointer x, min_pointer y) {return x.ptr_ < y.ptr_;}
371     friend TEST_CONSTEXPR_CXX14 bool operator> (min_pointer x, min_pointer y) {return y < x;}
372     friend TEST_CONSTEXPR_CXX14 bool operator<=(min_pointer x, min_pointer y) {return !(y < x);}
373     friend TEST_CONSTEXPR_CXX14 bool operator>=(min_pointer x, min_pointer y) {return !(x < y);}
374 
375     static TEST_CONSTEXPR_CXX14 min_pointer pointer_to(const T& t) {return min_pointer(std::addressof(t));}
376 
377     friend TEST_CONSTEXPR_CXX14 bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;}
378     friend TEST_CONSTEXPR_CXX14 bool operator!=(min_pointer x, min_pointer y) {return x.ptr_ != y.ptr_;}
379     friend TEST_CONSTEXPR_CXX14 bool operator==(min_pointer x, std::nullptr_t) {return x.ptr_ == nullptr;}
380     friend TEST_CONSTEXPR_CXX14 bool operator!=(min_pointer x, std::nullptr_t) {return x.ptr_ != nullptr;}
381     friend TEST_CONSTEXPR_CXX14 bool operator==(std::nullptr_t, min_pointer x) {return x.ptr_ == nullptr;}
382     friend TEST_CONSTEXPR_CXX14 bool operator!=(std::nullptr_t, min_pointer x) {return x.ptr_ != nullptr;}
383     template <class U, class XID> friend class min_pointer;
384 };
385 
386 template <class T>
387 class min_allocator
388 {
389 public:
390     typedef T value_type;
391     typedef min_pointer<T> pointer;
392 
393     min_allocator() = default;
394     template <class U>
395     TEST_CONSTEXPR_CXX20 min_allocator(min_allocator<U>) {}
396 
397     TEST_CONSTEXPR_CXX20 pointer allocate(std::ptrdiff_t n)
398     {
399         return pointer(std::allocator<T>().allocate(n));
400     }
401 
402     TEST_CONSTEXPR_CXX20 void deallocate(pointer p, std::ptrdiff_t n)
403     {
404         std::allocator<T>().deallocate(p.ptr_, n);
405     }
406 
407     TEST_CONSTEXPR_CXX20 friend bool operator==(min_allocator, min_allocator) {return true;}
408     TEST_CONSTEXPR_CXX20 friend bool operator!=(min_allocator x, min_allocator y) {return !(x == y);}
409 };
410 
411 template <class T>
412 class explicit_allocator
413 {
414 public:
415     typedef T value_type;
416 
417     TEST_CONSTEXPR_CXX20 explicit_allocator() TEST_NOEXCEPT {}
418 
419     template <class U>
420     TEST_CONSTEXPR_CXX20 explicit explicit_allocator(explicit_allocator<U>) TEST_NOEXCEPT {}
421 
422     TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n)
423     {
424         return static_cast<T*>(std::allocator<T>().allocate(n));
425     }
426 
427     TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n)
428     {
429         std::allocator<T>().deallocate(p, n);
430     }
431 
432     TEST_CONSTEXPR_CXX20 friend bool operator==(explicit_allocator, explicit_allocator) {return true;}
433     TEST_CONSTEXPR_CXX20 friend bool operator!=(explicit_allocator x, explicit_allocator y) {return !(x == y);}
434 };
435 
436 template <class T>
437 class unaligned_allocator {
438 public:
439   static_assert(TEST_ALIGNOF(T) == 1, "Type T cannot be created on unaligned address (UB)");
440   typedef T value_type;
441 
442   TEST_CONSTEXPR_CXX20 unaligned_allocator() TEST_NOEXCEPT {}
443 
444   template <class U>
445   TEST_CONSTEXPR_CXX20 explicit unaligned_allocator(unaligned_allocator<U>) TEST_NOEXCEPT {}
446 
447   TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return std::allocator<T>().allocate(n + 1) + 1; }
448 
449   TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { std::allocator<T>().deallocate(p - 1, n + 1); }
450 
451   TEST_CONSTEXPR_CXX20 friend bool operator==(unaligned_allocator, unaligned_allocator) { return true; }
452   TEST_CONSTEXPR_CXX20 friend bool operator!=(unaligned_allocator x, unaligned_allocator y) { return !(x == y); }
453 };
454 
455 template <class T>
456 class safe_allocator {
457 public:
458   typedef T value_type;
459 
460   TEST_CONSTEXPR_CXX20 safe_allocator() TEST_NOEXCEPT {}
461 
462   template <class U>
463   TEST_CONSTEXPR_CXX20 safe_allocator(safe_allocator<U>) TEST_NOEXCEPT {}
464 
465   TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) {
466     T* memory = std::allocator<T>().allocate(n);
467     if (!TEST_IS_CONSTANT_EVALUATED)
468       std::memset(static_cast<void*>(memory), 0, sizeof(T) * n);
469 
470     return memory;
471   }
472 
473   TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) {
474     if (!TEST_IS_CONSTANT_EVALUATED)
475       DoNotOptimize(std::memset(static_cast<void*>(p), 0, sizeof(T) * n));
476     std::allocator<T>().deallocate(p, n);
477   }
478 
479   TEST_CONSTEXPR_CXX20 friend bool operator==(safe_allocator, safe_allocator) { return true; }
480   TEST_CONSTEXPR_CXX20 friend bool operator!=(safe_allocator x, safe_allocator y) { return !(x == y); }
481 };
482 
483 #endif // MIN_ALLOCATOR_H
484