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