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 <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;
123 // Perfect forwarding constructor.
124 template<typename
... _Args
>
125 tracker_allocator(_Args
&&... __args
)
126 : Alloc(std::forward
<_Args
>(__args
)...)
132 tracker_allocator(const tracker_allocator
&)
140 tracker_allocator(const tracker_allocator
<U
,
141 typename
AllocTraits::template rebind
<U
>::other
>& alloc
)
142 _GLIBCXX_USE_NOEXCEPT
147 allocate(size_type n
, const void* = 0)
149 pointer p
= AllocTraits::allocate(*this, n
);
150 counter_type::allocate(n
* sizeof(T
));
154 #if __cplusplus >= 201103L
155 template<typename U
, typename
... Args
>
157 construct(U
* p
, Args
&&... args
)
159 AllocTraits::construct(*this, p
, std::forward
<Args
>(args
)...);
160 counter_type::construct();
167 AllocTraits::destroy(*this, p
);
168 counter_type::destroy();
172 construct(pointer p
, const T
& value
)
174 AllocTraits::construct(*this, p
, value
);
175 counter_type::construct();
181 AllocTraits::destroy(*this, p
);
182 counter_type::destroy();
187 deallocate(pointer p
, size_type num
)
189 counter_type::deallocate(num
* sizeof(T
));
190 AllocTraits::deallocate(*this, p
, num
);
193 // Implement swap for underlying allocators that might need it.
195 swap(tracker_allocator
& a
, tracker_allocator
& b
)
205 template<class T1
, class Alloc1
, class T2
, class Alloc2
>
207 operator==(const tracker_allocator
<T1
, Alloc1
>& lhs
,
208 const tracker_allocator
<T2
, Alloc2
>& rhs
) throw()
210 const Alloc1
& alloc1
= lhs
;
211 const Alloc2
& alloc2
= rhs
;
215 template<class T1
, class Alloc1
, class T2
, class Alloc2
>
217 operator!=(const tracker_allocator
<T1
, Alloc1
>& lhs
,
218 const tracker_allocator
<T2
, Alloc2
>& rhs
) throw()
219 { return !(lhs
== rhs
); }
222 check_construct_destroy(const char* tag
, int expected_c
, int expected_d
);
224 template<typename Alloc
>
226 check_deallocate_null()
228 // Let's not core here...
235 template<typename Alloc
>
237 check_allocate_max_size()
242 a
.allocate(a
.max_size() + 1);
244 catch(std::bad_alloc
&)
255 // A simple allocator which can be constructed endowed of a given
256 // "personality" (an integer), queried in operator== to simulate the
257 // behavior of realworld "unequal" allocators (i.e., not exploiting
258 // the provision in 20.1.5/4, first bullet). A global unordered_map,
259 // filled at allocation time with (pointer, personality) pairs, is
260 // then consulted to enforce the requirements in Table 32 about
261 // deallocation vs allocator equality. Note that this allocator is
262 // swappable, not copy assignable, consistently with Option 3 of DR 431
264 struct uneq_allocator_base
266 typedef std::tr1::unordered_map
<void*, int> map_type
;
268 // Avoid static initialization troubles and/or bad interactions
269 // with tests linking testsuite_allocator.o and playing globally
270 // with operator new/delete.
274 static map_type alloc_map
;
279 template<typename Tp
, typename Alloc
= std::allocator
<Tp
> >
281 : private uneq_allocator_base
,
284 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
286 Alloc
& base() { return *this; }
287 const Alloc
& base() const { return *this; }
288 void swap_base(Alloc
& b
) { swap(b
, this->base()); }
291 typedef typename check_consistent_alloc_value_type
<Tp
, Alloc
>::value_type
293 typedef typename
AllocTraits::size_type size_type
;
294 typedef typename
AllocTraits::pointer pointer
;
296 #if __cplusplus >= 201103L
297 typedef std::true_type propagate_on_container_swap
;
300 template<typename Tp1
>
303 typedef uneq_allocator
<Tp1
,
304 typename
AllocTraits::template rebind
<Tp1
>::other
> other
;
307 uneq_allocator() _GLIBCXX_USE_NOEXCEPT
310 uneq_allocator(int person
) _GLIBCXX_USE_NOEXCEPT
311 : personality(person
) { }
313 #if __cplusplus >= 201103L
314 uneq_allocator(const uneq_allocator
&) = default;
315 uneq_allocator(uneq_allocator
&&) = default;
318 template<typename Tp1
>
319 uneq_allocator(const uneq_allocator
<Tp1
,
320 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
321 _GLIBCXX_USE_NOEXCEPT
322 : personality(b
.get_personality()) { }
324 ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
327 int get_personality() const { return personality
; }
330 allocate(size_type n
, const void* hint
= 0)
332 pointer p
= AllocTraits::allocate(*this, n
);
336 get_map().insert(map_type::value_type(reinterpret_cast<void*>(p
),
341 AllocTraits::deallocate(*this, p
, n
);
342 __throw_exception_again
;
349 deallocate(pointer p
, size_type n
)
351 bool test
__attribute__((unused
)) = true;
355 map_type::iterator it
= get_map().find(reinterpret_cast<void*>(p
));
356 VERIFY( it
!= get_map().end() );
358 // Enforce requirements in Table 32 about deallocation vs
359 // allocator equality.
360 VERIFY( it
->second
== personality
);
363 AllocTraits::deallocate(*this, p
, n
);
366 #if __cplusplus >= 201103L
367 // Not copy assignable...
369 operator=(const uneq_allocator
&) = delete;
371 // ... but still moveable if base allocator is.
373 operator=(uneq_allocator
&&) = default;
378 operator=(const uneq_allocator
&);
382 // ... yet swappable!
384 swap(uneq_allocator
& a
, uneq_allocator
& b
)
386 std::swap(a
.personality
, b
.personality
);
390 template<typename Tp1
>
392 operator==(const uneq_allocator
& a
,
393 const uneq_allocator
<Tp1
,
394 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
395 { return a
.personality
== b
.personality
; }
397 template<typename Tp1
>
399 operator!=(const uneq_allocator
& a
,
400 const uneq_allocator
<Tp1
,
401 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
402 { return !(a
== b
); }
407 #if __cplusplus >= 201103L
408 // An uneq_allocator which can be used to test allocator propagation.
409 template<typename Tp
, bool Propagate
, typename Alloc
= std::allocator
<Tp
>>
410 class propagating_allocator
: public uneq_allocator
<Tp
, Alloc
>
412 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
414 typedef uneq_allocator
<Tp
, Alloc
> base_alloc
;
415 base_alloc
& base() { return *this; }
416 const base_alloc
& base() const { return *this; }
417 void swap_base(base_alloc
& b
) { swap(b
, this->base()); }
419 typedef std::integral_constant
<bool, Propagate
> trait_type
;
422 // default allocator_traits::rebind_alloc would select
423 // uneq_allocator::rebind so we must define rebind here
424 template<typename Up
>
427 typedef propagating_allocator
<Up
, Propagate
,
428 typename
AllocTraits::template rebind
<Up
>::other
> other
;
431 propagating_allocator(int i
) noexcept
435 template<typename Up
>
436 propagating_allocator(const propagating_allocator
<Up
, Propagate
,
437 typename
AllocTraits::template rebind
<Up
>::other
>& a
)
442 propagating_allocator() noexcept
= default;
444 propagating_allocator(const propagating_allocator
&) noexcept
= default;
446 propagating_allocator
&
447 operator=(const propagating_allocator
& a
) noexcept
449 static_assert(Propagate
, "assigning propagating_allocator<T, true>");
450 propagating_allocator(a
).swap_base(*this);
455 propagating_allocator
&
456 operator=(const propagating_allocator
<Tp
, P2
, Alloc
>& a
) noexcept
458 static_assert(P2
, "assigning propagating_allocator<T, true>");
459 propagating_allocator(a
).swap_base(*this);
463 // postcondition: a.get_personality() == 0
464 propagating_allocator(propagating_allocator
&& a
) noexcept
468 // postcondition: a.get_personality() == 0
469 propagating_allocator
&
470 operator=(propagating_allocator
&& a
) noexcept
472 propagating_allocator(std::move(a
)).swap_base(*this);
476 typedef trait_type propagate_on_container_copy_assignment
;
477 typedef trait_type propagate_on_container_move_assignment
;
478 typedef trait_type propagate_on_container_swap
;
480 propagating_allocator
select_on_container_copy_construction() const
481 { return Propagate
? *this : propagating_allocator(); }
484 // Class template supporting the minimal interface that satisfies the
485 // Allocator requirements, from example in [allocator.requirements]
487 struct SimpleAllocator
489 typedef Tp value_type
;
491 SimpleAllocator() noexcept
{ }
494 SimpleAllocator(const SimpleAllocator
<T
>& other
) { }
496 Tp
*allocate(std::size_t n
)
497 { return std::allocator
<Tp
>().allocate(n
); }
499 void deallocate(Tp
*p
, std::size_t n
)
500 { std::allocator
<Tp
>().deallocate(p
, n
); }
503 template <class T
, class U
>
504 bool operator==(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
506 template <class T
, class U
>
507 bool operator!=(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
512 template<typename Tp
>
513 struct ExplicitConsAlloc
: std::allocator
<Tp
>
515 ExplicitConsAlloc() { }
517 template<typename Up
>
519 ExplicitConsAlloc(const ExplicitConsAlloc
<Up
>&) { }
521 template<typename Up
>
523 { typedef ExplicitConsAlloc
<Up
> other
; };
526 #if __cplusplus >= 201103L
527 template<typename Tp
>
528 class CustomPointerAlloc
: public std::allocator
<Tp
>
530 template<typename Up
, typename Sp
= __gnu_cxx::_Std_pointer_impl
<Up
>>
531 using Ptr
= __gnu_cxx::_Pointer_adapter
<Sp
>;
534 CustomPointerAlloc() = default;
536 template<typename Up
>
537 CustomPointerAlloc(const CustomPointerAlloc
<Up
>&) { }
539 template<typename Up
>
541 { typedef CustomPointerAlloc
<Up
> other
; };
543 typedef Ptr
<Tp
> pointer
;
544 typedef Ptr
<const Tp
> const_pointer
;
545 typedef Ptr
<void> void_pointer
;
546 typedef Ptr
<const void> const_void_pointer
;
548 pointer
allocate(std::size_t n
, pointer
= {})
549 { return pointer(std::allocator
<Tp
>::allocate(n
)); }
551 void deallocate(pointer p
, std::size_t n
)
552 { std::allocator
<Tp
>::deallocate(std::addressof(*p
), n
); }
555 // Utility for use as CRTP base class of custom pointer types
556 template<typename Derived
, typename T
>
559 typedef T element_type
;
561 // typedefs for iterator_traits
562 typedef T value_type
;
563 typedef std::ptrdiff_t difference_type
;
564 typedef std::random_access_iterator_tag iterator_category
;
565 typedef Derived pointer
;
566 typedef T
& reference
;
570 explicit PointerBase(T
* p
= nullptr) : value(p
) { }
572 template<typename D
, typename U
,
573 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
574 PointerBase(const PointerBase
<D
, U
>& p
) : value(p
.value
) { }
576 T
& operator*() const { return *value
; }
577 T
* operator->() const { return value
; }
579 Derived
& operator++() { ++value
; return derived(); }
580 Derived
operator++(int) { Derived
tmp(derived()); ++value
; return tmp
; }
581 Derived
& operator--() { --value
; return derived(); }
582 Derived
operator--(int) { Derived
tmp(derived()); --value
; return tmp
; }
584 Derived
& operator+=(difference_type n
) { value
+= n
; return derived(); }
585 Derived
& operator-=(difference_type n
) { value
-= n
; return derived(); }
587 explicit operator bool() const { return value
!= nullptr; }
590 operator+(difference_type n
) const
592 Derived
p(derived());
597 operator-(difference_type n
) const
599 Derived
p(derived());
604 Derived
& derived() { return static_cast<Derived
&>(*this); }
607 template<typename D
, typename T
>
608 std::ptrdiff_t operator-(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
609 { return l
.value
- r
.value
; }
611 template<typename D
, typename T
>
612 bool operator==(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
613 { return l
.value
== r
.value
; }
615 template<typename D
, typename T
>
616 bool operator!=(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
617 { return l
.value
!= r
.value
; }
619 // implementation for void specializations
621 struct PointerBase_void
623 typedef T element_type
;
625 // typedefs for iterator_traits
626 typedef T value_type
;
627 typedef std::ptrdiff_t difference_type
;
628 typedef std::random_access_iterator_tag iterator_category
;
632 explicit PointerBase_void(T
* p
= nullptr) : value(p
) { }
634 template<typename D
, typename U
,
635 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
636 PointerBase_void(const PointerBase
<D
, U
>& p
) : value(p
.value
) { }
638 explicit operator bool() const { return value
!= nullptr; }
641 template<typename Derived
>
642 struct PointerBase
<Derived
, void> : PointerBase_void
<void>
644 using PointerBase_void::PointerBase_void
;
645 typedef Derived pointer
;
648 template<typename Derived
>
649 struct PointerBase
<Derived
, const void> : PointerBase_void
<const void>
651 using PointerBase_void::PointerBase_void
;
652 typedef Derived pointer
;
656 } // namespace __gnu_test
658 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H