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 TEST_ALLOCATOR_H
10 #define TEST_ALLOCATOR_H
12 #include <type_traits>
21 #include "test_macros.h"
23 template <class Alloc
>
24 inline typename
std::allocator_traits
<Alloc
>::size_type
25 alloc_max_size(Alloc
const &a
) {
26 typedef std::allocator_traits
<Alloc
> AT
;
27 return AT::max_size(a
);
33 static int time_to_throw
;
35 static int throw_after
;
37 static int alloc_count
;
42 const static int destructed_value
= -1;
43 const static int default_value
= 0;
44 const static int moved_value
= INT_MAX
;
47 assert(count
== 0 && "clearing leaking allocator data?");
51 throw_after
= INT_MAX
;
52 clear_ctor_counters();
55 static void clear_ctor_counters() {
62 int test_alloc_base::count
= 0;
63 int test_alloc_base::time_to_throw
= 0;
64 int test_alloc_base::alloc_count
= 0;
65 int test_alloc_base::throw_after
= INT_MAX
;
66 int test_alloc_base::copied
= 0;
67 int test_alloc_base::moved
= 0;
68 int test_alloc_base::converted
= 0;
72 : public test_alloc_base
74 int data_
; // participates in equality
75 int id_
; // unique identifier, doesn't participate in equality
76 template <class U
> friend class test_allocator
;
79 typedef unsigned size_type
;
80 typedef int difference_type
;
82 typedef value_type
* pointer
;
83 typedef const value_type
* const_pointer
;
84 typedef typename
std::add_lvalue_reference
<value_type
>::type reference
;
85 typedef typename
std::add_lvalue_reference
<const value_type
>::type const_reference
;
87 template <class U
> struct rebind
{typedef test_allocator
<U
> other
;};
89 test_allocator() TEST_NOEXCEPT
: data_(0), id_(0) {++count
;}
90 explicit test_allocator(int i
, int id
= 0) TEST_NOEXCEPT
: data_(i
), id_(id
)
92 test_allocator(const test_allocator
& a
) TEST_NOEXCEPT
: data_(a
.data_
),
96 assert(a
.data_
!= destructed_value
&& a
.id_
!= destructed_value
&&
97 "copying from destroyed allocator");
99 #if TEST_STD_VER >= 11
100 test_allocator(test_allocator
&& a
) TEST_NOEXCEPT
: data_(a
.data_
),
104 assert(a
.data_
!= destructed_value
&& a
.id_
!= destructed_value
&&
105 "moving from destroyed allocator");
106 a
.data_
= moved_value
;
111 test_allocator(const test_allocator
<U
>& a
) TEST_NOEXCEPT
: data_(a
.data_
),
116 ~test_allocator() TEST_NOEXCEPT
{
117 assert(data_
>= 0); assert(id_
>= 0);
119 data_
= destructed_value
;
120 id_
= destructed_value
;
122 pointer
address(reference x
) const {return &x
;}
123 const_pointer
address(const_reference x
) const {return &x
;}
124 pointer
allocate(size_type n
, const void* = 0)
127 if (time_to_throw
>= throw_after
) {
128 #ifndef TEST_HAS_NO_EXCEPTIONS
129 throw std::bad_alloc();
136 return (pointer
)::operator new(n
* sizeof(T
));
138 void deallocate(pointer p
, size_type
)
139 {assert(data_
>= 0); --alloc_count
; ::operator delete((void*)p
);}
140 size_type
max_size() const TEST_NOEXCEPT
141 {return UINT_MAX
/ sizeof(T
);}
142 #if TEST_STD_VER < 11
143 void construct(pointer p
, const T
& val
)
144 {::new(static_cast<void*>(p
)) T(val
);}
146 template <class U
> void construct(pointer p
, U
&& val
)
147 {::new(static_cast<void*>(p
)) T(std::forward
<U
>(val
));}
149 void destroy(pointer p
)
151 friend bool operator==(const test_allocator
& x
, const test_allocator
& y
)
152 {return x
.data_
== y
.data_
;}
153 friend bool operator!=(const test_allocator
& x
, const test_allocator
& y
)
156 int get_data() const { return data_
; }
157 int get_id() const { return id_
; }
161 class non_default_test_allocator
162 : public test_alloc_base
166 template <class U
> friend class non_default_test_allocator
;
169 typedef unsigned size_type
;
170 typedef int difference_type
;
171 typedef T value_type
;
172 typedef value_type
* pointer
;
173 typedef const value_type
* const_pointer
;
174 typedef typename
std::add_lvalue_reference
<value_type
>::type reference
;
175 typedef typename
std::add_lvalue_reference
<const value_type
>::type const_reference
;
177 template <class U
> struct rebind
{typedef non_default_test_allocator
<U
> other
;};
179 // non_default_test_allocator() TEST_NOEXCEPT : data_(0) {++count;}
180 explicit non_default_test_allocator(int i
) TEST_NOEXCEPT
: data_(i
) {++count
;}
181 non_default_test_allocator(const non_default_test_allocator
& a
) TEST_NOEXCEPT
182 : data_(a
.data_
) {++count
;}
183 template <class U
> non_default_test_allocator(const non_default_test_allocator
<U
>& a
) TEST_NOEXCEPT
184 : data_(a
.data_
) {++count
;}
185 ~non_default_test_allocator() TEST_NOEXCEPT
{assert(data_
>= 0); --count
; data_
= -1;}
186 pointer
address(reference x
) const {return &x
;}
187 const_pointer
address(const_reference x
) const {return &x
;}
188 pointer
allocate(size_type n
, const void* = 0)
191 if (time_to_throw
>= throw_after
) {
192 #ifndef TEST_HAS_NO_EXCEPTIONS
193 throw std::bad_alloc();
200 return (pointer
)::operator new (n
* sizeof(T
));
202 void deallocate(pointer p
, size_type
)
203 {assert(data_
>= 0); --alloc_count
; ::operator delete((void*)p
); }
204 size_type
max_size() const TEST_NOEXCEPT
205 {return UINT_MAX
/ sizeof(T
);}
206 #if TEST_STD_VER < 11
207 void construct(pointer p
, const T
& val
)
208 {::new(static_cast<void*>(p
)) T(val
);}
210 template <class U
> void construct(pointer p
, U
&& val
)
211 {::new(static_cast<void*>(p
)) T(std::forward
<U
>(val
));}
213 void destroy(pointer p
) {p
->~T();}
215 friend bool operator==(const non_default_test_allocator
& x
, const non_default_test_allocator
& y
)
216 {return x
.data_
== y
.data_
;}
217 friend bool operator!=(const non_default_test_allocator
& x
, const non_default_test_allocator
& y
)
222 class test_allocator
<void>
223 : public test_alloc_base
228 template <class U
> friend class test_allocator
;
231 typedef unsigned size_type
;
232 typedef int difference_type
;
233 typedef void value_type
;
234 typedef value_type
* pointer
;
235 typedef const value_type
* const_pointer
;
237 template <class U
> struct rebind
{typedef test_allocator
<U
> other
;};
239 test_allocator() TEST_NOEXCEPT
: data_(0), id_(0) {}
240 explicit test_allocator(int i
, int id
= 0) TEST_NOEXCEPT
: data_(i
), id_(id
) {}
241 test_allocator(const test_allocator
& a
) TEST_NOEXCEPT
242 : data_(a
.data_
), id_(a
.id_
) {}
243 template <class U
> test_allocator(const test_allocator
<U
>& a
) TEST_NOEXCEPT
244 : data_(a
.data_
), id_(a
.id_
) {}
245 ~test_allocator() TEST_NOEXCEPT
{data_
= -1; id_
= -1; }
247 int get_id() const { return id_
; }
248 int get_data() const { return data_
; }
250 friend bool operator==(const test_allocator
& x
, const test_allocator
& y
)
251 {return x
.data_
== y
.data_
;}
252 friend bool operator!=(const test_allocator
& x
, const test_allocator
& y
)
257 class other_allocator
261 template <class U
> friend class other_allocator
;
264 typedef T value_type
;
266 other_allocator() : data_(-1) {}
267 explicit other_allocator(int i
) : data_(i
) {}
268 template <class U
> other_allocator(const other_allocator
<U
>& a
)
270 T
* allocate(std::size_t n
)
271 {return (T
*)::operator new(n
* sizeof(T
));}
272 void deallocate(T
* p
, std::size_t)
273 {::operator delete((void*)p
);}
275 other_allocator
select_on_container_copy_construction() const
276 {return other_allocator(-2);}
278 friend bool operator==(const other_allocator
& x
, const other_allocator
& y
)
279 {return x
.data_
== y
.data_
;}
280 friend bool operator!=(const other_allocator
& x
, const other_allocator
& y
)
283 typedef std::true_type propagate_on_container_copy_assignment
;
284 typedef std::true_type propagate_on_container_move_assignment
;
285 typedef std::true_type propagate_on_container_swap
;
287 #if TEST_STD_VER < 11
288 std::size_t max_size() const
289 {return UINT_MAX
/ sizeof(T
);}
294 #if TEST_STD_VER >= 11
298 template <typename T
> class TaggingAllocator
;
301 // All constructors must be passed the Tag type.
303 // DefaultInsertable into vector<X, TaggingAllocator<X>>,
305 // CopyInsertable into vector<X, TaggingAllocator<X>>,
306 Tag_X(Ctor_Tag
, const Tag_X
&) {}
307 // MoveInsertable into vector<X, TaggingAllocator<X>>, and
308 Tag_X(Ctor_Tag
, Tag_X
&&) {}
310 // EmplaceConstructible into vector<X, TaggingAllocator<X>> from args.
311 template<typename
... Args
>
312 Tag_X(Ctor_Tag
, Args
&&...) { }
314 // not DefaultConstructible, CopyConstructible or MoveConstructible.
316 Tag_X(const Tag_X
&) = delete;
317 Tag_X(Tag_X
&&) = delete;
320 Tag_X
& operator=(const Tag_X
&) { return *this; }
323 Tag_X
& operator=(Tag_X
&&) { return *this; }
329 // Erasable from vector<X, TaggingAllocator<X>>.
330 friend class TaggingAllocator
<Tag_X
>;
335 class TaggingAllocator
{
337 using value_type
= T
;
338 TaggingAllocator() = default;
341 TaggingAllocator(const TaggingAllocator
<U
>&) { }
343 T
* allocate(std::size_t n
) { return std::allocator
<T
>{}.allocate(n
); }
345 void deallocate(T
* p
, std::size_t n
) { std::allocator
<T
>{}.deallocate(p
, n
); }
347 template<typename
... Args
>
348 void construct(Tag_X
* p
, Args
&&... args
)
349 { ::new((void*)p
) Tag_X(Ctor_Tag
{}, std::forward
<Args
>(args
)...); }
351 template<typename U
, typename
... Args
>
352 void construct(U
* p
, Args
&&... args
)
353 { ::new((void*)p
) U(std::forward
<Args
>(args
)...); }
355 template<typename U
, typename
... Args
>
360 template<typename T
, typename U
>
362 operator==(const TaggingAllocator
<T
>&, const TaggingAllocator
<U
>&)
365 template<typename T
, typename U
>
367 operator!=(const TaggingAllocator
<T
>&, const TaggingAllocator
<U
>&)
371 template <std::size_t MaxAllocs
>
372 struct limited_alloc_handle
{
373 std::size_t outstanding_
;
376 limited_alloc_handle() : outstanding_(0), last_alloc_(nullptr) {}
379 T
*allocate(std::size_t N
) {
380 if (N
+ outstanding_
> MaxAllocs
)
381 TEST_THROW(std::bad_alloc());
382 last_alloc_
= ::operator new(N
*sizeof(T
));
384 return static_cast<T
*>(last_alloc_
);
387 void deallocate(void* ptr
, std::size_t N
) {
388 if (ptr
== last_alloc_
) {
389 last_alloc_
= nullptr;
390 assert(outstanding_
>= N
);
393 ::operator delete(ptr
);
397 template <class T
, std::size_t N
>
398 class limited_allocator
400 template <class U
, std::size_t UN
> friend class limited_allocator
;
401 typedef limited_alloc_handle
<N
> BuffT
;
402 std::shared_ptr
<BuffT
> handle_
;
404 typedef T value_type
;
405 typedef value_type
* pointer
;
406 typedef const value_type
* const_pointer
;
407 typedef value_type
& reference
;
408 typedef const value_type
& const_reference
;
409 typedef std::size_t size_type
;
410 typedef std::ptrdiff_t difference_type
;
412 template <class U
> struct rebind
{ typedef limited_allocator
<U
, N
> other
; };
414 limited_allocator() : handle_(new BuffT
) {}
416 limited_allocator(limited_allocator
const& other
) : handle_(other
.handle_
) {}
419 explicit limited_allocator(limited_allocator
<U
, N
> const& other
)
420 : handle_(other
.handle_
) {}
423 limited_allocator
& operator=(const limited_allocator
&);// = delete;
426 pointer
allocate(size_type n
) { return handle_
->template allocate
<T
>(n
); }
427 void deallocate(pointer p
, size_type n
) { handle_
->deallocate(p
, n
); }
428 size_type
max_size() const {return N
;}
430 BuffT
* getHandle() const { return handle_
.get(); }
433 template <class T
, class U
, std::size_t N
>
434 inline bool operator==(limited_allocator
<T
, N
> const& LHS
,
435 limited_allocator
<U
, N
> const& RHS
) {
436 return LHS
.getHandle() == RHS
.getHandle();
439 template <class T
, class U
, std::size_t N
>
440 inline bool operator!=(limited_allocator
<T
, N
> const& LHS
,
441 limited_allocator
<U
, N
> const& RHS
) {
442 return !(LHS
== RHS
);
446 #endif // TEST_ALLOCATOR_H