2 // Testing allocator for the C++ library testsuite.
4 // Copyright (C) 2002-2018 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 <ext/alloc_traits.h>
33 #include <testsuite_hooks.h>
37 class tracker_allocator_counter
40 typedef std::size_t size_type
;
43 allocate(size_type blocksize
)
44 { allocationCount_
+= blocksize
; }
47 construct() { ++constructCount_
; }
50 destroy() { ++destructCount_
; }
53 deallocate(size_type blocksize
)
54 { deallocationCount_
+= blocksize
; }
57 get_allocation_count() { return allocationCount_
; }
60 get_deallocation_count() { return deallocationCount_
; }
63 get_construct_count() { return constructCount_
; }
66 get_destruct_count() { return destructCount_
; }
72 deallocationCount_
= 0;
78 static size_type allocationCount_
;
79 static size_type deallocationCount_
;
80 static int constructCount_
;
81 static int destructCount_
;
84 // Helper to detect inconsistency between type used to instantiate an
85 // allocator and the underlying allocator value_type.
86 template<typename T
, typename Alloc
,
87 typename
= typename
Alloc::value_type
>
88 struct check_consistent_alloc_value_type
;
90 template<typename T
, typename Alloc
>
91 struct check_consistent_alloc_value_type
<T
, Alloc
, T
>
92 { typedef T value_type
; };
94 // An allocator facade that intercepts allocate/deallocate/construct/destroy
95 // calls and track them through the tracker_allocator_counter class. This
96 // class is templated on the target object type, but tracker isn't.
97 template<typename T
, typename Alloc
= std::allocator
<T
> >
98 class tracker_allocator
: public Alloc
101 typedef tracker_allocator_counter counter_type
;
103 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
107 check_consistent_alloc_value_type
<T
, Alloc
>::value_type value_type
;
108 typedef typename
AllocTraits::pointer pointer
;
109 typedef typename
AllocTraits::size_type size_type
;
114 typedef tracker_allocator
<U
,
115 typename
AllocTraits::template rebind
<U
>::other
> other
;
118 #if __cplusplus >= 201103L
119 tracker_allocator() = default;
120 tracker_allocator(const tracker_allocator
&) = default;
121 tracker_allocator(tracker_allocator
&&) = default;
122 tracker_allocator
& operator=(const tracker_allocator
&) = default;
123 tracker_allocator
& operator=(tracker_allocator
&&) = default;
125 // Perfect forwarding constructor.
126 template<typename
... _Args
>
127 tracker_allocator(_Args
&&... __args
)
128 : Alloc(std::forward
<_Args
>(__args
)...)
134 tracker_allocator(const tracker_allocator
&)
142 tracker_allocator(const tracker_allocator
<U
,
143 typename
AllocTraits::template rebind
<U
>::other
>& alloc
)
144 _GLIBCXX_USE_NOEXCEPT
149 allocate(size_type n
, const void* = 0)
151 pointer p
= AllocTraits::allocate(*this, n
);
152 counter_type::allocate(n
* sizeof(T
));
156 #if __cplusplus >= 201103L
157 template<typename U
, typename
... Args
>
159 construct(U
* p
, Args
&&... args
)
161 AllocTraits::construct(*this, p
, std::forward
<Args
>(args
)...);
162 counter_type::construct();
169 AllocTraits::destroy(*this, p
);
170 counter_type::destroy();
174 construct(pointer p
, const T
& value
)
176 AllocTraits::construct(*this, p
, value
);
177 counter_type::construct();
183 AllocTraits::destroy(*this, p
);
184 counter_type::destroy();
189 deallocate(pointer p
, size_type num
)
191 counter_type::deallocate(num
* sizeof(T
));
192 AllocTraits::deallocate(*this, p
, num
);
195 // Implement swap for underlying allocators that might need it.
197 swap(tracker_allocator
& a
, tracker_allocator
& b
)
207 template<class T1
, class Alloc1
, class T2
, class Alloc2
>
209 operator==(const tracker_allocator
<T1
, Alloc1
>& lhs
,
210 const tracker_allocator
<T2
, Alloc2
>& rhs
) throw()
212 const Alloc1
& alloc1
= lhs
;
213 const Alloc2
& alloc2
= rhs
;
214 return alloc1
== alloc2
;
217 template<class T1
, class Alloc1
, class T2
, class Alloc2
>
219 operator!=(const tracker_allocator
<T1
, Alloc1
>& lhs
,
220 const tracker_allocator
<T2
, Alloc2
>& rhs
) throw()
221 { return !(lhs
== rhs
); }
224 check_construct_destroy(const char* tag
, int expected_c
, int expected_d
);
226 template<typename Alloc
>
228 check_deallocate_null()
230 // Let's not core here...
237 template<typename Alloc
>
239 check_allocate_max_size()
244 a
.allocate(a
.max_size() + 1);
246 catch(std::bad_alloc
&)
257 // A simple allocator which can be constructed endowed of a given
258 // "personality" (an integer), queried in operator== to simulate the
259 // behavior of realworld "unequal" allocators (i.e., not exploiting
260 // the provision in 20.1.5/4, first bullet). A global unordered_map,
261 // filled at allocation time with (pointer, personality) pairs, is
262 // then consulted to enforce the requirements in Table 32 about
263 // deallocation vs allocator equality. Note that this allocator is
264 // swappable, not copy assignable, consistently with Option 3 of DR 431
266 struct uneq_allocator_base
268 typedef std::tr1::unordered_map
<void*, int> map_type
;
270 // Avoid static initialization troubles and/or bad interactions
271 // with tests linking testsuite_allocator.o and playing globally
272 // with operator new/delete.
276 static map_type alloc_map
;
281 template<typename Tp
, typename Alloc
= std::allocator
<Tp
> >
283 : private uneq_allocator_base
,
286 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
288 Alloc
& base() { return *this; }
289 const Alloc
& base() const { return *this; }
290 void swap_base(Alloc
& b
) { using std::swap
; swap(b
, this->base()); }
293 typedef typename check_consistent_alloc_value_type
<Tp
, Alloc
>::value_type
295 typedef typename
AllocTraits::size_type size_type
;
296 typedef typename
AllocTraits::pointer pointer
;
298 #if __cplusplus >= 201103L
299 typedef std::true_type propagate_on_container_swap
;
300 typedef std::false_type is_always_equal
;
303 template<typename Tp1
>
306 typedef uneq_allocator
<Tp1
,
307 typename
AllocTraits::template rebind
<Tp1
>::other
> other
;
310 uneq_allocator() _GLIBCXX_USE_NOEXCEPT
313 uneq_allocator(int person
) _GLIBCXX_USE_NOEXCEPT
314 : personality(person
) { }
316 #if __cplusplus >= 201103L
317 uneq_allocator(const uneq_allocator
&) = default;
318 uneq_allocator(uneq_allocator
&&) = default;
321 template<typename Tp1
>
322 uneq_allocator(const uneq_allocator
<Tp1
,
323 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
324 _GLIBCXX_USE_NOEXCEPT
325 : personality(b
.get_personality()) { }
327 ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
330 int get_personality() const { return personality
; }
333 allocate(size_type n
, const void* hint
= 0)
335 pointer p
= AllocTraits::allocate(*this, n
);
339 get_map().insert(map_type::value_type(reinterpret_cast<void*>(p
),
344 AllocTraits::deallocate(*this, p
, n
);
345 __throw_exception_again
;
352 deallocate(pointer p
, size_type n
)
356 map_type::iterator it
= get_map().find(reinterpret_cast<void*>(p
));
357 VERIFY( it
!= get_map().end() );
359 // Enforce requirements in Table 32 about deallocation vs
360 // allocator equality.
361 VERIFY( it
->second
== personality
);
364 AllocTraits::deallocate(*this, p
, n
);
367 #if __cplusplus >= 201103L
368 // Not copy assignable...
370 operator=(const uneq_allocator
&) = delete;
372 // ... but still moveable if base allocator is.
374 operator=(uneq_allocator
&&) = default;
379 operator=(const uneq_allocator
&);
383 // ... yet swappable!
385 swap(uneq_allocator
& a
, uneq_allocator
& b
)
387 std::swap(a
.personality
, b
.personality
);
391 template<typename Tp1
>
393 operator==(const uneq_allocator
& a
,
394 const uneq_allocator
<Tp1
,
395 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
396 { return a
.personality
== b
.personality
; }
398 template<typename Tp1
>
400 operator!=(const uneq_allocator
& a
,
401 const uneq_allocator
<Tp1
,
402 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
403 { return !(a
== b
); }
408 #if __cplusplus >= 201103L
409 // An uneq_allocator which can be used to test allocator propagation.
410 template<typename Tp
, bool Propagate
, typename Alloc
= std::allocator
<Tp
>>
411 class propagating_allocator
: public uneq_allocator
<Tp
, Alloc
>
413 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
415 typedef uneq_allocator
<Tp
, Alloc
> base_alloc
;
416 base_alloc
& base() { return *this; }
417 const base_alloc
& base() const { return *this; }
418 void swap_base(base_alloc
& b
) { swap(b
, this->base()); }
420 typedef std::integral_constant
<bool, Propagate
> trait_type
;
423 // default allocator_traits::rebind_alloc would select
424 // uneq_allocator::rebind so we must define rebind here
425 template<typename Up
>
428 typedef propagating_allocator
<Up
, Propagate
,
429 typename
AllocTraits::template rebind
<Up
>::other
> other
;
432 propagating_allocator(int i
) noexcept
436 template<typename Up
>
437 propagating_allocator(const propagating_allocator
<Up
, Propagate
,
438 typename
AllocTraits::template rebind
<Up
>::other
>& a
)
443 propagating_allocator() noexcept
= default;
445 propagating_allocator(const propagating_allocator
&) noexcept
= default;
447 propagating_allocator
&
448 operator=(const propagating_allocator
& a
) noexcept
450 static_assert(Propagate
, "assigning propagating_allocator<T, true>");
451 propagating_allocator(a
).swap_base(*this);
456 propagating_allocator
&
457 operator=(const propagating_allocator
<Tp
, P2
, Alloc
>& a
) noexcept
459 static_assert(P2
, "assigning propagating_allocator<T, true>");
460 propagating_allocator(a
).swap_base(*this);
464 // postcondition: a.get_personality() == 0
465 propagating_allocator(propagating_allocator
&& a
) noexcept
469 // postcondition: a.get_personality() == 0
470 propagating_allocator
&
471 operator=(propagating_allocator
&& a
) noexcept
473 propagating_allocator(std::move(a
)).swap_base(*this);
477 typedef trait_type propagate_on_container_copy_assignment
;
478 typedef trait_type propagate_on_container_move_assignment
;
479 typedef trait_type propagate_on_container_swap
;
481 propagating_allocator
select_on_container_copy_construction() const
482 { return Propagate
? *this : propagating_allocator(); }
485 // Class template supporting the minimal interface that satisfies the
486 // Allocator requirements, from example in [allocator.requirements]
488 struct SimpleAllocator
490 typedef Tp value_type
;
492 SimpleAllocator() noexcept
{ }
495 SimpleAllocator(const SimpleAllocator
<T
>&) { }
497 Tp
*allocate(std::size_t n
)
498 { return std::allocator
<Tp
>().allocate(n
); }
500 void deallocate(Tp
*p
, std::size_t n
)
501 { std::allocator
<Tp
>().deallocate(p
, n
); }
504 template <class T
, class U
>
505 bool operator==(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
507 template <class T
, class U
>
508 bool operator!=(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
512 struct default_init_allocator
514 using value_type
= T
;
516 default_init_allocator() = default;
519 default_init_allocator(const default_init_allocator
<U
>& a
)
524 allocate(std::size_t n
)
525 { return std::allocator
<T
>().allocate(n
); }
528 deallocate(T
* p
, std::size_t n
)
529 { std::allocator
<T
>().deallocate(p
, n
); }
534 template<typename T
, typename U
>
535 bool operator==(const default_init_allocator
<T
>& t
,
536 const default_init_allocator
<U
>& u
)
537 { return t
.state
== u
.state
; }
539 template<typename T
, typename U
>
540 bool operator!=(const default_init_allocator
<T
>& t
,
541 const default_init_allocator
<U
>& u
)
542 { return !(t
== u
); }
545 template<typename Tp
>
546 struct ExplicitConsAlloc
: std::allocator
<Tp
>
548 ExplicitConsAlloc() { }
550 template<typename Up
>
552 ExplicitConsAlloc(const ExplicitConsAlloc
<Up
>&) { }
554 template<typename Up
>
556 { typedef ExplicitConsAlloc
<Up
> other
; };
559 #if __cplusplus >= 201103L
560 template<typename Tp
>
561 class CustomPointerAlloc
: public std::allocator
<Tp
>
563 template<typename Up
, typename Sp
= __gnu_cxx::_Std_pointer_impl
<Up
>>
564 using Ptr
= __gnu_cxx::_Pointer_adapter
<Sp
>;
567 CustomPointerAlloc() = default;
569 template<typename Up
>
570 CustomPointerAlloc(const CustomPointerAlloc
<Up
>&) { }
572 template<typename Up
>
574 { typedef CustomPointerAlloc
<Up
> other
; };
576 typedef Ptr
<Tp
> pointer
;
577 typedef Ptr
<const Tp
> const_pointer
;
578 typedef Ptr
<void> void_pointer
;
579 typedef Ptr
<const void> const_void_pointer
;
581 pointer
allocate(std::size_t n
, pointer
= {})
582 { return pointer(std::allocator
<Tp
>::allocate(n
)); }
584 void deallocate(pointer p
, std::size_t n
)
585 { std::allocator
<Tp
>::deallocate(std::addressof(*p
), n
); }
588 // Utility for use as CRTP base class of custom pointer types
589 template<typename Derived
, typename T
>
592 typedef T element_type
;
594 // typedefs for iterator_traits
595 typedef T value_type
;
596 typedef std::ptrdiff_t difference_type
;
597 typedef std::random_access_iterator_tag iterator_category
;
598 typedef Derived pointer
;
599 typedef T
& reference
;
603 explicit PointerBase(T
* p
= nullptr) : value(p
) { }
605 PointerBase(std::nullptr_t
) : value(nullptr) { }
607 template<typename D
, typename U
,
608 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
609 PointerBase(const PointerBase
<D
, U
>& p
) : value(p
.value
) { }
611 T
& operator*() const { return *value
; }
612 T
* operator->() const { return value
; }
613 T
& operator[](difference_type n
) const { return value
[n
]; }
615 Derived
& operator++() { ++value
; return derived(); }
616 Derived
operator++(int) { Derived
tmp(derived()); ++value
; return tmp
; }
617 Derived
& operator--() { --value
; return derived(); }
618 Derived
operator--(int) { Derived
tmp(derived()); --value
; return tmp
; }
620 Derived
& operator+=(difference_type n
) { value
+= n
; return derived(); }
621 Derived
& operator-=(difference_type n
) { value
-= n
; return derived(); }
623 explicit operator bool() const { return value
!= nullptr; }
626 operator+(difference_type n
) const
628 Derived
p(derived());
633 operator-(difference_type n
) const
635 Derived
p(derived());
641 derived() { return static_cast<Derived
&>(*this); }
644 derived() const { return static_cast<const Derived
&>(*this); }
647 template<typename D
, typename T
>
648 std::ptrdiff_t operator-(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
649 { return l
.value
- r
.value
; }
651 template<typename D
, typename T
>
652 bool operator==(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
653 { return l
.value
== r
.value
; }
655 template<typename D
, typename T
>
656 bool operator!=(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
657 { return l
.value
!= r
.value
; }
659 // implementation for void specializations
661 struct PointerBase_void
663 typedef T element_type
;
665 // typedefs for iterator_traits
666 typedef T value_type
;
667 typedef std::ptrdiff_t difference_type
;
668 typedef std::random_access_iterator_tag iterator_category
;
672 explicit PointerBase_void(T
* p
= nullptr) : value(p
) { }
674 template<typename D
, typename U
,
675 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
676 PointerBase_void(const PointerBase
<D
, U
>& p
) : value(p
.value
) { }
678 explicit operator bool() const { return value
!= nullptr; }
681 template<typename Derived
>
682 struct PointerBase
<Derived
, void> : PointerBase_void
<void>
684 using PointerBase_void::PointerBase_void
;
685 typedef Derived pointer
;
688 template<typename Derived
>
689 struct PointerBase
<Derived
, const void> : PointerBase_void
<const void>
691 using PointerBase_void::PointerBase_void
;
692 typedef Derived pointer
;
696 } // namespace __gnu_test
698 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H