2 // Testing allocator for the C++ library testsuite.
4 // Copyright (C) 2002-2019 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>
34 #if __cplusplus >= 201703L
35 # include <memory_resource>
41 class tracker_allocator_counter
44 typedef std::size_t size_type
;
47 allocate(size_type blocksize
)
48 { allocationCount_
+= blocksize
; }
51 construct() { ++constructCount_
; }
54 destroy() { ++destructCount_
; }
57 deallocate(size_type blocksize
)
58 { deallocationCount_
+= blocksize
; }
61 get_allocation_count() { return allocationCount_
; }
64 get_deallocation_count() { return deallocationCount_
; }
67 get_construct_count() { return constructCount_
; }
70 get_destruct_count() { return destructCount_
; }
76 deallocationCount_
= 0;
82 static size_type allocationCount_
;
83 static size_type deallocationCount_
;
84 static int constructCount_
;
85 static int destructCount_
;
88 // Helper to detect inconsistency between type used to instantiate an
89 // allocator and the underlying allocator value_type.
90 template<typename T
, typename Alloc
,
91 typename
= typename
Alloc::value_type
>
92 struct check_consistent_alloc_value_type
;
94 template<typename T
, typename Alloc
>
95 struct check_consistent_alloc_value_type
<T
, Alloc
, T
>
96 { typedef T value_type
; };
98 // An allocator facade that intercepts allocate/deallocate/construct/destroy
99 // calls and track them through the tracker_allocator_counter class. This
100 // class is templated on the target object type, but tracker isn't.
101 template<typename T
, typename Alloc
= std::allocator
<T
> >
102 class tracker_allocator
: public Alloc
105 typedef tracker_allocator_counter counter_type
;
107 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
111 check_consistent_alloc_value_type
<T
, Alloc
>::value_type value_type
;
112 typedef typename
AllocTraits::pointer pointer
;
113 typedef typename
AllocTraits::size_type size_type
;
118 typedef tracker_allocator
<U
,
119 typename
AllocTraits::template rebind
<U
>::other
> other
;
122 #if __cplusplus >= 201103L
123 tracker_allocator() = default;
124 tracker_allocator(const tracker_allocator
&) = default;
125 tracker_allocator(tracker_allocator
&&) = default;
126 tracker_allocator
& operator=(const tracker_allocator
&) = default;
127 tracker_allocator
& operator=(tracker_allocator
&&) = default;
129 // Perfect forwarding constructor.
130 template<typename
... _Args
>
131 tracker_allocator(_Args
&&... __args
)
132 : Alloc(std::forward
<_Args
>(__args
)...)
138 tracker_allocator(const tracker_allocator
&)
146 tracker_allocator(const tracker_allocator
<U
,
147 typename
AllocTraits::template rebind
<U
>::other
>& alloc
)
148 _GLIBCXX_USE_NOEXCEPT
153 allocate(size_type n
, const void* = 0)
155 pointer p
= AllocTraits::allocate(*this, n
);
156 counter_type::allocate(n
* sizeof(T
));
160 #if __cplusplus >= 201103L
161 template<typename U
, typename
... Args
>
163 construct(U
* p
, Args
&&... args
)
165 AllocTraits::construct(*this, p
, std::forward
<Args
>(args
)...);
166 counter_type::construct();
173 AllocTraits::destroy(*this, p
);
174 counter_type::destroy();
178 construct(pointer p
, const T
& value
)
180 AllocTraits::construct(*this, p
, value
);
181 counter_type::construct();
187 AllocTraits::destroy(*this, p
);
188 counter_type::destroy();
193 deallocate(pointer p
, size_type num
)
195 counter_type::deallocate(num
* sizeof(T
));
196 AllocTraits::deallocate(*this, p
, num
);
199 // Implement swap for underlying allocators that might need it.
201 swap(tracker_allocator
& a
, tracker_allocator
& b
)
211 template<class T1
, class Alloc1
, class T2
, class Alloc2
>
213 operator==(const tracker_allocator
<T1
, Alloc1
>& lhs
,
214 const tracker_allocator
<T2
, Alloc2
>& rhs
) throw()
216 const Alloc1
& alloc1
= lhs
;
217 const Alloc2
& alloc2
= rhs
;
218 return alloc1
== alloc2
;
221 template<class T1
, class Alloc1
, class T2
, class Alloc2
>
223 operator!=(const tracker_allocator
<T1
, Alloc1
>& lhs
,
224 const tracker_allocator
<T2
, Alloc2
>& rhs
) throw()
225 { return !(lhs
== rhs
); }
228 check_construct_destroy(const char* tag
, int expected_c
, int expected_d
);
230 template<typename Alloc
>
232 check_deallocate_null()
234 // Let's not core here...
241 template<typename Alloc
>
243 check_allocate_max_size()
248 a
.allocate(a
.max_size() + 1);
250 catch(std::bad_alloc
&)
261 // A simple allocator which can be constructed endowed of a given
262 // "personality" (an integer), queried in operator== to simulate the
263 // behavior of realworld "unequal" allocators (i.e., not exploiting
264 // the provision in 20.1.5/4, first bullet). A global unordered_map,
265 // filled at allocation time with (pointer, personality) pairs, is
266 // then consulted to enforce the requirements in Table 32 about
267 // deallocation vs allocator equality. Note that this allocator is
268 // swappable, not copy assignable, consistently with Option 3 of DR 431
270 struct uneq_allocator_base
272 typedef std::tr1::unordered_map
<void*, int> map_type
;
274 // Avoid static initialization troubles and/or bad interactions
275 // with tests linking testsuite_allocator.o and playing globally
276 // with operator new/delete.
280 static map_type alloc_map
;
285 template<typename Tp
, typename Alloc
= std::allocator
<Tp
> >
287 : private uneq_allocator_base
,
290 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
292 Alloc
& base() { return *this; }
293 const Alloc
& base() const { return *this; }
294 void swap_base(Alloc
& b
) { using std::swap
; swap(b
, this->base()); }
297 typedef typename check_consistent_alloc_value_type
<Tp
, Alloc
>::value_type
299 typedef typename
AllocTraits::size_type size_type
;
300 typedef typename
AllocTraits::pointer pointer
;
302 #if __cplusplus >= 201103L
303 typedef std::true_type propagate_on_container_swap
;
304 typedef std::false_type is_always_equal
;
307 template<typename Tp1
>
310 typedef uneq_allocator
<Tp1
,
311 typename
AllocTraits::template rebind
<Tp1
>::other
> other
;
314 uneq_allocator() _GLIBCXX_USE_NOEXCEPT
317 uneq_allocator(int person
) _GLIBCXX_USE_NOEXCEPT
318 : personality(person
) { }
320 #if __cplusplus >= 201103L
321 uneq_allocator(const uneq_allocator
&) = default;
322 uneq_allocator(uneq_allocator
&&) = default;
325 template<typename Tp1
>
326 uneq_allocator(const uneq_allocator
<Tp1
,
327 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
328 _GLIBCXX_USE_NOEXCEPT
329 : personality(b
.get_personality()) { }
331 ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
334 int get_personality() const { return personality
; }
337 allocate(size_type n
, const void* hint
= 0)
339 pointer p
= AllocTraits::allocate(*this, n
);
343 get_map().insert(map_type::value_type(reinterpret_cast<void*>(p
),
348 AllocTraits::deallocate(*this, p
, n
);
349 __throw_exception_again
;
356 deallocate(pointer p
, size_type n
)
360 map_type::iterator it
= get_map().find(reinterpret_cast<void*>(p
));
361 VERIFY( it
!= get_map().end() );
363 // Enforce requirements in Table 32 about deallocation vs
364 // allocator equality.
365 VERIFY( it
->second
== personality
);
368 AllocTraits::deallocate(*this, p
, n
);
371 #if __cplusplus >= 201103L
372 // Not copy assignable...
374 operator=(const uneq_allocator
&) = delete;
376 // ... but still moveable if base allocator is.
378 operator=(uneq_allocator
&&) = default;
383 operator=(const uneq_allocator
&);
387 // ... yet swappable!
389 swap(uneq_allocator
& a
, uneq_allocator
& b
)
391 std::swap(a
.personality
, b
.personality
);
395 template<typename Tp1
>
397 operator==(const uneq_allocator
& a
,
398 const uneq_allocator
<Tp1
,
399 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
400 { return a
.personality
== b
.personality
; }
402 template<typename Tp1
>
404 operator!=(const uneq_allocator
& a
,
405 const uneq_allocator
<Tp1
,
406 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
407 { return !(a
== b
); }
412 #if __cplusplus >= 201103L
413 // An uneq_allocator which can be used to test allocator propagation.
414 template<typename Tp
, bool Propagate
, typename Alloc
= std::allocator
<Tp
>>
415 class propagating_allocator
: public uneq_allocator
<Tp
, Alloc
>
417 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
419 typedef uneq_allocator
<Tp
, Alloc
> base_alloc
;
420 base_alloc
& base() { return *this; }
421 const base_alloc
& base() const { return *this; }
422 void swap_base(base_alloc
& b
) { swap(b
, this->base()); }
424 typedef std::integral_constant
<bool, Propagate
> trait_type
;
427 // default allocator_traits::rebind_alloc would select
428 // uneq_allocator::rebind so we must define rebind here
429 template<typename Up
>
432 typedef propagating_allocator
<Up
, Propagate
,
433 typename
AllocTraits::template rebind
<Up
>::other
> other
;
436 propagating_allocator(int i
) noexcept
440 template<typename Up
>
441 propagating_allocator(const propagating_allocator
<Up
, Propagate
,
442 typename
AllocTraits::template rebind
<Up
>::other
>& a
)
447 propagating_allocator() noexcept
= default;
449 propagating_allocator(const propagating_allocator
&) noexcept
= default;
451 propagating_allocator
&
452 operator=(const propagating_allocator
& a
) noexcept
454 static_assert(Propagate
, "assigning propagating_allocator<T, true>");
455 propagating_allocator(a
).swap_base(*this);
460 propagating_allocator
&
461 operator=(const propagating_allocator
<Tp
, P2
, Alloc
>& a
) noexcept
463 static_assert(P2
, "assigning propagating_allocator<T, true>");
464 propagating_allocator(a
).swap_base(*this);
468 // postcondition: a.get_personality() == 0
469 propagating_allocator(propagating_allocator
&& a
) noexcept
473 // postcondition: a.get_personality() == 0
474 propagating_allocator
&
475 operator=(propagating_allocator
&& a
) noexcept
477 propagating_allocator(std::move(a
)).swap_base(*this);
481 typedef trait_type propagate_on_container_copy_assignment
;
482 typedef trait_type propagate_on_container_move_assignment
;
483 typedef trait_type propagate_on_container_swap
;
485 propagating_allocator
select_on_container_copy_construction() const
486 { return Propagate
? *this : propagating_allocator(); }
489 // Class template supporting the minimal interface that satisfies the
490 // Allocator requirements, from example in [allocator.requirements]
492 struct SimpleAllocator
494 typedef Tp value_type
;
496 SimpleAllocator() noexcept
{ }
499 SimpleAllocator(const SimpleAllocator
<T
>&) { }
501 Tp
*allocate(std::size_t n
)
502 { return std::allocator
<Tp
>().allocate(n
); }
504 void deallocate(Tp
*p
, std::size_t n
)
505 { std::allocator
<Tp
>().deallocate(p
, n
); }
508 template <class T
, class U
>
509 bool operator==(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
511 template <class T
, class U
>
512 bool operator!=(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
516 struct default_init_allocator
518 using value_type
= T
;
520 default_init_allocator() = default;
523 default_init_allocator(const default_init_allocator
<U
>& a
)
528 allocate(std::size_t n
)
529 { return std::allocator
<T
>().allocate(n
); }
532 deallocate(T
* p
, std::size_t n
)
533 { std::allocator
<T
>().deallocate(p
, n
); }
538 template<typename T
, typename U
>
539 bool operator==(const default_init_allocator
<T
>& t
,
540 const default_init_allocator
<U
>& u
)
541 { return t
.state
== u
.state
; }
543 template<typename T
, typename U
>
544 bool operator!=(const default_init_allocator
<T
>& t
,
545 const default_init_allocator
<U
>& u
)
546 { return !(t
== u
); }
549 template<typename Tp
>
550 struct ExplicitConsAlloc
: std::allocator
<Tp
>
552 ExplicitConsAlloc() { }
554 template<typename Up
>
556 ExplicitConsAlloc(const ExplicitConsAlloc
<Up
>&) { }
558 template<typename Up
>
560 { typedef ExplicitConsAlloc
<Up
> other
; };
563 #if __cplusplus >= 201103L
564 template<typename Tp
>
565 class CustomPointerAlloc
: public std::allocator
<Tp
>
567 template<typename Up
, typename Sp
= __gnu_cxx::_Std_pointer_impl
<Up
>>
568 using Ptr
= __gnu_cxx::_Pointer_adapter
<Sp
>;
571 CustomPointerAlloc() = default;
573 template<typename Up
>
574 CustomPointerAlloc(const CustomPointerAlloc
<Up
>&) { }
576 template<typename Up
>
578 { typedef CustomPointerAlloc
<Up
> other
; };
580 typedef Ptr
<Tp
> pointer
;
581 typedef Ptr
<const Tp
> const_pointer
;
582 typedef Ptr
<void> void_pointer
;
583 typedef Ptr
<const void> const_void_pointer
;
585 pointer
allocate(std::size_t n
, const_void_pointer
= {})
586 { return pointer(std::allocator
<Tp
>::allocate(n
)); }
588 void deallocate(pointer p
, std::size_t n
)
589 { std::allocator
<Tp
>::deallocate(std::addressof(*p
), n
); }
592 // Utility for use as CRTP base class of custom pointer types
593 template<typename Derived
, typename T
>
596 typedef T element_type
;
598 // typedefs for iterator_traits
599 typedef T value_type
;
600 typedef std::ptrdiff_t difference_type
;
601 typedef std::random_access_iterator_tag iterator_category
;
602 typedef Derived pointer
;
603 typedef T
& reference
;
607 explicit PointerBase(T
* p
= nullptr) : value(p
) { }
609 PointerBase(std::nullptr_t
) : value(nullptr) { }
611 template<typename D
, typename U
,
612 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
613 PointerBase(const PointerBase
<D
, U
>& p
) : value(p
.value
) { }
615 T
& operator*() const { return *value
; }
616 T
* operator->() const { return value
; }
617 T
& operator[](difference_type n
) const { return value
[n
]; }
619 Derived
& operator++() { ++value
; return derived(); }
620 Derived
operator++(int) { Derived
tmp(derived()); ++value
; return tmp
; }
621 Derived
& operator--() { --value
; return derived(); }
622 Derived
operator--(int) { Derived
tmp(derived()); --value
; return tmp
; }
624 Derived
& operator+=(difference_type n
) { value
+= n
; return derived(); }
625 Derived
& operator-=(difference_type n
) { value
-= n
; return derived(); }
627 explicit operator bool() const { return value
!= nullptr; }
630 operator+(difference_type n
) const
632 Derived
p(derived());
637 operator-(difference_type n
) const
639 Derived
p(derived());
645 derived() { return static_cast<Derived
&>(*this); }
648 derived() const { return static_cast<const Derived
&>(*this); }
651 template<typename D
, typename T
>
652 std::ptrdiff_t 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 template<typename D
, typename T
>
660 bool operator!=(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
661 { return l
.value
!= r
.value
; }
663 // implementation for void specializations
665 struct PointerBase_void
667 typedef T element_type
;
669 // typedefs for iterator_traits
670 typedef T value_type
;
671 typedef std::ptrdiff_t difference_type
;
672 typedef std::random_access_iterator_tag iterator_category
;
676 explicit PointerBase_void(T
* p
= nullptr) : value(p
) { }
678 template<typename D
, typename U
,
679 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
680 PointerBase_void(const PointerBase
<D
, U
>& p
) : value(p
.value
) { }
682 explicit operator bool() const { return value
!= nullptr; }
685 template<typename Derived
>
686 struct PointerBase
<Derived
, void> : PointerBase_void
<void>
688 using PointerBase_void::PointerBase_void
;
689 typedef Derived pointer
;
692 template<typename Derived
>
693 struct PointerBase
<Derived
, const void> : PointerBase_void
<const void>
695 using PointerBase_void::PointerBase_void
;
696 typedef Derived pointer
;
700 #if __cplusplus >= 201703L
701 #if __cpp_aligned_new && __cpp_rtti
702 // A concrete memory_resource, with error checking.
703 class memory_resource
: public std::pmr::memory_resource
707 : lists(new allocation_lists
)
710 memory_resource(const memory_resource
& r
) noexcept
712 { lists
->refcount
++; }
714 memory_resource
& operator=(const memory_resource
&) = delete;
718 if (lists
->refcount
-- == 1)
719 delete lists
; // last one out turns out the lights
723 struct bad_alignment
{ };
724 struct bad_address
{ };
726 // Deallocate everything (moving the tracking info to the freed list)
728 deallocate_everything()
730 while (lists
->active
)
732 auto a
= lists
->active
;
733 // Intentionally virtual dispatch, to inform derived classes:
734 this->do_deallocate(a
->p
, a
->bytes
, a
->alignment
);
738 // Clear the freed list
740 forget_freed_allocations()
741 { lists
->forget_allocations(lists
->freed
); }
743 // Count how many allocations have been done and not freed.
745 number_of_active_allocations() const noexcept
748 for (auto a
= lists
->active
; a
!= nullptr; a
= a
->next
)
755 do_allocate(std::size_t bytes
, std::size_t alignment
) override
757 // TODO perform a single allocation and put the allocation struct
758 // in the buffer using placement new? It means deallocation won't
759 // actually return memory to the OS, as it will stay in lists->freed.
761 // TODO adjust the returned pointer to be minimally aligned?
762 // e.g. if alignment==1 don't return something aligned to 2 bytes.
763 // Maybe not worth it, at least monotonic_buffer_resource will
764 // never ask upstream for anything with small alignment.
765 void* p
= ::operator new(bytes
, std::align_val_t(alignment
));
766 lists
->active
= new allocation
{p
, bytes
, alignment
, lists
->active
};
771 do_deallocate(void* p
, std::size_t bytes
, std::size_t alignment
) override
773 allocation
** aptr
= &lists
->active
;
776 allocation
* a
= *aptr
;
779 if (bytes
!= a
->bytes
)
781 if (alignment
!= a
->alignment
)
782 throw bad_alignment();
783 ::operator delete(p
, bytes
, std::align_val_t(alignment
));
785 a
->next
= lists
->freed
;
795 do_is_equal(const std::pmr::memory_resource
& r
) const noexcept override
797 // Equality is determined by sharing the same allocation_lists object.
798 if (auto p
= dynamic_cast<const memory_resource
*>(&r
))
799 return p
->lists
== lists
;
808 std::size_t alignment
;
812 // Maintain list of allocated blocks and list of freed blocks.
813 // Copies of this memory_resource share the same ref-counted lists.
814 struct allocation_lists
816 unsigned refcount
= 1;
817 allocation
* active
= nullptr;
818 allocation
* freed
= nullptr;
820 void forget_allocations(allocation
*& list
)
832 forget_allocations(active
); // Anything in this list is a leak!
833 forget_allocations(freed
);
837 allocation_lists
* lists
;
839 #endif // aligned-new && rtti
841 // Set the default resource, and restore the previous one on destruction.
842 struct default_resource_mgr
844 explicit default_resource_mgr(std::pmr::memory_resource
* r
)
845 : prev(std::pmr::set_default_resource(r
))
848 ~default_resource_mgr()
849 { std::pmr::set_default_resource(prev
); }
851 std::pmr::memory_resource
* prev
;
856 } // namespace __gnu_test
858 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H