2 // Testing allocator for the C++ library testsuite.
4 // Copyright (C) 2002-2014 Free Software Foundation, Inc.
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License along
18 // with this library; see the file COPYING3. If not see
19 // <http://www.gnu.org/licenses/>.
22 // This file provides an test instrumentation allocator that can be
23 // used to verify allocation functionality of standard library
24 // containers. 2002.11.25 smw
26 #ifndef _GLIBCXX_TESTSUITE_ALLOCATOR_H
27 #define _GLIBCXX_TESTSUITE_ALLOCATOR_H
29 #include <tr1/unordered_map>
30 #include <bits/move.h>
31 #include <ext/pointer.h>
32 #include <testsuite_hooks.h>
36 class tracker_allocator_counter
39 typedef std::size_t size_type
;
42 allocate(size_type blocksize
)
44 void* p
= ::operator new(blocksize
);
45 allocationCount_
+= blocksize
;
50 construct() { constructCount_
++; }
53 destroy() { destructCount_
++; }
56 deallocate(void* p
, size_type blocksize
)
59 deallocationCount_
+= blocksize
;
63 get_allocation_count() { return allocationCount_
; }
66 get_deallocation_count() { return deallocationCount_
; }
69 get_construct_count() { return constructCount_
; }
72 get_destruct_count() { return destructCount_
; }
78 deallocationCount_
= 0;
84 static size_type allocationCount_
;
85 static size_type deallocationCount_
;
86 static int constructCount_
;
87 static int destructCount_
;
90 // A simple basic allocator that just forwards to the
91 // tracker_allocator_counter to fulfill memory requests. This class
92 // is templated on the target object type, but tracker isn't.
94 class tracker_allocator
97 typedef tracker_allocator_counter counter_type
;
100 typedef T value_type
;
102 typedef const T
* const_pointer
;
103 typedef T
& reference
;
104 typedef const T
& const_reference
;
105 typedef std::size_t size_type
;
106 typedef std::ptrdiff_t difference_type
;
108 template<class U
> struct rebind
{ typedef tracker_allocator
<U
> other
; };
111 address(reference value
) const _GLIBCXX_NOEXCEPT
112 { return std::__addressof(value
); }
115 address(const_reference value
) const _GLIBCXX_NOEXCEPT
116 { return std::__addressof(value
); }
118 tracker_allocator() _GLIBCXX_USE_NOEXCEPT
121 tracker_allocator(const tracker_allocator
&) _GLIBCXX_USE_NOEXCEPT
125 tracker_allocator(const tracker_allocator
<U
>&) _GLIBCXX_USE_NOEXCEPT
128 ~tracker_allocator() _GLIBCXX_USE_NOEXCEPT
132 max_size() const _GLIBCXX_USE_NOEXCEPT
133 { return size_type(-1) / sizeof(T
); }
136 allocate(size_type n
, const void* = 0)
137 { return static_cast<pointer
>(counter_type::allocate(n
* sizeof(T
))); }
139 #if __cplusplus >= 201103L
140 template<typename U
, typename
... Args
>
142 construct(U
* p
, Args
&&... args
)
144 ::new((void *)p
) U(std::forward
<Args
>(args
)...);
145 counter_type::construct();
153 counter_type::destroy();
157 construct(pointer p
, const T
& value
)
159 ::new ((void *)p
) T(value
);
160 counter_type::construct();
167 counter_type::destroy();
172 deallocate(pointer p
, size_type num
)
173 { counter_type::deallocate(p
, num
* sizeof(T
)); }
176 template<class T1
, class T2
>
178 operator==(const tracker_allocator
<T1
>&,
179 const tracker_allocator
<T2
>&) throw()
182 template<class T1
, class T2
>
184 operator!=(const tracker_allocator
<T1
>&,
185 const tracker_allocator
<T2
>&) throw()
189 check_construct_destroy(const char* tag
, int expected_c
, int expected_d
);
191 template<typename Alloc
>
193 check_deallocate_null()
195 // Let's not core here...
202 template<typename Alloc
>
204 check_allocate_max_size()
209 a
.allocate(a
.max_size() + 1);
211 catch(std::bad_alloc
&)
223 // A simple allocator which can be constructed endowed of a given
224 // "personality" (an integer), queried in operator== to simulate the
225 // behavior of realworld "unequal" allocators (i.e., not exploiting
226 // the provision in 20.1.5/4, first bullet). A global unordered_map,
227 // filled at allocation time with (pointer, personality) pairs, is
228 // then consulted to enforce the requirements in Table 32 about
229 // deallocation vs allocator equality. Note that this allocator is
230 // swappable, not assignable, consistently with Option 3 of DR 431
232 struct uneq_allocator_base
234 typedef std::tr1::unordered_map
<void*, int> map_type
;
236 // Avoid static initialization troubles and/or bad interactions
237 // with tests linking testsuite_allocator.o and playing globally
238 // with operator new/delete.
242 static map_type alloc_map
;
247 template<typename Tp
>
249 : private uneq_allocator_base
252 typedef std::size_t size_type
;
253 typedef std::ptrdiff_t difference_type
;
255 typedef const Tp
* const_pointer
;
256 typedef Tp
& reference
;
257 typedef const Tp
& const_reference
;
258 typedef Tp value_type
;
260 #if __cplusplus >= 201103L
261 typedef std::true_type propagate_on_container_swap
;
264 template<typename Tp1
>
266 { typedef uneq_allocator
<Tp1
> other
; };
268 uneq_allocator() _GLIBCXX_USE_NOEXCEPT
271 uneq_allocator(int person
) _GLIBCXX_USE_NOEXCEPT
272 : personality(person
) { }
274 template<typename Tp1
>
275 uneq_allocator(const uneq_allocator
<Tp1
>& b
) _GLIBCXX_USE_NOEXCEPT
276 : personality(b
.get_personality()) { }
278 ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
281 int get_personality() const { return personality
; }
284 address(reference x
) const _GLIBCXX_NOEXCEPT
285 { return std::__addressof(x
); }
288 address(const_reference x
) const _GLIBCXX_NOEXCEPT
289 { return std::__addressof(x
); }
292 allocate(size_type n
, const void* = 0)
294 if (__builtin_expect(n
> this->max_size(), false))
295 std::__throw_bad_alloc();
297 pointer p
= static_cast<Tp
*>(::operator new(n
* sizeof(Tp
)));
300 get_map().insert(map_type::value_type(reinterpret_cast<void*>(p
),
305 ::operator delete(p
);
306 __throw_exception_again
;
312 deallocate(pointer p
, size_type
)
314 bool test
__attribute__((unused
)) = true;
318 map_type::iterator it
= get_map().find(reinterpret_cast<void*>(p
));
319 VERIFY( it
!= get_map().end() );
321 // Enforce requirements in Table 32 about deallocation vs
322 // allocator equality.
323 VERIFY( it
->second
== personality
);
326 ::operator delete(p
);
330 max_size() const _GLIBCXX_USE_NOEXCEPT
331 { return size_type(-1) / sizeof(Tp
); }
333 #if __cplusplus >= 201103L
334 template<typename U
, typename
... Args
>
336 construct(U
* p
, Args
&&... args
)
337 { ::new((void *)p
) U(std::forward
<Args
>(args
)...); }
341 destroy(U
* p
) { p
->~U(); }
343 // Not copy assignable...
345 operator=(const uneq_allocator
&) = delete;
348 construct(pointer p
, const Tp
& val
)
349 { ::new((void *)p
) Tp(val
); }
352 destroy(pointer p
) { p
->~Tp(); }
357 operator=(const uneq_allocator
&);
362 // ... yet swappable!
364 swap(uneq_allocator
& a
, uneq_allocator
& b
)
365 { std::swap(a
.personality
, b
.personality
); }
367 template<typename Tp1
>
369 operator==(const uneq_allocator
& a
, const uneq_allocator
<Tp1
>& b
)
370 { return a
.personality
== b
.personality
; }
372 template<typename Tp1
>
374 operator!=(const uneq_allocator
& a
, const uneq_allocator
<Tp1
>& b
)
375 { return !(a
== b
); }
380 #if __cplusplus >= 201103L
381 // An uneq_allocator which can be used to test allocator propagation.
382 template<typename Tp
, bool Propagate
>
383 class propagating_allocator
: public uneq_allocator
<Tp
>
385 typedef uneq_allocator
<Tp
> base_alloc
;
386 base_alloc
& base() { return *this; }
387 const base_alloc
& base() const { return *this; }
388 void swap_base(base_alloc
& b
) { swap(b
, this->base()); }
390 typedef std::integral_constant
<bool, Propagate
> trait_type
;
393 // default allocator_traits::rebind_alloc would select
394 // uneq_allocator::rebind so we must define rebind here
395 template<typename Up
>
396 struct rebind
{ typedef propagating_allocator
<Up
, Propagate
> other
; };
398 propagating_allocator(int i
) noexcept
402 template<typename Up
>
403 propagating_allocator(const propagating_allocator
<Up
, Propagate
>& a
)
408 propagating_allocator() noexcept
= default;
410 propagating_allocator(const propagating_allocator
&) noexcept
= default;
412 propagating_allocator
&
413 operator=(const propagating_allocator
& a
) noexcept
415 static_assert(Propagate
, "assigning propagating_allocator<T, true>");
416 propagating_allocator(a
).swap_base(*this);
421 propagating_allocator
&
422 operator=(const propagating_allocator
<Tp
, P2
>& a
) noexcept
424 static_assert(P2
, "assigning propagating_allocator<T, true>");
425 propagating_allocator(a
).swap_base(*this);
429 // postcondition: a.get_personality() == 0
430 propagating_allocator(propagating_allocator
&& a
) noexcept
434 // postcondition: a.get_personality() == 0
435 propagating_allocator
&
436 operator=(propagating_allocator
&& a
) noexcept
438 propagating_allocator(std::move(a
)).swap_base(*this);
442 typedef trait_type propagate_on_container_copy_assignment
;
443 typedef trait_type propagate_on_container_move_assignment
;
444 typedef trait_type propagate_on_container_swap
;
446 propagating_allocator
select_on_container_copy_construction() const
447 { return Propagate
? *this : propagating_allocator(); }
450 // Class template supporting the minimal interface that satisfies the
451 // Allocator requirements, from example in [allocator.requirements]
453 struct SimpleAllocator
455 typedef Tp value_type
;
457 SimpleAllocator() noexcept
{ }
460 SimpleAllocator(const SimpleAllocator
<T
>& other
) { }
462 Tp
*allocate(std::size_t n
)
463 { return std::allocator
<Tp
>().allocate(n
); }
465 void deallocate(Tp
*p
, std::size_t n
)
466 { std::allocator
<Tp
>().deallocate(p
, n
); }
469 template <class T
, class U
>
470 bool operator==(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
472 template <class T
, class U
>
473 bool operator!=(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
478 template<typename Tp
>
479 struct ExplicitConsAlloc
: std::allocator
<Tp
>
481 ExplicitConsAlloc() { }
483 template<typename Up
>
485 ExplicitConsAlloc(const ExplicitConsAlloc
<Up
>&) { }
487 template<typename Up
>
489 { typedef ExplicitConsAlloc
<Up
> other
; };
492 #if __cplusplus >= 201103L
493 template<typename Tp
>
494 class CustomPointerAlloc
: public std::allocator
<Tp
>
496 template<typename Up
, typename Sp
= __gnu_cxx::_Std_pointer_impl
<Up
>>
497 using Ptr
= __gnu_cxx::_Pointer_adapter
<Sp
>;
500 CustomPointerAlloc() = default;
502 template<typename Up
>
503 CustomPointerAlloc(const CustomPointerAlloc
<Up
>&) { }
505 template<typename Up
>
507 { typedef CustomPointerAlloc
<Up
> other
; };
509 typedef Ptr
<Tp
> pointer
;
510 typedef Ptr
<const Tp
> const_pointer
;
511 typedef Ptr
<void> void_pointer
;
512 typedef Ptr
<const void> const_void_pointer
;
514 pointer
allocate(std::size_t n
, pointer
= {})
515 { return pointer(std::allocator
<Tp
>::allocate(n
)); }
517 void deallocate(pointer p
, std::size_t n
)
518 { std::allocator
<Tp
>::deallocate(std::addressof(*p
), n
); }
521 // Utility for use as CRTP base class of custom pointer types
522 template<typename Derived
, typename T
>
525 typedef T element_type
;
527 // typedefs for iterator_traits
528 typedef T value_type
;
529 typedef std::ptrdiff_t difference_type
;
530 typedef std::random_access_iterator_tag iterator_category
;
531 typedef Derived pointer
;
532 typedef T
& reference
;
536 explicit PointerBase(T
* p
= nullptr) : value(p
) { }
538 template<typename D
, typename U
,
539 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
540 PointerBase(const PointerBase
<D
, U
>& p
) : value(p
.value
) { }
542 T
& operator*() const { return *value
; }
543 T
* operator->() const { return value
; }
545 Derived
& operator++() { ++value
; return derived(); }
546 Derived
operator++(int) { Derived
tmp(derived()); ++value
; return tmp
; }
547 Derived
& operator--() { --value
; return derived(); }
548 Derived
operator--(int) { Derived
tmp(derived()); --value
; return tmp
; }
550 Derived
& operator+=(difference_type n
) { value
+= n
; return derived(); }
551 Derived
& operator-=(difference_type n
) { value
-= n
; return derived(); }
553 explicit operator bool() const { return value
!= nullptr; }
556 operator+(difference_type n
) const
558 Derived
p(derived());
563 operator-(difference_type n
) const
565 Derived
p(derived());
570 Derived
& derived() { return static_cast<Derived
&>(*this); }
573 template<typename D
, typename T
>
574 std::ptrdiff_t operator-(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
575 { return l
.value
- r
.value
; }
577 template<typename D
, typename T
>
578 bool operator==(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
579 { return l
.value
== r
.value
; }
581 template<typename D
, typename T
>
582 bool operator!=(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
583 { return l
.value
!= r
.value
; }
585 // implementation for void specializations
587 struct PointerBase_void
589 typedef T element_type
;
591 // typedefs for iterator_traits
592 typedef T value_type
;
593 typedef std::ptrdiff_t difference_type
;
594 typedef std::random_access_iterator_tag iterator_category
;
598 explicit PointerBase_void(T
* p
= nullptr) : value(p
) { }
600 template<typename D
, typename U
,
601 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
602 PointerBase_void(const PointerBase
<D
, U
>& p
) : value(p
.value
) { }
604 explicit operator bool() const { return value
!= nullptr; }
607 template<typename Derived
>
608 struct PointerBase
<Derived
, void> : PointerBase_void
<void>
610 using PointerBase_void::PointerBase_void
;
611 typedef Derived pointer
;
614 template<typename Derived
>
615 struct PointerBase
<Derived
, const void> : PointerBase_void
<const void>
617 using PointerBase_void::PointerBase_void
;
618 typedef Derived pointer
;
622 } // namespace __gnu_test
624 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H