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 template<typename Tp1
>
314 uneq_allocator(const uneq_allocator
<Tp1
,
315 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
316 _GLIBCXX_USE_NOEXCEPT
317 : personality(b
.get_personality()) { }
319 ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
322 int get_personality() const { return personality
; }
325 allocate(size_type n
, const void* hint
= 0)
327 pointer p
= AllocTraits::allocate(*this, n
);
330 get_map().insert(map_type::value_type(reinterpret_cast<void*>(p
),
335 AllocTraits::deallocate(*this, p
, n
);
336 __throw_exception_again
;
342 deallocate(pointer p
, size_type n
)
344 bool test
__attribute__((unused
)) = true;
348 map_type::iterator it
= get_map().find(reinterpret_cast<void*>(p
));
349 VERIFY( it
!= get_map().end() );
351 // Enforce requirements in Table 32 about deallocation vs
352 // allocator equality.
353 VERIFY( it
->second
== personality
);
356 AllocTraits::deallocate(*this, p
, n
);
359 #if __cplusplus >= 201103L
360 // Not copy assignable...
362 operator=(const uneq_allocator
&) = delete;
364 // ... but still moveable if base allocator is.
366 operator=(uneq_allocator
&&) = default;
371 operator=(const uneq_allocator
&);
375 // ... yet swappable!
377 swap(uneq_allocator
& a
, uneq_allocator
& b
)
379 std::swap(a
.personality
, b
.personality
);
383 template<typename Tp1
>
385 operator==(const uneq_allocator
& a
,
386 const uneq_allocator
<Tp1
,
387 typename
AllocTraits::template rebind
<Tp1
>::other
>& b
)
388 { return 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
== b
); }
400 #if __cplusplus >= 201103L
401 // An uneq_allocator which can be used to test allocator propagation.
402 template<typename Tp
, bool Propagate
, typename Alloc
= std::allocator
<Tp
>>
403 class propagating_allocator
: public uneq_allocator
<Tp
, Alloc
>
405 typedef __gnu_cxx::__alloc_traits
<Alloc
> AllocTraits
;
407 typedef uneq_allocator
<Tp
, Alloc
> base_alloc
;
408 base_alloc
& base() { return *this; }
409 const base_alloc
& base() const { return *this; }
410 void swap_base(base_alloc
& b
) { swap(b
, this->base()); }
412 typedef std::integral_constant
<bool, Propagate
> trait_type
;
415 // default allocator_traits::rebind_alloc would select
416 // uneq_allocator::rebind so we must define rebind here
417 template<typename Up
>
420 typedef propagating_allocator
<Up
, Propagate
,
421 typename
AllocTraits::template rebind
<Up
>::other
> other
;
424 propagating_allocator(int i
) noexcept
428 template<typename Up
>
429 propagating_allocator(const propagating_allocator
<Up
, Propagate
,
430 typename
AllocTraits::template rebind
<Up
>::other
>& a
)
435 propagating_allocator() noexcept
= default;
437 propagating_allocator(const propagating_allocator
&) noexcept
= default;
439 propagating_allocator
&
440 operator=(const propagating_allocator
& a
) noexcept
442 static_assert(Propagate
, "assigning propagating_allocator<T, true>");
443 propagating_allocator(a
).swap_base(*this);
448 propagating_allocator
&
449 operator=(const propagating_allocator
<Tp
, P2
, Alloc
>& a
) noexcept
451 static_assert(P2
, "assigning propagating_allocator<T, true>");
452 propagating_allocator(a
).swap_base(*this);
456 // postcondition: a.get_personality() == 0
457 propagating_allocator(propagating_allocator
&& a
) noexcept
461 // postcondition: a.get_personality() == 0
462 propagating_allocator
&
463 operator=(propagating_allocator
&& a
) noexcept
465 propagating_allocator(std::move(a
)).swap_base(*this);
469 typedef trait_type propagate_on_container_copy_assignment
;
470 typedef trait_type propagate_on_container_move_assignment
;
471 typedef trait_type propagate_on_container_swap
;
473 propagating_allocator
select_on_container_copy_construction() const
474 { return Propagate
? *this : propagating_allocator(); }
477 // Class template supporting the minimal interface that satisfies the
478 // Allocator requirements, from example in [allocator.requirements]
480 struct SimpleAllocator
482 typedef Tp value_type
;
484 SimpleAllocator() noexcept
{ }
487 SimpleAllocator(const SimpleAllocator
<T
>& other
) { }
489 Tp
*allocate(std::size_t n
)
490 { return std::allocator
<Tp
>().allocate(n
); }
492 void deallocate(Tp
*p
, std::size_t n
)
493 { std::allocator
<Tp
>().deallocate(p
, n
); }
496 template <class T
, class U
>
497 bool operator==(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
499 template <class T
, class U
>
500 bool operator!=(const SimpleAllocator
<T
>&, const SimpleAllocator
<U
>&)
505 template<typename Tp
>
506 struct ExplicitConsAlloc
: std::allocator
<Tp
>
508 ExplicitConsAlloc() { }
510 template<typename Up
>
512 ExplicitConsAlloc(const ExplicitConsAlloc
<Up
>&) { }
514 template<typename Up
>
516 { typedef ExplicitConsAlloc
<Up
> other
; };
519 #if __cplusplus >= 201103L
520 template<typename Tp
>
521 class CustomPointerAlloc
: public std::allocator
<Tp
>
523 template<typename Up
, typename Sp
= __gnu_cxx::_Std_pointer_impl
<Up
>>
524 using Ptr
= __gnu_cxx::_Pointer_adapter
<Sp
>;
527 CustomPointerAlloc() = default;
529 template<typename Up
>
530 CustomPointerAlloc(const CustomPointerAlloc
<Up
>&) { }
532 template<typename Up
>
534 { typedef CustomPointerAlloc
<Up
> other
; };
536 typedef Ptr
<Tp
> pointer
;
537 typedef Ptr
<const Tp
> const_pointer
;
538 typedef Ptr
<void> void_pointer
;
539 typedef Ptr
<const void> const_void_pointer
;
541 pointer
allocate(std::size_t n
, pointer
= {})
542 { return pointer(std::allocator
<Tp
>::allocate(n
)); }
544 void deallocate(pointer p
, std::size_t n
)
545 { std::allocator
<Tp
>::deallocate(std::addressof(*p
), n
); }
548 // Utility for use as CRTP base class of custom pointer types
549 template<typename Derived
, typename T
>
552 typedef T element_type
;
554 // typedefs for iterator_traits
555 typedef T value_type
;
556 typedef std::ptrdiff_t difference_type
;
557 typedef std::random_access_iterator_tag iterator_category
;
558 typedef Derived pointer
;
559 typedef T
& reference
;
563 explicit PointerBase(T
* p
= nullptr) : value(p
) { }
565 template<typename D
, typename U
,
566 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
567 PointerBase(const PointerBase
<D
, U
>& p
) : value(p
.value
) { }
569 T
& operator*() const { return *value
; }
570 T
* operator->() const { return value
; }
572 Derived
& operator++() { ++value
; return derived(); }
573 Derived
operator++(int) { Derived
tmp(derived()); ++value
; return tmp
; }
574 Derived
& operator--() { --value
; return derived(); }
575 Derived
operator--(int) { Derived
tmp(derived()); --value
; return tmp
; }
577 Derived
& operator+=(difference_type n
) { value
+= n
; return derived(); }
578 Derived
& operator-=(difference_type n
) { value
-= n
; return derived(); }
580 explicit operator bool() const { return value
!= nullptr; }
583 operator+(difference_type n
) const
585 Derived
p(derived());
590 operator-(difference_type n
) const
592 Derived
p(derived());
597 Derived
& derived() { return static_cast<Derived
&>(*this); }
600 template<typename D
, typename T
>
601 std::ptrdiff_t operator-(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
602 { return l
.value
- r
.value
; }
604 template<typename D
, typename T
>
605 bool operator==(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
606 { return l
.value
== r
.value
; }
608 template<typename D
, typename T
>
609 bool operator!=(PointerBase
<D
, T
> l
, PointerBase
<D
, T
> r
)
610 { return l
.value
!= r
.value
; }
612 // implementation for void specializations
614 struct PointerBase_void
616 typedef T element_type
;
618 // typedefs for iterator_traits
619 typedef T value_type
;
620 typedef std::ptrdiff_t difference_type
;
621 typedef std::random_access_iterator_tag iterator_category
;
625 explicit PointerBase_void(T
* p
= nullptr) : value(p
) { }
627 template<typename D
, typename U
,
628 typename
= decltype(static_cast<T
*>(std::declval
<U
*>()))>
629 PointerBase_void(const PointerBase
<D
, U
>& p
) : value(p
.value
) { }
631 explicit operator bool() const { return value
!= nullptr; }
634 template<typename Derived
>
635 struct PointerBase
<Derived
, void> : PointerBase_void
<void>
637 using PointerBase_void::PointerBase_void
;
638 typedef Derived pointer
;
641 template<typename Derived
>
642 struct PointerBase
<Derived
, const void> : PointerBase_void
<const void>
644 using PointerBase_void::PointerBase_void
;
645 typedef Derived pointer
;
649 } // namespace __gnu_test
651 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H