2 // Testing allocator for the C++ library testsuite.
4 // Copyright (C) 2002-2025 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 <bits/move.h>
30 #include <ext/pointer.h>
31 #include <ext/alloc_traits.h>
32 #include <testsuite_hooks.h>
33 #if __cplusplus >= 201703L
34 # include <memory_resource>
38 #if __cplusplus >= 201103L
39 # include <unordered_map>
40 namespace unord
= std
;
42 # include <tr1/unordered_map>
43 namespace unord
= std::tr1
;
48 // A common API for calling max_size() on an allocator in any -std mode.
53 #if __cplusplus >= 201103L
54 return std::allocator_traits
<A
>::max_size(a
);
60 class tracker_allocator_counter
63 typedef std::size_t size_type
;
66 allocate(size_type blocksize
)
67 { allocationCount_
+= blocksize
; }
70 construct() { ++constructCount_
; }
73 destroy() { ++destructCount_
; }
76 deallocate(size_type blocksize
)
77 { deallocationCount_
+= blocksize
; }
80 get_allocation_count() { return allocationCount_
; }
83 get_deallocation_count() { return deallocationCount_
; }
86 get_construct_count() { return constructCount_
; }
89 get_destruct_count() { return destructCount_
; }
95 deallocationCount_
= 0;
101 static size_type allocationCount_
;
102 static size_type deallocationCount_
;
103 static int constructCount_
;
104 static int destructCount_
;
107 // Helper to detect inconsistency between type used to instantiate an
108 // allocator and the underlying allocator value_type.
109 template<typename T
, typename Alloc
,
110 typename
= typename
Alloc::value_type
>
111 struct check_consistent_alloc_value_type
;
113 template<typename T
, typename Alloc
>
114 struct check_consistent_alloc_value_type
<T
, Alloc
, T
>
115 { typedef T value_type
; };
117 // An allocator facade that intercepts allocate/deallocate/construct/destroy
118 // calls and track them through the tracker_allocator_counter class. This
119 // class is templated on the target object type, but tracker isn't.
120 template<typename T
, typename Alloc
= std::allocator
<T
> >
121 class tracker_allocator
: public Alloc
124 typedef tracker_allocator_counter counter_type
;
126 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
130 check_consistent_alloc_value_type
<T
, Alloc
>::value_type value_type
;
131 typedef typename
AllocTraits::pointer pointer
;
132 typedef typename
AllocTraits::size_type size_type
;
137 typedef tracker_allocator
<U
,
138 typename
AllocTraits::template rebind
<U
>::other
> other
;
141 #if __cplusplus >= 201103L
142 tracker_allocator() = default;
143 tracker_allocator(const tracker_allocator
&) = default;
144 tracker_allocator(tracker_allocator
&&) = default;
145 tracker_allocator
& operator=(const tracker_allocator
&) = default;
146 tracker_allocator
& operator=(tracker_allocator
&&) = default;
148 // Perfect forwarding constructor.
149 template<typename
... _Args
>
150 tracker_allocator(_Args
&&... __args
)
151 : Alloc(std::forward
<_Args
>(__args
)...)
157 tracker_allocator(const tracker_allocator
& a
) : Alloc(a
)
165 tracker_allocator(const tracker_allocator
<U
,
166 typename
AllocTraits::template rebind
<U
>::other
>& alloc
)
167 _GLIBCXX_USE_NOEXCEPT
172 allocate(size_type n
, const void* = 0)
174 pointer p
= AllocTraits::allocate(*this, n
);
175 counter_type::allocate(n
* sizeof(T
));
179 #if __cplusplus >= 201103L
180 template<typename U
, typename
... Args
>
182 construct(U
* p
, Args
&&... args
)
184 AllocTraits::construct(*this, p
, std::forward
<Args
>(args
)...);
185 counter_type::construct();
192 AllocTraits::destroy(*this, p
);
193 counter_type::destroy();
197 construct(pointer p
, const T
& value
)
199 AllocTraits::construct(*this, p
, value
);
200 counter_type::construct();
206 AllocTraits::destroy(*this, p
);
207 counter_type::destroy();
212 deallocate(pointer p
, size_type num
)
214 counter_type::deallocate(num
* sizeof(T
));
215 AllocTraits::deallocate(*this, p
, num
);
218 // Implement swap for underlying allocators that might need it.
220 swap(tracker_allocator
& a
, tracker_allocator
& b
)
230 template<class T1
, class Alloc1
, class T2
, class Alloc2
>
232 operator==(const tracker_allocator
<T1
, Alloc1
>& lhs
,
233 const tracker_allocator
<T2
, Alloc2
>& rhs
) throw()
235 const Alloc1
& alloc1
= lhs
;
236 const Alloc2
& alloc2
= rhs
;
237 return alloc1
== alloc2
;
240 template<class T1
, class Alloc1
, class T2
, class Alloc2
>
242 operator!=(const tracker_allocator
<T1
, Alloc1
>& lhs
,
243 const tracker_allocator
<T2
, Alloc2
>& rhs
) throw()
244 { return !(lhs
== rhs
); }
247 check_construct_destroy(const char* tag
, int expected_c
, int expected_d
);
249 template<typename Alloc
>
251 check_deallocate_null()
253 // Let's not core here...
261 template<typename Alloc
>
263 check_allocate_max_size()
268 (void) a
.allocate(__gnu_test::max_size(a
) + 1);
270 catch(std::bad_alloc
&)
282 // A simple allocator which can be constructed endowed of a given
283 // "personality" (an integer), queried in operator== to simulate the
284 // behavior of realworld "unequal" allocators (i.e., not exploiting
285 // the provision in 20.1.5/4, first bullet). A global unordered_map,
286 // filled at allocation time with (pointer, personality) pairs, is
287 // then consulted to enforce the requirements in Table 32 about
288 // deallocation vs allocator equality. Note that this allocator is
289 // swappable, not copy assignable, consistently with Option 3 of DR 431
291 struct uneq_allocator_base
293 typedef unord::unordered_map
<void*, int> map_type
;
295 // Avoid static initialization troubles and/or bad interactions
296 // with tests linking testsuite_allocator.o and playing globally
297 // with operator new/delete.
301 static map_type alloc_map
;
306 template<typename Tp
, typename Alloc
= std::allocator
<Tp
> >
308 : private uneq_allocator_base
,
311 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
313 Alloc
& base() { return *this; }
314 const Alloc
& base() const { return *this; }
315 void swap_base(Alloc
& b
) { using std::swap
; swap(b
, this->base()); }
318 typedef typename check_consistent_alloc_value_type
<Tp
, Alloc
>::value_type
320 typedef typename
AllocTraits::size_type size_type
;
321 typedef typename
AllocTraits::pointer pointer
;
323 #if __cplusplus >= 201103L
324 typedef std::true_type propagate_on_container_swap
;
325 typedef std::false_type is_always_equal
;
328 template<typename Tp1
>
331 typedef uneq_allocator
<Tp1
,
332 typename
AllocTraits::template rebind
<Tp1
>::other
> other
;
335 uneq_allocator() _GLIBCXX_USE_NOEXCEPT
338 uneq_allocator(int person
) _GLIBCXX_USE_NOEXCEPT
339 : personality(person
) { }
341 #if __cplusplus >= 201103L
342 uneq_allocator(const uneq_allocator
&) = default;
343 uneq_allocator(uneq_allocator
&&) = default;
346 template<typename Tp1
>
347 uneq_allocator(const uneq_allocator
<Tp1
,
348 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
349 _GLIBCXX_USE_NOEXCEPT
350 : personality(b
.get_personality()) { }
352 ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
355 int get_personality() const { return personality
; }
358 allocate(size_type n
, const void* = 0)
360 pointer p
= AllocTraits::allocate(*this, n
);
364 get_map().insert(map_type::value_type(reinterpret_cast<void*>(p
),
369 AllocTraits::deallocate(*this, p
, n
);
370 __throw_exception_again
;
377 deallocate(pointer p
, size_type n
)
381 map_type::iterator it
= get_map().find(reinterpret_cast<void*>(p
));
382 VERIFY( it
!= get_map().end() );
384 // Enforce requirements in Table 32 about deallocation vs
385 // allocator equality.
386 VERIFY( it
->second
== personality
);
389 AllocTraits::deallocate(*this, p
, n
);
392 #if __cplusplus >= 201103L
393 // Not copy assignable...
395 operator=(const uneq_allocator
&) = delete;
397 // ... but still moveable if base allocator is.
399 operator=(uneq_allocator
&&) = default;
404 operator=(const uneq_allocator
&);
408 // ... yet swappable!
410 swap(uneq_allocator
& a
, uneq_allocator
& b
)
412 std::swap(a
.personality
, b
.personality
);
416 template<typename Tp1
>
418 operator==(const uneq_allocator
& a
,
419 const uneq_allocator
<Tp1
,
420 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
421 { return a
.personality
== b
.get_personality(); }
423 template<typename Tp1
>
425 operator!=(const uneq_allocator
& a
,
426 const uneq_allocator
<Tp1
,
427 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
428 { return !(a
== b
); }
433 #if __cplusplus >= 201103L
434 // An uneq_allocator which can be used to test allocator propagation.
435 template<typename Tp
, bool Propagate
, typename Alloc
= std::allocator
<Tp
>>
436 class propagating_allocator
: public uneq_allocator
<Tp
, Alloc
>
438 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
440 typedef uneq_allocator
<Tp
, Alloc
> base_alloc
;
441 base_alloc
& base() { return *this; }
442 const base_alloc
& base() const { return *this; }
443 void swap_base(base_alloc
& b
) { swap(b
, this->base()); }
445 typedef std::integral_constant
<bool, Propagate
> trait_type
;
448 // default allocator_traits::rebind_alloc would select
449 // uneq_allocator::rebind so we must define rebind here
450 template<typename Up
>
453 typedef propagating_allocator
<Up
, Propagate
,
454 typename
AllocTraits::template rebind
<Up
>::other
> other
;
457 propagating_allocator(int i
) noexcept
461 template<typename Up
>
462 propagating_allocator(const propagating_allocator
<Up
, Propagate
,
463 typename
AllocTraits::template rebind
<Up
>::other
>& a
)
468 propagating_allocator() noexcept
= default;
470 propagating_allocator(const propagating_allocator
&) noexcept
= default;
472 propagating_allocator
&
473 operator=(const propagating_allocator
& a
) noexcept
475 static_assert(Propagate
, "assigning propagating_allocator<T, true>");
476 propagating_allocator(a
).swap_base(*this);
481 propagating_allocator
&
482 operator=(const propagating_allocator
<Tp
, P2
, Alloc
>& a
) noexcept
484 static_assert(P2
, "assigning propagating_allocator<T, true>");
485 propagating_allocator(a
).swap_base(*this);
489 // postcondition: LWG2593 a.get_personality() un-changed.
490 propagating_allocator(propagating_allocator
&& a
) noexcept
491 : base_alloc(std::move(a
.base()))
494 // postcondition: LWG2593 a.get_personality() un-changed
495 propagating_allocator
&
496 operator=(propagating_allocator
&& a
) noexcept
498 propagating_allocator(std::move(a
)).swap_base(*this);
502 typedef trait_type propagate_on_container_copy_assignment
;
503 typedef trait_type propagate_on_container_move_assignment
;
504 typedef trait_type propagate_on_container_swap
;
506 propagating_allocator
select_on_container_copy_construction() const
507 { return Propagate
? *this : propagating_allocator(); }
510 // Class template supporting the minimal interface that satisfies the
511 // Allocator requirements, from example in [allocator.requirements]
513 struct SimpleAllocator
515 typedef Tp value_type
;
517 constexpr SimpleAllocator() noexcept
{ }
520 SimpleAllocator(const SimpleAllocator
<T
>&) { }
522 Tp
*allocate(std::size_t n
)
523 { return std::allocator
<Tp
>().allocate(n
); }
525 void deallocate(Tp
*p
, std::size_t n
)
526 { std::allocator
<Tp
>().deallocate(p
, n
); }
529 template <class T
, class U
>
530 bool operator==(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
532 template <class T
, class U
>
533 bool operator!=(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
537 struct default_init_allocator
539 using value_type
= T
;
541 default_init_allocator() = default;
544 default_init_allocator(const default_init_allocator
<U
>& a
)
549 allocate(std::size_t n
)
550 { return std::allocator
<T
>().allocate(n
); }
553 deallocate(T
* p
, std::size_t n
)
554 { std::allocator
<T
>().deallocate(p
, n
); }
559 template<typename T
, typename U
>
560 bool operator==(const default_init_allocator
<T
>& t
,
561 const default_init_allocator
<U
>& u
)
562 { return t
.state
== u
.state
; }
564 template<typename T
, typename U
>
565 bool operator!=(const default_init_allocator
<T
>& t
,
566 const default_init_allocator
<U
>& u
)
567 { return !(t
== u
); }
570 template<typename Tp
>
571 struct ExplicitConsAlloc
: std::allocator
<Tp
>
573 ExplicitConsAlloc() { }
575 template<typename Up
>
577 ExplicitConsAlloc(const ExplicitConsAlloc
<Up
>&) { }
579 template<typename Up
>
581 { typedef ExplicitConsAlloc
<Up
> other
; };
584 #if __cplusplus >= 201103L
585 template<typename Tp
>
586 class CustomPointerAlloc
: public std::allocator
<Tp
>
588 template<typename Up
, typename Sp
= __gnu_cxx::_Std_pointer_impl
<Up
>>
589 using Ptr
= __gnu_cxx::_Pointer_adapter
<Sp
>;
592 CustomPointerAlloc() = default;
594 template<typename Up
>
595 CustomPointerAlloc(const CustomPointerAlloc
<Up
>&) { }
597 template<typename Up
>
599 { typedef CustomPointerAlloc
<Up
> other
; };
601 typedef Ptr
<Tp
> pointer
;
602 typedef Ptr
<const Tp
> const_pointer
;
603 typedef Ptr
<void> void_pointer
;
604 typedef Ptr
<const void> const_void_pointer
;
606 pointer
allocate(std::size_t n
, const_void_pointer
= {})
607 { return pointer(std::allocator
<Tp
>::allocate(n
)); }
609 void deallocate(pointer p
, std::size_t n
)
610 { std::allocator
<Tp
>::deallocate(std::addressof(*p
), n
); }
613 // A class type meeting *only* the Cpp17NullablePointer requirements.
614 // Can be used as a base class for fancy pointers (like PointerBase, below)
615 // or to wrap a built-in pointer type to remove operations not required
616 // by the Cpp17NullablePointer requirements (dereference, increment etc.)
617 template<typename Ptr
>
618 struct NullablePointer
620 // N.B. default constructor does not initialize value
621 NullablePointer() = default;
622 NullablePointer(std::nullptr_t
) noexcept
: value() { }
624 explicit operator bool() const noexcept
{ return value
!= nullptr; }
627 operator==(NullablePointer lhs
, NullablePointer rhs
) noexcept
628 { return lhs
.value
== rhs
.value
; }
631 operator!=(NullablePointer lhs
, NullablePointer rhs
) noexcept
632 { return lhs
.value
!= rhs
.value
; }
635 explicit NullablePointer(Ptr p
) noexcept
: value(p
) { }
639 // NullablePointer<void> is an empty type that models Cpp17NullablePointer.
641 struct NullablePointer
<void>
643 NullablePointer() = default;
644 NullablePointer(std::nullptr_t
) noexcept
{ }
645 explicit NullablePointer(const volatile void*) noexcept
{ }
647 explicit operator bool() const noexcept
{ return false; }
650 operator==(NullablePointer
, NullablePointer
) noexcept
654 operator!=(NullablePointer
, NullablePointer
) noexcept
658 // Utility for use as CRTP base class of custom pointer types
659 template<typename Derived
, typename T
>
660 struct PointerBase
: NullablePointer
<T
*>
662 typedef T element_type
;
664 // typedefs for iterator_traits
665 typedef T value_type
;
666 typedef std::ptrdiff_t difference_type
;
667 typedef std::random_access_iterator_tag iterator_category
;
668 typedef Derived pointer
;
669 typedef T
& reference
;
671 using NullablePointer
<T
*>::NullablePointer
;
673 // Public (but explicit) constructor from raw pointer:
674 explicit PointerBase(T
* p
) noexcept
: NullablePointer
<T
*>(p
) { }
676 template<typename D
, typename U
,
677 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
678 PointerBase(const PointerBase
<D
, U
>& p
)
679 : NullablePointer
<T
*>(p
.operator->()) { }
681 T
& operator*() const { return *this->value
; }
682 T
* operator->() const { return this->value
; }
683 T
& operator[](difference_type n
) const { return this->value
[n
]; }
685 Derived
& operator++() { ++this->value
; return derived(); }
686 Derived
& operator--() { --this->value
; return derived(); }
688 Derived
operator++(int) { return Derived(this->value
++); }
690 Derived
operator--(int) { return Derived(this->value
--); }
692 Derived
& operator+=(difference_type n
)
698 Derived
& operator-=(difference_type n
)
705 operator+(difference_type n
) const
707 Derived
p(derived());
712 operator-(difference_type n
) const
714 Derived
p(derived());
719 friend std::ptrdiff_t operator-(PointerBase l
, PointerBase r
)
720 { return l
.value
- r
.value
; }
722 friend bool operator<(PointerBase l
, PointerBase r
)
723 { return l
.value
< r
.value
; }
724 friend bool operator>(PointerBase l
, PointerBase r
)
725 { return l
.value
> r
.value
; }
726 friend bool operator<=(PointerBase l
, PointerBase r
)
727 { return l
.value
<= r
.value
; }
728 friend bool operator>=(PointerBase l
, PointerBase r
)
729 { return l
.value
>= r
.value
; }
732 derived() { return static_cast<Derived
&>(*this); }
735 derived() const { return static_cast<const Derived
&>(*this); }
738 // implementation for pointer-to-void specializations
740 struct PointerBase_void
: NullablePointer
<T
*>
742 typedef T element_type
;
744 // typedefs for iterator_traits
745 typedef T value_type
;
746 typedef std::ptrdiff_t difference_type
;
747 typedef std::random_access_iterator_tag iterator_category
;
749 using NullablePointer
<T
*>::NullablePointer
;
751 T
* operator->() const { return this->value
; }
753 template<typename D
, typename U
,
754 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
755 PointerBase_void(const PointerBase
<D
, U
>& p
)
756 : NullablePointer
<T
*>(p
.operator->()) { }
759 template<typename Derived
>
760 struct PointerBase
<Derived
, void> : PointerBase_void
<void>
762 using PointerBase_void::PointerBase_void
;
763 typedef Derived pointer
;
766 template<typename Derived
>
767 struct PointerBase
<Derived
, const void> : PointerBase_void
<const void>
769 using PointerBase_void::PointerBase_void
;
770 typedef Derived pointer
;
774 #if __cplusplus >= 201703L
775 #if __cpp_aligned_new
776 // A concrete memory_resource, with error checking.
777 class memory_resource
: public std::pmr::memory_resource
781 : lists(new allocation_lists
)
784 memory_resource(const memory_resource
& r
) noexcept
786 { lists
->refcount
++; }
788 memory_resource
& operator=(const memory_resource
&) = delete;
792 if (lists
->refcount
-- == 1)
793 delete lists
; // last one out turns out the lights
797 struct bad_alignment
{ };
798 struct bad_address
{ };
800 // Deallocate everything (moving the tracking info to the freed list)
802 deallocate_everything()
804 while (lists
->active
)
806 auto a
= lists
->active
;
807 // Intentionally virtual dispatch, to inform derived classes:
808 this->do_deallocate(a
->p
, a
->bytes
, a
->alignment
);
812 // Clear the freed list
814 forget_freed_allocations()
815 { lists
->forget_allocations(lists
->freed
); }
817 // Count how many allocations have been done and not freed.
819 number_of_active_allocations() const noexcept
822 for (auto a
= lists
->active
; a
!= nullptr; a
= a
->next
)
829 do_allocate(std::size_t bytes
, std::size_t alignment
) override
831 // TODO perform a single allocation and put the allocation struct
832 // in the buffer using placement new? It means deallocation won't
833 // actually return memory to the OS, as it will stay in lists->freed.
835 // TODO adjust the returned pointer to be minimally aligned?
836 // e.g. if alignment==1 don't return something aligned to 2 bytes.
837 // Maybe not worth it, at least monotonic_buffer_resource will
838 // never ask upstream for anything with small alignment.
839 void* p
= ::operator new(bytes
, std::align_val_t(alignment
));
840 lists
->active
= new allocation
{p
, bytes
, alignment
, lists
->active
};
845 do_deallocate(void* p
, std::size_t bytes
, std::size_t alignment
) override
847 allocation
** aptr
= &lists
->active
;
850 allocation
* a
= *aptr
;
853 if (bytes
!= a
->bytes
)
854 _S_throw
<bad_size
>();
855 if (alignment
!= a
->alignment
)
856 _S_throw
<bad_alignment
>();
857 #if __cpp_sized_deallocation
858 ::operator delete(p
, bytes
, std::align_val_t(alignment
));
860 ::operator delete(p
, std::align_val_t(alignment
));
863 a
->next
= lists
->freed
;
869 _S_throw
<bad_address
>();
873 do_is_equal(const std::pmr::memory_resource
& r
) const noexcept override
876 // Equality is determined by sharing the same allocation_lists object.
877 if (auto p
= dynamic_cast<const memory_resource
*>(&r
))
878 return p
->lists
== lists
;
880 if (this == &r
) // Is this the best we can do without RTTI?
902 std::size_t alignment
;
906 // Maintain list of allocated blocks and list of freed blocks.
907 // Copies of this memory_resource share the same ref-counted lists.
908 struct allocation_lists
910 unsigned refcount
= 1;
911 allocation
* active
= nullptr;
912 allocation
* freed
= nullptr;
914 void forget_allocations(allocation
*& list
)
926 forget_allocations(active
); // Anything in this list is a leak!
927 forget_allocations(freed
);
931 allocation_lists
* lists
;
933 #endif // aligned-new
935 // Set the default resource, and restore the previous one on destruction.
936 struct default_resource_mgr
938 explicit default_resource_mgr(std::pmr::memory_resource
* r
)
939 : prev(std::pmr::set_default_resource(r
))
942 ~default_resource_mgr()
943 { std::pmr::set_default_resource(prev
); }
945 std::pmr::memory_resource
* prev
;
950 } // namespace __gnu_test
952 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H