2018-03-08 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libstdc++-v3 / testsuite / util / testsuite_allocator.h
blob501a81f2276d3c4b61c606ade13f2abf4c1ca97f
1 // -*- C++ -*-
2 // Testing allocator for the C++ library testsuite.
3 //
4 // Copyright (C) 2002-2018 Free Software Foundation, Inc.
5 //
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)
10 // any later version.
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>
35 namespace __gnu_test
37 class tracker_allocator_counter
39 public:
40 typedef std::size_t size_type;
42 static void
43 allocate(size_type blocksize)
44 { allocationCount_ += blocksize; }
46 static void
47 construct() { ++constructCount_; }
49 static void
50 destroy() { ++destructCount_; }
52 static void
53 deallocate(size_type blocksize)
54 { deallocationCount_ += blocksize; }
56 static size_type
57 get_allocation_count() { return allocationCount_; }
59 static size_type
60 get_deallocation_count() { return deallocationCount_; }
62 static int
63 get_construct_count() { return constructCount_; }
65 static int
66 get_destruct_count() { return destructCount_; }
68 static void
69 reset()
71 allocationCount_ = 0;
72 deallocationCount_ = 0;
73 constructCount_ = 0;
74 destructCount_ = 0;
77 private:
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
100 private:
101 typedef tracker_allocator_counter counter_type;
103 typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
105 public:
106 typedef typename
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;
111 template<class U>
112 struct rebind
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)...)
130 #else
131 tracker_allocator()
134 tracker_allocator(const tracker_allocator&)
137 ~tracker_allocator()
139 #endif
141 template<class U>
142 tracker_allocator(const tracker_allocator<U,
143 typename AllocTraits::template rebind<U>::other>& alloc)
144 _GLIBCXX_USE_NOEXCEPT
145 : Alloc(alloc)
148 pointer
149 allocate(size_type n, const void* = 0)
151 pointer p = AllocTraits::allocate(*this, n);
152 counter_type::allocate(n * sizeof(T));
153 return p;
156 #if __cplusplus >= 201103L
157 template<typename U, typename... Args>
158 void
159 construct(U* p, Args&&... args)
161 AllocTraits::construct(*this, p, std::forward<Args>(args)...);
162 counter_type::construct();
165 template<typename U>
166 void
167 destroy(U* p)
169 AllocTraits::destroy(*this, p);
170 counter_type::destroy();
172 #else
173 void
174 construct(pointer p, const T& value)
176 AllocTraits::construct(*this, p, value);
177 counter_type::construct();
180 void
181 destroy(pointer p)
183 AllocTraits::destroy(*this, p);
184 counter_type::destroy();
186 #endif
188 void
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.
196 friend inline void
197 swap(tracker_allocator& a, tracker_allocator& b)
199 using std::swap;
201 Alloc& aa = a;
202 Alloc& ab = b;
203 swap(aa, ab);
207 template<class T1, class Alloc1, class T2, class Alloc2>
208 bool
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>
218 bool
219 operator!=(const tracker_allocator<T1, Alloc1>& lhs,
220 const tracker_allocator<T2, Alloc2>& rhs) throw()
221 { return !(lhs == rhs); }
223 bool
224 check_construct_destroy(const char* tag, int expected_c, int expected_d);
226 template<typename Alloc>
227 bool
228 check_deallocate_null()
230 // Let's not core here...
231 Alloc a;
232 a.deallocate(0, 1);
233 a.deallocate(0, 10);
234 return true;
237 template<typename Alloc>
238 bool
239 check_allocate_max_size()
241 Alloc a;
244 a.allocate(a.max_size() + 1);
246 catch(std::bad_alloc&)
248 return true;
250 catch(...)
252 throw;
254 throw;
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
265 // (see N1599).
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.
273 static map_type&
274 get_map()
276 static map_type alloc_map;
277 return alloc_map;
281 template<typename Tp, typename Alloc = std::allocator<Tp> >
282 class uneq_allocator
283 : private uneq_allocator_base,
284 public Alloc
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()); }
292 public:
293 typedef typename check_consistent_alloc_value_type<Tp, Alloc>::value_type
294 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;
301 #endif
303 template<typename Tp1>
304 struct rebind
306 typedef uneq_allocator<Tp1,
307 typename AllocTraits::template rebind<Tp1>::other> other;
310 uneq_allocator() _GLIBCXX_USE_NOEXCEPT
311 : personality(0) { }
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;
319 #endif
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; }
332 pointer
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),
340 personality));
342 catch(...)
344 AllocTraits::deallocate(*this, p, n);
345 __throw_exception_again;
348 return p;
351 void
352 deallocate(pointer p, size_type n)
354 VERIFY( p );
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 );
363 get_map().erase(it);
364 AllocTraits::deallocate(*this, p, n);
367 #if __cplusplus >= 201103L
368 // Not copy assignable...
369 uneq_allocator&
370 operator=(const uneq_allocator&) = delete;
372 // ... but still moveable if base allocator is.
373 uneq_allocator&
374 operator=(uneq_allocator&&) = default;
375 #else
376 private:
377 // Not assignable...
378 uneq_allocator&
379 operator=(const uneq_allocator&);
380 #endif
382 private:
383 // ... yet swappable!
384 friend inline void
385 swap(uneq_allocator& a, uneq_allocator& b)
387 std::swap(a.personality, b.personality);
388 a.swap_base(b);
391 template<typename Tp1>
392 friend inline bool
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>
399 friend inline bool
400 operator!=(const uneq_allocator& a,
401 const uneq_allocator<Tp1,
402 typename AllocTraits::template rebind<Tp1>::other>& b)
403 { return !(a == b); }
405 int personality;
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;
422 public:
423 // default allocator_traits::rebind_alloc would select
424 // uneq_allocator::rebind so we must define rebind here
425 template<typename Up>
426 struct rebind
428 typedef propagating_allocator<Up, Propagate,
429 typename AllocTraits::template rebind<Up>::other> other;
432 propagating_allocator(int i) noexcept
433 : base_alloc(i)
436 template<typename Up>
437 propagating_allocator(const propagating_allocator<Up, Propagate,
438 typename AllocTraits::template rebind<Up>::other>& a)
439 noexcept
440 : base_alloc(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);
452 return *this;
455 template<bool P2>
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);
461 return *this;
464 // postcondition: a.get_personality() == 0
465 propagating_allocator(propagating_allocator&& a) noexcept
466 : base_alloc()
467 { swap_base(a); }
469 // postcondition: a.get_personality() == 0
470 propagating_allocator&
471 operator=(propagating_allocator&& a) noexcept
473 propagating_allocator(std::move(a)).swap_base(*this);
474 return *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]
487 template <class Tp>
488 struct SimpleAllocator
490 typedef Tp value_type;
492 SimpleAllocator() noexcept { }
494 template <class T>
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>&)
506 { return true; }
507 template <class T, class U>
508 bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&)
509 { return false; }
511 template<typename T>
512 struct default_init_allocator
514 using value_type = T;
516 default_init_allocator() = default;
518 template<typename U>
519 default_init_allocator(const default_init_allocator<U>& a)
520 : state(a.state)
524 allocate(std::size_t n)
525 { return std::allocator<T>().allocate(n); }
527 void
528 deallocate(T* p, std::size_t n)
529 { std::allocator<T>().deallocate(p, n); }
531 int state;
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); }
543 #endif
545 template<typename Tp>
546 struct ExplicitConsAlloc : std::allocator<Tp>
548 ExplicitConsAlloc() { }
550 template<typename Up>
551 explicit
552 ExplicitConsAlloc(const ExplicitConsAlloc<Up>&) { }
554 template<typename Up>
555 struct rebind
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>;
566 public:
567 CustomPointerAlloc() = default;
569 template<typename Up>
570 CustomPointerAlloc(const CustomPointerAlloc<Up>&) { }
572 template<typename Up>
573 struct rebind
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>
590 struct PointerBase
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;
601 T* value;
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; }
625 Derived
626 operator+(difference_type n) const
628 Derived p(derived());
629 return p += n;
632 Derived
633 operator-(difference_type n) const
635 Derived p(derived());
636 return p -= n;
639 private:
640 Derived&
641 derived() { return static_cast<Derived&>(*this); }
643 const Derived&
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
660 template<typename T>
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;
670 T* value;
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;
694 #endif
696 } // namespace __gnu_test
698 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H