]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/testsuite/util/testsuite_allocator.h
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / util / testsuite_allocator.h
1 // -*- C++ -*-
2 // Testing allocator for the C++ library testsuite.
3 //
4 // Copyright (C) 2002-2019 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.
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
18 // with this library; see the file COPYING3. If not see
19 // <http://www.gnu.org/licenses/>.
20 //
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
26 #ifndef _GLIBCXX_TESTSUITE_ALLOCATOR_H
27 #define _GLIBCXX_TESTSUITE_ALLOCATOR_H
28
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>
34 #if __cplusplus >= 201703L
35 # include <memory_resource>
36 # include <new>
37 #endif
38
39 namespace __gnu_test
40 {
41 class tracker_allocator_counter
42 {
43 public:
44 typedef std::size_t size_type;
45
46 static void
47 allocate(size_type blocksize)
48 { allocationCount_ += blocksize; }
49
50 static void
51 construct() { ++constructCount_; }
52
53 static void
54 destroy() { ++destructCount_; }
55
56 static void
57 deallocate(size_type blocksize)
58 { deallocationCount_ += blocksize; }
59
60 static size_type
61 get_allocation_count() { return allocationCount_; }
62
63 static size_type
64 get_deallocation_count() { return deallocationCount_; }
65
66 static int
67 get_construct_count() { return constructCount_; }
68
69 static int
70 get_destruct_count() { return destructCount_; }
71
72 static void
73 reset()
74 {
75 allocationCount_ = 0;
76 deallocationCount_ = 0;
77 constructCount_ = 0;
78 destructCount_ = 0;
79 }
80
81 private:
82 static size_type allocationCount_;
83 static size_type deallocationCount_;
84 static int constructCount_;
85 static int destructCount_;
86 };
87
88 // Helper to detect inconsistency between type used to instantiate an
89 // allocator and the underlying allocator value_type.
90 template<typename T, typename Alloc,
91 typename = typename Alloc::value_type>
92 struct check_consistent_alloc_value_type;
93
94 template<typename T, typename Alloc>
95 struct check_consistent_alloc_value_type<T, Alloc, T>
96 { typedef T value_type; };
97
98 // An allocator facade that intercepts allocate/deallocate/construct/destroy
99 // calls and track them through the tracker_allocator_counter class. This
100 // class is templated on the target object type, but tracker isn't.
101 template<typename T, typename Alloc = std::allocator<T> >
102 class tracker_allocator : public Alloc
103 {
104 private:
105 typedef tracker_allocator_counter counter_type;
106
107 typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
108
109 public:
110 typedef typename
111 check_consistent_alloc_value_type<T, Alloc>::value_type value_type;
112 typedef typename AllocTraits::pointer pointer;
113 typedef typename AllocTraits::size_type size_type;
114
115 template<class U>
116 struct rebind
117 {
118 typedef tracker_allocator<U,
119 typename AllocTraits::template rebind<U>::other> other;
120 };
121
122 #if __cplusplus >= 201103L
123 tracker_allocator() = default;
124 tracker_allocator(const tracker_allocator&) = default;
125 tracker_allocator(tracker_allocator&&) = default;
126 tracker_allocator& operator=(const tracker_allocator&) = default;
127 tracker_allocator& operator=(tracker_allocator&&) = default;
128
129 // Perfect forwarding constructor.
130 template<typename... _Args>
131 tracker_allocator(_Args&&... __args)
132 : Alloc(std::forward<_Args>(__args)...)
133 { }
134 #else
135 tracker_allocator()
136 { }
137
138 tracker_allocator(const tracker_allocator&)
139 { }
140
141 ~tracker_allocator()
142 { }
143 #endif
144
145 template<class U>
146 tracker_allocator(const tracker_allocator<U,
147 typename AllocTraits::template rebind<U>::other>& alloc)
148 _GLIBCXX_USE_NOEXCEPT
149 : Alloc(alloc)
150 { }
151
152 pointer
153 allocate(size_type n, const void* = 0)
154 {
155 pointer p = AllocTraits::allocate(*this, n);
156 counter_type::allocate(n * sizeof(T));
157 return p;
158 }
159
160 #if __cplusplus >= 201103L
161 template<typename U, typename... Args>
162 void
163 construct(U* p, Args&&... args)
164 {
165 AllocTraits::construct(*this, p, std::forward<Args>(args)...);
166 counter_type::construct();
167 }
168
169 template<typename U>
170 void
171 destroy(U* p)
172 {
173 AllocTraits::destroy(*this, p);
174 counter_type::destroy();
175 }
176 #else
177 void
178 construct(pointer p, const T& value)
179 {
180 AllocTraits::construct(*this, p, value);
181 counter_type::construct();
182 }
183
184 void
185 destroy(pointer p)
186 {
187 AllocTraits::destroy(*this, p);
188 counter_type::destroy();
189 }
190 #endif
191
192 void
193 deallocate(pointer p, size_type num)
194 {
195 counter_type::deallocate(num * sizeof(T));
196 AllocTraits::deallocate(*this, p, num);
197 }
198
199 // Implement swap for underlying allocators that might need it.
200 friend inline void
201 swap(tracker_allocator& a, tracker_allocator& b)
202 {
203 using std::swap;
204
205 Alloc& aa = a;
206 Alloc& ab = b;
207 swap(aa, ab);
208 }
209 };
210
211 template<class T1, class Alloc1, class T2, class Alloc2>
212 bool
213 operator==(const tracker_allocator<T1, Alloc1>& lhs,
214 const tracker_allocator<T2, Alloc2>& rhs) throw()
215 {
216 const Alloc1& alloc1 = lhs;
217 const Alloc2& alloc2 = rhs;
218 return alloc1 == alloc2;
219 }
220
221 template<class T1, class Alloc1, class T2, class Alloc2>
222 bool
223 operator!=(const tracker_allocator<T1, Alloc1>& lhs,
224 const tracker_allocator<T2, Alloc2>& rhs) throw()
225 { return !(lhs == rhs); }
226
227 bool
228 check_construct_destroy(const char* tag, int expected_c, int expected_d);
229
230 template<typename Alloc>
231 bool
232 check_deallocate_null()
233 {
234 // Let's not core here...
235 Alloc a;
236 a.deallocate(0, 1);
237 a.deallocate(0, 10);
238 return true;
239 }
240
241 template<typename Alloc>
242 bool
243 check_allocate_max_size()
244 {
245 Alloc a;
246 try
247 {
248 a.allocate(a.max_size() + 1);
249 }
250 catch(std::bad_alloc&)
251 {
252 return true;
253 }
254 catch(...)
255 {
256 throw;
257 }
258 throw;
259 }
260
261 // A simple allocator which can be constructed endowed of a given
262 // "personality" (an integer), queried in operator== to simulate the
263 // behavior of realworld "unequal" allocators (i.e., not exploiting
264 // the provision in 20.1.5/4, first bullet). A global unordered_map,
265 // filled at allocation time with (pointer, personality) pairs, is
266 // then consulted to enforce the requirements in Table 32 about
267 // deallocation vs allocator equality. Note that this allocator is
268 // swappable, not copy assignable, consistently with Option 3 of DR 431
269 // (see N1599).
270 struct uneq_allocator_base
271 {
272 typedef std::tr1::unordered_map<void*, int> map_type;
273
274 // Avoid static initialization troubles and/or bad interactions
275 // with tests linking testsuite_allocator.o and playing globally
276 // with operator new/delete.
277 static map_type&
278 get_map()
279 {
280 static map_type alloc_map;
281 return alloc_map;
282 }
283 };
284
285 template<typename Tp, typename Alloc = std::allocator<Tp> >
286 class uneq_allocator
287 : private uneq_allocator_base,
288 public Alloc
289 {
290 typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
291
292 Alloc& base() { return *this; }
293 const Alloc& base() const { return *this; }
294 void swap_base(Alloc& b) { using std::swap; swap(b, this->base()); }
295
296 public:
297 typedef typename check_consistent_alloc_value_type<Tp, Alloc>::value_type
298 value_type;
299 typedef typename AllocTraits::size_type size_type;
300 typedef typename AllocTraits::pointer pointer;
301
302 #if __cplusplus >= 201103L
303 typedef std::true_type propagate_on_container_swap;
304 typedef std::false_type is_always_equal;
305 #endif
306
307 template<typename Tp1>
308 struct rebind
309 {
310 typedef uneq_allocator<Tp1,
311 typename AllocTraits::template rebind<Tp1>::other> other;
312 };
313
314 uneq_allocator() _GLIBCXX_USE_NOEXCEPT
315 : personality(0) { }
316
317 uneq_allocator(int person) _GLIBCXX_USE_NOEXCEPT
318 : personality(person) { }
319
320 #if __cplusplus >= 201103L
321 uneq_allocator(const uneq_allocator&) = default;
322 uneq_allocator(uneq_allocator&&) = default;
323 #endif
324
325 template<typename Tp1>
326 uneq_allocator(const uneq_allocator<Tp1,
327 typename AllocTraits::template rebind<Tp1>::other>& b)
328 _GLIBCXX_USE_NOEXCEPT
329 : personality(b.get_personality()) { }
330
331 ~uneq_allocator() _GLIBCXX_USE_NOEXCEPT
332 { }
333
334 int get_personality() const { return personality; }
335
336 pointer
337 allocate(size_type n, const void* hint = 0)
338 {
339 pointer p = AllocTraits::allocate(*this, n);
340
341 try
342 {
343 get_map().insert(map_type::value_type(reinterpret_cast<void*>(p),
344 personality));
345 }
346 catch(...)
347 {
348 AllocTraits::deallocate(*this, p, n);
349 __throw_exception_again;
350 }
351
352 return p;
353 }
354
355 void
356 deallocate(pointer p, size_type n)
357 {
358 VERIFY( p );
359
360 map_type::iterator it = get_map().find(reinterpret_cast<void*>(p));
361 VERIFY( it != get_map().end() );
362
363 // Enforce requirements in Table 32 about deallocation vs
364 // allocator equality.
365 VERIFY( it->second == personality );
366
367 get_map().erase(it);
368 AllocTraits::deallocate(*this, p, n);
369 }
370
371 #if __cplusplus >= 201103L
372 // Not copy assignable...
373 uneq_allocator&
374 operator=(const uneq_allocator&) = delete;
375
376 // ... but still moveable if base allocator is.
377 uneq_allocator&
378 operator=(uneq_allocator&&) = default;
379 #else
380 private:
381 // Not assignable...
382 uneq_allocator&
383 operator=(const uneq_allocator&);
384 #endif
385
386 private:
387 // ... yet swappable!
388 friend inline void
389 swap(uneq_allocator& a, uneq_allocator& b)
390 {
391 std::swap(a.personality, b.personality);
392 a.swap_base(b);
393 }
394
395 template<typename Tp1>
396 friend inline bool
397 operator==(const uneq_allocator& a,
398 const uneq_allocator<Tp1,
399 typename AllocTraits::template rebind<Tp1>::other>& b)
400 { return a.personality == b.personality; }
401
402 template<typename Tp1>
403 friend inline bool
404 operator!=(const uneq_allocator& a,
405 const uneq_allocator<Tp1,
406 typename AllocTraits::template rebind<Tp1>::other>& b)
407 { return !(a == b); }
408
409 int personality;
410 };
411
412 #if __cplusplus >= 201103L
413 // An uneq_allocator which can be used to test allocator propagation.
414 template<typename Tp, bool Propagate, typename Alloc = std::allocator<Tp>>
415 class propagating_allocator : public uneq_allocator<Tp, Alloc>
416 {
417 typedef __gnu_cxx::__alloc_traits<Alloc> AllocTraits;
418
419 typedef uneq_allocator<Tp, Alloc> base_alloc;
420 base_alloc& base() { return *this; }
421 const base_alloc& base() const { return *this; }
422 void swap_base(base_alloc& b) { swap(b, this->base()); }
423
424 typedef std::integral_constant<bool, Propagate> trait_type;
425
426 public:
427 // default allocator_traits::rebind_alloc would select
428 // uneq_allocator::rebind so we must define rebind here
429 template<typename Up>
430 struct rebind
431 {
432 typedef propagating_allocator<Up, Propagate,
433 typename AllocTraits::template rebind<Up>::other> other;
434 };
435
436 propagating_allocator(int i) noexcept
437 : base_alloc(i)
438 { }
439
440 template<typename Up>
441 propagating_allocator(const propagating_allocator<Up, Propagate,
442 typename AllocTraits::template rebind<Up>::other>& a)
443 noexcept
444 : base_alloc(a)
445 { }
446
447 propagating_allocator() noexcept = default;
448
449 propagating_allocator(const propagating_allocator&) noexcept = default;
450
451 propagating_allocator&
452 operator=(const propagating_allocator& a) noexcept
453 {
454 static_assert(Propagate, "assigning propagating_allocator<T, true>");
455 propagating_allocator(a).swap_base(*this);
456 return *this;
457 }
458
459 template<bool P2>
460 propagating_allocator&
461 operator=(const propagating_allocator<Tp, P2, Alloc>& a) noexcept
462 {
463 static_assert(P2, "assigning propagating_allocator<T, true>");
464 propagating_allocator(a).swap_base(*this);
465 return *this;
466 }
467
468 // postcondition: a.get_personality() == 0
469 propagating_allocator(propagating_allocator&& a) noexcept
470 : base_alloc()
471 { swap_base(a); }
472
473 // postcondition: a.get_personality() == 0
474 propagating_allocator&
475 operator=(propagating_allocator&& a) noexcept
476 {
477 propagating_allocator(std::move(a)).swap_base(*this);
478 return *this;
479 }
480
481 typedef trait_type propagate_on_container_copy_assignment;
482 typedef trait_type propagate_on_container_move_assignment;
483 typedef trait_type propagate_on_container_swap;
484
485 propagating_allocator select_on_container_copy_construction() const
486 { return Propagate ? *this : propagating_allocator(); }
487 };
488
489 // Class template supporting the minimal interface that satisfies the
490 // Allocator requirements, from example in [allocator.requirements]
491 template <class Tp>
492 struct SimpleAllocator
493 {
494 typedef Tp value_type;
495
496 SimpleAllocator() noexcept { }
497
498 template <class T>
499 SimpleAllocator(const SimpleAllocator<T>&) { }
500
501 Tp *allocate(std::size_t n)
502 { return std::allocator<Tp>().allocate(n); }
503
504 void deallocate(Tp *p, std::size_t n)
505 { std::allocator<Tp>().deallocate(p, n); }
506 };
507
508 template <class T, class U>
509 bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&)
510 { return true; }
511 template <class T, class U>
512 bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&)
513 { return false; }
514
515 template<typename T>
516 struct default_init_allocator
517 {
518 using value_type = T;
519
520 default_init_allocator() = default;
521
522 template<typename U>
523 default_init_allocator(const default_init_allocator<U>& a)
524 : state(a.state)
525 { }
526
527 T*
528 allocate(std::size_t n)
529 { return std::allocator<T>().allocate(n); }
530
531 void
532 deallocate(T* p, std::size_t n)
533 { std::allocator<T>().deallocate(p, n); }
534
535 int state;
536 };
537
538 template<typename T, typename U>
539 bool operator==(const default_init_allocator<T>& t,
540 const default_init_allocator<U>& u)
541 { return t.state == u.state; }
542
543 template<typename T, typename U>
544 bool operator!=(const default_init_allocator<T>& t,
545 const default_init_allocator<U>& u)
546 { return !(t == u); }
547 #endif
548
549 template<typename Tp>
550 struct ExplicitConsAlloc : std::allocator<Tp>
551 {
552 ExplicitConsAlloc() { }
553
554 template<typename Up>
555 explicit
556 ExplicitConsAlloc(const ExplicitConsAlloc<Up>&) { }
557
558 template<typename Up>
559 struct rebind
560 { typedef ExplicitConsAlloc<Up> other; };
561 };
562
563 #if __cplusplus >= 201103L
564 template<typename Tp>
565 class CustomPointerAlloc : public std::allocator<Tp>
566 {
567 template<typename Up, typename Sp = __gnu_cxx::_Std_pointer_impl<Up>>
568 using Ptr = __gnu_cxx::_Pointer_adapter<Sp>;
569
570 public:
571 CustomPointerAlloc() = default;
572
573 template<typename Up>
574 CustomPointerAlloc(const CustomPointerAlloc<Up>&) { }
575
576 template<typename Up>
577 struct rebind
578 { typedef CustomPointerAlloc<Up> other; };
579
580 typedef Ptr<Tp> pointer;
581 typedef Ptr<const Tp> const_pointer;
582 typedef Ptr<void> void_pointer;
583 typedef Ptr<const void> const_void_pointer;
584
585 pointer allocate(std::size_t n, const_void_pointer = {})
586 { return pointer(std::allocator<Tp>::allocate(n)); }
587
588 void deallocate(pointer p, std::size_t n)
589 { std::allocator<Tp>::deallocate(std::addressof(*p), n); }
590 };
591
592 // Utility for use as CRTP base class of custom pointer types
593 template<typename Derived, typename T>
594 struct PointerBase
595 {
596 typedef T element_type;
597
598 // typedefs for iterator_traits
599 typedef T value_type;
600 typedef std::ptrdiff_t difference_type;
601 typedef std::random_access_iterator_tag iterator_category;
602 typedef Derived pointer;
603 typedef T& reference;
604
605 T* value;
606
607 explicit PointerBase(T* p = nullptr) : value(p) { }
608
609 PointerBase(std::nullptr_t) : value(nullptr) { }
610
611 template<typename D, typename U,
612 typename = decltype(static_cast<T*>(std::declval<U*>()))>
613 PointerBase(const PointerBase<D, U>& p) : value(p.value) { }
614
615 T& operator*() const { return *value; }
616 T* operator->() const { return value; }
617 T& operator[](difference_type n) const { return value[n]; }
618
619 Derived& operator++() { ++value; return derived(); }
620 Derived operator++(int) { Derived tmp(derived()); ++value; return tmp; }
621 Derived& operator--() { --value; return derived(); }
622 Derived operator--(int) { Derived tmp(derived()); --value; return tmp; }
623
624 Derived& operator+=(difference_type n) { value += n; return derived(); }
625 Derived& operator-=(difference_type n) { value -= n; return derived(); }
626
627 explicit operator bool() const { return value != nullptr; }
628
629 Derived
630 operator+(difference_type n) const
631 {
632 Derived p(derived());
633 return p += n;
634 }
635
636 Derived
637 operator-(difference_type n) const
638 {
639 Derived p(derived());
640 return p -= n;
641 }
642
643 private:
644 Derived&
645 derived() { return static_cast<Derived&>(*this); }
646
647 const Derived&
648 derived() const { return static_cast<const Derived&>(*this); }
649 };
650
651 template<typename D, typename T>
652 std::ptrdiff_t operator-(PointerBase<D, T> l, PointerBase<D, T> r)
653 { return l.value - r.value; }
654
655 template<typename D, typename T>
656 bool operator==(PointerBase<D, T> l, PointerBase<D, T> r)
657 { return l.value == r.value; }
658
659 template<typename D, typename T>
660 bool operator!=(PointerBase<D, T> l, PointerBase<D, T> r)
661 { return l.value != r.value; }
662
663 // implementation for void specializations
664 template<typename T>
665 struct PointerBase_void
666 {
667 typedef T element_type;
668
669 // typedefs for iterator_traits
670 typedef T value_type;
671 typedef std::ptrdiff_t difference_type;
672 typedef std::random_access_iterator_tag iterator_category;
673
674 T* value;
675
676 explicit PointerBase_void(T* p = nullptr) : value(p) { }
677
678 template<typename D, typename U,
679 typename = decltype(static_cast<T*>(std::declval<U*>()))>
680 PointerBase_void(const PointerBase<D, U>& p) : value(p.value) { }
681
682 explicit operator bool() const { return value != nullptr; }
683 };
684
685 template<typename Derived>
686 struct PointerBase<Derived, void> : PointerBase_void<void>
687 {
688 using PointerBase_void::PointerBase_void;
689 typedef Derived pointer;
690 };
691
692 template<typename Derived>
693 struct PointerBase<Derived, const void> : PointerBase_void<const void>
694 {
695 using PointerBase_void::PointerBase_void;
696 typedef Derived pointer;
697 };
698 #endif // C++11
699
700 #if __cplusplus >= 201703L
701 #if __cpp_aligned_new && __cpp_rtti
702 // A concrete memory_resource, with error checking.
703 class memory_resource : public std::pmr::memory_resource
704 {
705 public:
706 memory_resource()
707 : lists(new allocation_lists)
708 { }
709
710 memory_resource(const memory_resource& r) noexcept
711 : lists(r.lists)
712 { lists->refcount++; }
713
714 memory_resource& operator=(const memory_resource&) = delete;
715
716 ~memory_resource()
717 {
718 if (lists->refcount-- == 1)
719 delete lists; // last one out turns out the lights
720 }
721
722 struct bad_size { };
723 struct bad_alignment { };
724 struct bad_address { };
725
726 // Deallocate everything (moving the tracking info to the freed list)
727 void
728 deallocate_everything()
729 {
730 while (lists->active)
731 {
732 auto a = lists->active;
733 // Intentionally virtual dispatch, to inform derived classes:
734 this->do_deallocate(a->p, a->bytes, a->alignment);
735 }
736 }
737
738 // Clear the freed list
739 void
740 forget_freed_allocations()
741 { lists->forget_allocations(lists->freed); }
742
743 // Count how many allocations have been done and not freed.
744 std::size_t
745 number_of_active_allocations() const noexcept
746 {
747 std::size_t n = 0;
748 for (auto a = lists->active; a != nullptr; a = a->next)
749 ++n;
750 return n;
751 }
752
753 protected:
754 void*
755 do_allocate(std::size_t bytes, std::size_t alignment) override
756 {
757 // TODO perform a single allocation and put the allocation struct
758 // in the buffer using placement new? It means deallocation won't
759 // actually return memory to the OS, as it will stay in lists->freed.
760 //
761 // TODO adjust the returned pointer to be minimally aligned?
762 // e.g. if alignment==1 don't return something aligned to 2 bytes.
763 // Maybe not worth it, at least monotonic_buffer_resource will
764 // never ask upstream for anything with small alignment.
765 void* p = ::operator new(bytes, std::align_val_t(alignment));
766 lists->active = new allocation{p, bytes, alignment, lists->active};
767 return p;
768 }
769
770 void
771 do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override
772 {
773 allocation** aptr = &lists->active;
774 while (*aptr)
775 {
776 allocation* a = *aptr;
777 if (p == a->p)
778 {
779 if (bytes != a->bytes)
780 throw bad_size();
781 if (alignment != a->alignment)
782 throw bad_alignment();
783 ::operator delete(p, bytes, std::align_val_t(alignment));
784 *aptr = a->next;
785 a->next = lists->freed;
786 lists->freed = a;
787 return;
788 }
789 aptr = &a->next;
790 }
791 throw bad_address();
792 }
793
794 bool
795 do_is_equal(const std::pmr::memory_resource& r) const noexcept override
796 {
797 // Equality is determined by sharing the same allocation_lists object.
798 if (auto p = dynamic_cast<const memory_resource*>(&r))
799 return p->lists == lists;
800 return false;
801 }
802
803 private:
804 struct allocation
805 {
806 void* p;
807 std::size_t bytes;
808 std::size_t alignment;
809 allocation* next;
810 };
811
812 // Maintain list of allocated blocks and list of freed blocks.
813 // Copies of this memory_resource share the same ref-counted lists.
814 struct allocation_lists
815 {
816 unsigned refcount = 1;
817 allocation* active = nullptr;
818 allocation* freed = nullptr;
819
820 void forget_allocations(allocation*& list)
821 {
822 while (list)
823 {
824 auto p = list;
825 list = list->next;
826 delete p;
827 }
828 }
829
830 ~allocation_lists()
831 {
832 forget_allocations(active); // Anything in this list is a leak!
833 forget_allocations(freed);
834 }
835 };
836
837 allocation_lists* lists;
838 };
839 #endif // aligned-new && rtti
840
841 // Set the default resource, and restore the previous one on destruction.
842 struct default_resource_mgr
843 {
844 explicit default_resource_mgr(std::pmr::memory_resource* r)
845 : prev(std::pmr::set_default_resource(r))
846 { }
847
848 ~default_resource_mgr()
849 { std::pmr::set_default_resource(prev); }
850
851 std::pmr::memory_resource* prev;
852 };
853
854 #endif // C++17
855
856 } // namespace __gnu_test
857
858 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H