]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/testsuite/util/testsuite_allocator.h
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / util / testsuite_allocator.h
CommitLineData
8d59b230 1// -*- C++ -*-
162c7cd9
SW
2// Testing allocator for the C++ library testsuite.
3//
818ab71a 4// Copyright (C) 2002-2016 Free Software Foundation, Inc.
162c7cd9
SW
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
748086b7 9// Free Software Foundation; either version 3, or (at your option)
162c7cd9
SW
10// any later version.
11//
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.
16//
17// You should have received a copy of the GNU General Public License along
748086b7
JJ
18// with this library; see the file COPYING3. If not see
19// <http://www.gnu.org/licenses/>.
162c7cd9 20//
162c7cd9
SW
21
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
25
3d7c150e
BK
26#ifndef _GLIBCXX_TESTSUITE_ALLOCATOR_H
27#define _GLIBCXX_TESTSUITE_ALLOCATOR_H
162c7cd9 28
31905f34 29#include <tr1/unordered_map>
ca0f8fd1 30#include <bits/move.h>
f038f582 31#include <ext/pointer.h>
5c7c5f9a 32#include <ext/alloc_traits.h>
7d9cb054 33#include <testsuite_hooks.h>
162c7cd9 34
aecf642c 35namespace __gnu_test
162c7cd9 36{
9f9900db 37 class tracker_allocator_counter
162c7cd9 38 {
8d59b230
BK
39 public:
40 typedef std::size_t size_type;
e1f3ce0d 41
5c7c5f9a 42 static void
8d59b230 43 allocate(size_type blocksize)
5c7c5f9a 44 { allocationCount_ += blocksize; }
e1f3ce0d 45
8d59b230 46 static void
5c7c5f9a 47 construct() { ++constructCount_; }
162c7cd9 48
8d59b230 49 static void
5c7c5f9a 50 destroy() { ++destructCount_; }
162c7cd9 51
8d59b230 52 static void
5c7c5f9a
FD
53 deallocate(size_type blocksize)
54 { deallocationCount_ += blocksize; }
e1f3ce0d 55
8d59b230 56 static size_type
9f9900db 57 get_allocation_count() { return allocationCount_; }
e1f3ce0d 58
8d59b230 59 static size_type
9f9900db 60 get_deallocation_count() { return deallocationCount_; }
e1f3ce0d 61
8d59b230 62 static int
9f9900db 63 get_construct_count() { return constructCount_; }
162c7cd9 64
8d59b230 65 static int
9f9900db 66 get_destruct_count() { return destructCount_; }
e1f3ce0d 67
8d59b230 68 static void
9f9900db 69 reset()
8d59b230 70 {
9f9900db
BK
71 allocationCount_ = 0;
72 deallocationCount_ = 0;
8d59b230 73 constructCount_ = 0;
9f9900db 74 destructCount_ = 0;
8d59b230 75 }
162c7cd9
SW
76
77 private:
9f9900db
BK
78 static size_type allocationCount_;
79 static size_type deallocationCount_;
8d59b230
BK
80 static int constructCount_;
81 static int destructCount_;
82 };
83
5c7c5f9a
FD
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;
89
90 template<typename T, typename Alloc>
91 struct check_consistent_alloc_value_type<T, Alloc, T>
92 { typedef T value_type; };
93
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
99 {
100 private:
101 typedef tracker_allocator_counter counter_type;
162c7cd9 102
5c7c5f9a 103 typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
8274b281 104
5c7c5f9a
FD
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;
8274b281 110
5c7c5f9a
FD
111 template<class U>
112 struct rebind
113 {
114 typedef tracker_allocator<U,
115 typename AllocTraits::template rebind<U>::other> other;
116 };
117
118#if __cplusplus >= 201103L
119 tracker_allocator() = default;
120 tracker_allocator(const tracker_allocator&) = default;
121 tracker_allocator(tracker_allocator&&) = default;
5caff414
JW
122 tracker_allocator& operator=(const tracker_allocator&) = default;
123 tracker_allocator& operator=(tracker_allocator&&) = default;
5c7c5f9a
FD
124
125 // Perfect forwarding constructor.
126 template<typename... _Args>
127 tracker_allocator(_Args&&... __args)
128 : Alloc(std::forward<_Args>(__args)...)
129 { }
130#else
131 tracker_allocator()
132 { }
162c7cd9 133
5c7c5f9a 134 tracker_allocator(const tracker_allocator&)
b3fb198d 135 { }
162c7cd9 136
5c7c5f9a
FD
137 ~tracker_allocator()
138 { }
139#endif
162c7cd9 140
5c7c5f9a
FD
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)
146 { }
162c7cd9 147
5c7c5f9a
FD
148 pointer
149 allocate(size_type n, const void* = 0)
150 {
151 pointer p = AllocTraits::allocate(*this, n);
152 counter_type::allocate(n * sizeof(T));
153 return p;
154 }
b3fb198d 155
8274b281 156#if __cplusplus >= 201103L
5c7c5f9a
FD
157 template<typename U, typename... Args>
158 void
159 construct(U* p, Args&&... args)
160 {
161 AllocTraits::construct(*this, p, std::forward<Args>(args)...);
162 counter_type::construct();
163 }
164
165 template<typename U>
166 void
167 destroy(U* p)
168 {
169 AllocTraits::destroy(*this, p);
170 counter_type::destroy();
171 }
172#else
6c6424b3 173 void
5c7c5f9a 174 construct(pointer p, const T& value)
6c6424b3 175 {
5c7c5f9a 176 AllocTraits::construct(*this, p, value);
6c6424b3
JW
177 counter_type::construct();
178 }
179
6c6424b3 180 void
5c7c5f9a 181 destroy(pointer p)
6c6424b3 182 {
5c7c5f9a 183 AllocTraits::destroy(*this, p);
6c6424b3
JW
184 counter_type::destroy();
185 }
8274b281 186#endif
162c7cd9 187
5c7c5f9a
FD
188 void
189 deallocate(pointer p, size_type num)
190 {
191 counter_type::deallocate(num * sizeof(T));
192 AllocTraits::deallocate(*this, p, num);
193 }
b3fb198d 194
5c7c5f9a
FD
195 // Implement swap for underlying allocators that might need it.
196 friend inline void
197 swap(tracker_allocator& a, tracker_allocator& b)
198 {
199 using std::swap;
200
201 Alloc& aa = a;
202 Alloc& ab = b;
203 swap(aa, ab);
204 }
205 };
206
207 template<class T1, class Alloc1, class T2, class Alloc2>
8d59b230 208 bool
5c7c5f9a
FD
209 operator==(const tracker_allocator<T1, Alloc1>& lhs,
210 const tracker_allocator<T2, Alloc2>& rhs) throw()
211 {
212 const Alloc1& alloc1 = lhs;
213 const Alloc2& alloc2 = rhs;
2acb7096 214 return alloc1 == alloc2;
5c7c5f9a 215 }
8d59b230 216
5c7c5f9a 217 template<class T1, class Alloc1, class T2, class Alloc2>
8d59b230 218 bool
5c7c5f9a
FD
219 operator!=(const tracker_allocator<T1, Alloc1>& lhs,
220 const tracker_allocator<T2, Alloc2>& rhs) throw()
221 { return !(lhs == rhs); }
1985f1cd 222
8bfd0a46
BK
223 bool
224 check_construct_destroy(const char* tag, int expected_c, int expected_d);
1985f1cd 225
5d1b2a1e 226 template<typename Alloc>
001a2a47 227 bool
5d1b2a1e
BK
228 check_deallocate_null()
229 {
230 // Let's not core here...
5c7c5f9a 231 Alloc a;
8fc81078
PC
232 a.deallocate(0, 1);
233 a.deallocate(0, 10);
001a2a47 234 return true;
5d1b2a1e 235 }
a063e891
PC
236
237 template<typename Alloc>
238 bool
239 check_allocate_max_size()
240 {
241 Alloc a;
242 try
243 {
244 a.allocate(a.max_size() + 1);
245 }
246 catch(std::bad_alloc&)
247 {
248 return true;
249 }
250 catch(...)
251 {
252 throw;
253 }
254 throw;
255 }
0cb855b7 256
31905f34
PC
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
5c7c5f9a 264 // swappable, not copy assignable, consistently with Option 3 of DR 431
31905f34
PC
265 // (see N1599).
266 struct uneq_allocator_base
267 {
268 typedef std::tr1::unordered_map<void*, int> map_type;
269
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()
275 {
276 static map_type alloc_map;
277 return alloc_map;
278 }
279 };
280
5c7c5f9a 281 template<typename Tp, typename Alloc = std::allocator<Tp> >
31905f34 282 class uneq_allocator
5c7c5f9a
FD
283 : private uneq_allocator_base,
284 public Alloc
31905f34 285 {
5c7c5f9a
FD
286 typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
287
288 Alloc& base() { return *this; }
289 const Alloc& base() const { return *this; }
290 void swap_base(Alloc& b) { swap(b, this->base()); }
291
31905f34 292 public:
5c7c5f9a
FD
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;
920a97b7 297
734f5023 298#if __cplusplus >= 201103L
5c7c5f9a 299 typedef std::true_type propagate_on_container_swap;
920a97b7
JW
300#endif
301
31905f34 302 template<typename Tp1>
5c7c5f9a
FD
303 struct rebind
304 {
305 typedef uneq_allocator<Tp1,
306 typename AllocTraits::template rebind<Tp1>::other> other;
307 };
31905f34 308
7d9cb054 309 uneq_allocator() _GLIBCXX_USE_NOEXCEPT
31905f34
PC
310 : personality(0) { }
311
7d9cb054 312 uneq_allocator(int person) _GLIBCXX_USE_NOEXCEPT
31905f34 313 : personality(person) { }
5c7c5f9a
FD
314
315#if __cplusplus >= 201103L
316 uneq_allocator(const uneq_allocator&) = default;
317 uneq_allocator(uneq_allocator&&) = default;
318#endif
31905f34
PC
319
320 template<typename Tp1>
5c7c5f9a
FD
321 uneq_allocator(const uneq_allocator<Tp1,
322 typename AllocTraits::template rebind<Tp1>::other>& b)
323 _GLIBCXX_USE_NOEXCEPT
31905f34
PC
324 : personality(b.get_personality()) { }
325
7d9cb054
PC
326 ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
327 { }
328
31905f34
PC
329 int get_personality() const { return personality; }
330
331 pointer
5c7c5f9a 332 allocate(size_type n, const void* hint = 0)
31905f34 333 {
5c7c5f9a
FD
334 pointer p = AllocTraits::allocate(*this, n);
335
31905f34
PC
336 try
337 {
338 get_map().insert(map_type::value_type(reinterpret_cast<void*>(p),
339 personality));
340 }
341 catch(...)
342 {
5c7c5f9a 343 AllocTraits::deallocate(*this, p, n);
31905f34
PC
344 __throw_exception_again;
345 }
5c7c5f9a 346
31905f34
PC
347 return p;
348 }
7d9cb054 349
31905f34 350 void
5c7c5f9a 351 deallocate(pointer p, size_type n)
31905f34 352 {
7d9cb054
PC
353 bool test __attribute__((unused)) = true;
354
355 VERIFY( p );
356
31905f34 357 map_type::iterator it = get_map().find(reinterpret_cast<void*>(p));
7d9cb054 358 VERIFY( it != get_map().end() );
31905f34
PC
359
360 // Enforce requirements in Table 32 about deallocation vs
361 // allocator equality.
7d9cb054
PC
362 VERIFY( it->second == personality );
363
31905f34 364 get_map().erase(it);
5c7c5f9a 365 AllocTraits::deallocate(*this, p, n);
31905f34 366 }
7d9cb054 367
734f5023 368#if __cplusplus >= 201103L
173f26ae
PC
369 // Not copy assignable...
370 uneq_allocator&
371 operator=(const uneq_allocator&) = delete;
8274b281 372
5c7c5f9a
FD
373 // ... but still moveable if base allocator is.
374 uneq_allocator&
375 operator=(uneq_allocator&&) = default;
376#else
6c6424b3 377 private:
31905f34
PC
378 // Not assignable...
379 uneq_allocator&
380 operator=(const uneq_allocator&);
173f26ae 381#endif
31905f34 382
6c6424b3 383 private:
31905f34
PC
384 // ... yet swappable!
385 friend inline void
386 swap(uneq_allocator& a, uneq_allocator& b)
5c7c5f9a
FD
387 {
388 std::swap(a.personality, b.personality);
389 a.swap_base(b);
390 }
391
31905f34 392 template<typename Tp1>
5c7c5f9a
FD
393 friend inline bool
394 operator==(const uneq_allocator& a,
395 const uneq_allocator<Tp1,
396 typename AllocTraits::template rebind<Tp1>::other>& b)
397 { return a.personality == b.personality; }
31905f34
PC
398
399 template<typename Tp1>
5c7c5f9a
FD
400 friend inline bool
401 operator!=(const uneq_allocator& a,
402 const uneq_allocator<Tp1,
403 typename AllocTraits::template rebind<Tp1>::other>& b)
404 { return !(a == b); }
31905f34
PC
405
406 int personality;
407 };
bd8485dc 408
734f5023 409#if __cplusplus >= 201103L
bd8485dc 410 // An uneq_allocator which can be used to test allocator propagation.
5c7c5f9a
FD
411 template<typename Tp, bool Propagate, typename Alloc = std::allocator<Tp>>
412 class propagating_allocator : public uneq_allocator<Tp, Alloc>
bd8485dc 413 {
5c7c5f9a
FD
414 typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
415
416 typedef uneq_allocator<Tp, Alloc> base_alloc;
bd8485dc
JW
417 base_alloc& base() { return *this; }
418 const base_alloc& base() const { return *this; }
419 void swap_base(base_alloc& b) { swap(b, this->base()); }
420
421 typedef std::integral_constant<bool, Propagate> trait_type;
422
423 public:
73f05031
JW
424 // default allocator_traits::rebind_alloc would select
425 // uneq_allocator::rebind so we must define rebind here
bd8485dc 426 template<typename Up>
5c7c5f9a
FD
427 struct rebind
428 {
429 typedef propagating_allocator<Up, Propagate,
430 typename AllocTraits::template rebind<Up>::other> other;
431 };
bd8485dc
JW
432
433 propagating_allocator(int i) noexcept
434 : base_alloc(i)
435 { }
436
437 template<typename Up>
5c7c5f9a
FD
438 propagating_allocator(const propagating_allocator<Up, Propagate,
439 typename AllocTraits::template rebind<Up>::other>& a)
440 noexcept
bd8485dc
JW
441 : base_alloc(a)
442 { }
443
444 propagating_allocator() noexcept = default;
445
446 propagating_allocator(const propagating_allocator&) noexcept = default;
447
a2e70335
JM
448 propagating_allocator&
449 operator=(const propagating_allocator& a) noexcept
ff90a89e
JW
450 {
451 static_assert(Propagate, "assigning propagating_allocator<T, true>");
452 propagating_allocator(a).swap_base(*this);
453 return *this;
454 }
a2e70335 455
bd8485dc 456 template<bool P2>
5c7c5f9a
FD
457 propagating_allocator&
458 operator=(const propagating_allocator<Tp, P2, Alloc>& a) noexcept
bd8485dc
JW
459 {
460 static_assert(P2, "assigning propagating_allocator<T, true>");
461 propagating_allocator(a).swap_base(*this);
0f509bb7 462 return *this;
bd8485dc
JW
463 }
464
465 // postcondition: a.get_personality() == 0
466 propagating_allocator(propagating_allocator&& a) noexcept
467 : base_alloc()
468 { swap_base(a); }
469
470 // postcondition: a.get_personality() == 0
471 propagating_allocator&
472 operator=(propagating_allocator&& a) noexcept
473 {
474 propagating_allocator(std::move(a)).swap_base(*this);
475 return *this;
476 }
477
478 typedef trait_type propagate_on_container_copy_assignment;
479 typedef trait_type propagate_on_container_move_assignment;
480 typedef trait_type propagate_on_container_swap;
481
482 propagating_allocator select_on_container_copy_construction() const
483 { return Propagate ? *this : propagating_allocator(); }
484 };
485
73f05031
JW
486 // Class template supporting the minimal interface that satisfies the
487 // Allocator requirements, from example in [allocator.requirements]
488 template <class Tp>
489 struct SimpleAllocator
490 {
491 typedef Tp value_type;
492
d9dcda6f 493 SimpleAllocator() noexcept { }
73f05031
JW
494
495 template <class T>
32e6a60e 496 SimpleAllocator(const SimpleAllocator<T>&) { }
73f05031
JW
497
498 Tp *allocate(std::size_t n)
499 { return std::allocator<Tp>().allocate(n); }
500
501 void deallocate(Tp *p, std::size_t n)
502 { std::allocator<Tp>().deallocate(p, n); }
503 };
504
505 template <class T, class U>
506 bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&)
507 { return true; }
508 template <class T, class U>
509 bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&)
510 { return false; }
511
bd8485dc
JW
512#endif
513
ff15f019
PC
514 template<typename Tp>
515 struct ExplicitConsAlloc : std::allocator<Tp>
516 {
517 ExplicitConsAlloc() { }
518
519 template<typename Up>
520 explicit
521 ExplicitConsAlloc(const ExplicitConsAlloc<Up>&) { }
522
523 template<typename Up>
524 struct rebind
525 { typedef ExplicitConsAlloc<Up> other; };
526 };
527
f038f582
JW
528#if __cplusplus >= 201103L
529 template<typename Tp>
530 class CustomPointerAlloc : public std::allocator<Tp>
531 {
532 template<typename Up, typename Sp = __gnu_cxx::_Std_pointer_impl<Up>>
533 using Ptr = __gnu_cxx::_Pointer_adapter<Sp>;
534
535 public:
536 CustomPointerAlloc() = default;
537
538 template<typename Up>
539 CustomPointerAlloc(const CustomPointerAlloc<Up>&) { }
540
541 template<typename Up>
542 struct rebind
543 { typedef CustomPointerAlloc<Up> other; };
544
545 typedef Ptr<Tp> pointer;
546 typedef Ptr<const Tp> const_pointer;
547 typedef Ptr<void> void_pointer;
548 typedef Ptr<const void> const_void_pointer;
549
550 pointer allocate(std::size_t n, pointer = {})
551 { return pointer(std::allocator<Tp>::allocate(n)); }
552
553 void deallocate(pointer p, std::size_t n)
554 { std::allocator<Tp>::deallocate(std::addressof(*p), n); }
555 };
20067423
JW
556
557 // Utility for use as CRTP base class of custom pointer types
558 template<typename Derived, typename T>
559 struct PointerBase
560 {
561 typedef T element_type;
562
563 // typedefs for iterator_traits
564 typedef T value_type;
565 typedef std::ptrdiff_t difference_type;
566 typedef std::random_access_iterator_tag iterator_category;
567 typedef Derived pointer;
568 typedef T& reference;
569
570 T* value;
571
572 explicit PointerBase(T* p = nullptr) : value(p) { }
573
574 template<typename D, typename U,
575 typename = decltype(static_cast<T*>(std::declval<U*>()))>
576 PointerBase(const PointerBase<D, U>& p) : value(p.value) { }
577
578 T& operator*() const { return *value; }
579 T* operator->() const { return value; }
a7890973 580 T& operator[](difference_type n) const { return value[n]; }
20067423
JW
581
582 Derived& operator++() { ++value; return derived(); }
583 Derived operator++(int) { Derived tmp(derived()); ++value; return tmp; }
584 Derived& operator--() { --value; return derived(); }
585 Derived operator--(int) { Derived tmp(derived()); --value; return tmp; }
586
587 Derived& operator+=(difference_type n) { value += n; return derived(); }
588 Derived& operator-=(difference_type n) { value -= n; return derived(); }
589
590 explicit operator bool() const { return value != nullptr; }
591
592 Derived
593 operator+(difference_type n) const
594 {
595 Derived p(derived());
596 return p += n;
597 }
598
599 Derived
600 operator-(difference_type n) const
601 {
602 Derived p(derived());
603 return p -= n;
604 }
605
606 private:
607 Derived& derived() { return static_cast<Derived&>(*this); }
608 };
609
610 template<typename D, typename T>
611 std::ptrdiff_t operator-(PointerBase<D, T> l, PointerBase<D, T> r)
612 { return l.value - r.value; }
613
614 template<typename D, typename T>
615 bool operator==(PointerBase<D, T> l, PointerBase<D, T> r)
616 { return l.value == r.value; }
617
618 template<typename D, typename T>
619 bool operator!=(PointerBase<D, T> l, PointerBase<D, T> r)
620 { return l.value != r.value; }
621
622 // implementation for void specializations
623 template<typename T>
624 struct PointerBase_void
625 {
626 typedef T element_type;
627
628 // typedefs for iterator_traits
629 typedef T value_type;
630 typedef std::ptrdiff_t difference_type;
631 typedef std::random_access_iterator_tag iterator_category;
632
633 T* value;
634
635 explicit PointerBase_void(T* p = nullptr) : value(p) { }
636
637 template<typename D, typename U,
638 typename = decltype(static_cast<T*>(std::declval<U*>()))>
639 PointerBase_void(const PointerBase<D, U>& p) : value(p.value) { }
640
641 explicit operator bool() const { return value != nullptr; }
642 };
643
644 template<typename Derived>
645 struct PointerBase<Derived, void> : PointerBase_void<void>
646 {
647 using PointerBase_void::PointerBase_void;
648 typedef Derived pointer;
649 };
650
651 template<typename Derived>
652 struct PointerBase<Derived, const void> : PointerBase_void<const void>
653 {
654 using PointerBase_void::PointerBase_void;
655 typedef Derived pointer;
656 };
f038f582
JW
657#endif
658
799a6e36 659} // namespace __gnu_test
162c7cd9 660
3d7c150e 661#endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H