1  // <memory_resource> -*- C++ -*-
       2  
       3  // Copyright (C) 2018-2023 Free Software Foundation, Inc.
       4  //
       5  // This file is part of the GNU ISO C++ Library.  This library is free
       6  // software; you can redistribute it and/or modify it under the
       7  // terms of the GNU General Public License as published by the
       8  // Free Software Foundation; either version 3, or (at your option)
       9  // any later version.
      10  
      11  // This library is distributed in the hope that it will be useful,
      12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14  // GNU General Public License for more details.
      15  
      16  // Under Section 7 of GPL version 3, you are granted additional
      17  // permissions described in the GCC Runtime Library Exception, version
      18  // 3.1, as published by the Free Software Foundation.
      19  
      20  // You should have received a copy of the GNU General Public License and
      21  // a copy of the GCC Runtime Library Exception along with this program;
      22  // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23  // <http://www.gnu.org/licenses/>.
      24  
      25  /** @file include/bits/memory_resource.h
      26   *  This is an internal header file, included by other library headers.
      27   *  Do not attempt to use it directly. @headername{memory_resource}
      28   */
      29  
      30  #ifndef _GLIBCXX_MEMORY_RESOURCE_H
      31  #define _GLIBCXX_MEMORY_RESOURCE_H 1
      32  
      33  #pragma GCC system_header
      34  
      35  #if __cplusplus >= 201703L
      36  
      37  #include <new>				// operator new(size_t, void*)
      38  #include <cstddef>			// size_t, max_align_t, byte
      39  #include <bits/functexcept.h>		// __throw_bad_array_new_length
      40  #include <bits/uses_allocator.h>	// allocator_arg_t, __use_alloc
      41  #include <bits/uses_allocator_args.h>	// uninitialized_construct_using_alloc
      42  #include <ext/numeric_traits.h>		// __int_traits
      43  #include <debug/assertions.h>
      44  
      45  #if ! __cpp_lib_make_obj_using_allocator
      46  # include <bits/utility.h>		// index_sequence
      47  # include <tuple>			// tuple, forward_as_tuple
      48  #endif
      49  
      50  namespace std _GLIBCXX_VISIBILITY(default)
      51  {
      52  _GLIBCXX_BEGIN_NAMESPACE_VERSION
      53  namespace pmr
      54  {
      55    /// Class memory_resource
      56    /**
      57     * @ingroup pmr
      58     * @headerfile memory_resource
      59     * @since C++17
      60     */
      61    class memory_resource
      62    {
      63      static constexpr size_t _S_max_align = alignof(max_align_t);
      64  
      65    public:
      66      memory_resource() = default;
      67      memory_resource(const memory_resource&) = default;
      68      virtual ~memory_resource(); // key function
      69  
      70      memory_resource& operator=(const memory_resource&) = default;
      71  
      72      [[nodiscard]]
      73      void*
      74      allocate(size_t __bytes, size_t __alignment = _S_max_align)
      75      __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3)))
      76      { return ::operator new(__bytes, do_allocate(__bytes, __alignment)); }
      77  
      78      void
      79      deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
      80      __attribute__((__nonnull__))
      81      { return do_deallocate(__p, __bytes, __alignment); }
      82  
      83      [[nodiscard]]
      84      bool
      85      is_equal(const memory_resource& __other) const noexcept
      86      { return do_is_equal(__other); }
      87  
      88    private:
      89      virtual void*
      90      do_allocate(size_t __bytes, size_t __alignment) = 0;
      91  
      92      virtual void
      93      do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;
      94  
      95      virtual bool
      96      do_is_equal(const memory_resource& __other) const noexcept = 0;
      97    };
      98  
      99    [[nodiscard]]
     100    inline bool
     101    operator==(const memory_resource& __a, const memory_resource& __b) noexcept
     102    { return &__a == &__b || __a.is_equal(__b); }
     103  
     104  #if __cpp_impl_three_way_comparison < 201907L
     105    [[nodiscard]]
     106    inline bool
     107    operator!=(const memory_resource& __a, const memory_resource& __b) noexcept
     108    { return !(__a == __b); }
     109  #endif
     110  
     111    // C++17 23.12.3 Class template polymorphic_allocator
     112  
     113    /// Class template polymorphic_allocator
     114    /**
     115     * @ingroup pmr
     116     * @headerfile memory_resource
     117     * @since C++17
     118     */
     119    template<typename _Tp>
     120      class polymorphic_allocator
     121      {
     122        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     123        // 2975. Missing case for pair construction in polymorphic allocators
     124        template<typename _Up>
     125  	struct __not_pair { using type = void; };
     126  
     127        template<typename _Up1, typename _Up2>
     128  	struct __not_pair<pair<_Up1, _Up2>> { };
     129  
     130      public:
     131        using value_type = _Tp;
     132  
     133        polymorphic_allocator() noexcept
     134        {
     135  	extern memory_resource* get_default_resource() noexcept
     136  	  __attribute__((__returns_nonnull__));
     137  	_M_resource = get_default_resource();
     138        }
     139  
     140        polymorphic_allocator(memory_resource* __r) noexcept
     141        __attribute__((__nonnull__))
     142        : _M_resource(__r)
     143        { _GLIBCXX_DEBUG_ASSERT(__r); }
     144  
     145        polymorphic_allocator(const polymorphic_allocator& __other) = default;
     146  
     147        template<typename _Up>
     148  	polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept
     149  	: _M_resource(__x.resource())
     150  	{ }
     151  
     152        polymorphic_allocator&
     153        operator=(const polymorphic_allocator&) = delete;
     154  
     155        [[nodiscard]]
     156        _Tp*
     157        allocate(size_t __n)
     158        __attribute__((__returns_nonnull__))
     159        {
     160  	if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp)) < __n)
     161  	  std::__throw_bad_array_new_length();
     162  	return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
     163  						       alignof(_Tp)));
     164        }
     165  
     166        void
     167        deallocate(_Tp* __p, size_t __n) noexcept
     168        __attribute__((__nonnull__))
     169        { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
     170  
     171  #if __cplusplus > 201703L
     172        [[nodiscard]] void*
     173        allocate_bytes(size_t __nbytes,
     174  		     size_t __alignment = alignof(max_align_t))
     175        { return _M_resource->allocate(__nbytes, __alignment); }
     176  
     177        void
     178        deallocate_bytes(void* __p, size_t __nbytes,
     179  		       size_t __alignment = alignof(max_align_t))
     180        { _M_resource->deallocate(__p, __nbytes, __alignment); }
     181  
     182        template<typename _Up>
     183  	[[nodiscard]] _Up*
     184  	allocate_object(size_t __n = 1)
     185  	{
     186  	  if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Up)) < __n)
     187  	    std::__throw_bad_array_new_length();
     188  	  return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up),
     189  						  alignof(_Up)));
     190  	}
     191  
     192        template<typename _Up>
     193  	void
     194  	deallocate_object(_Up* __p, size_t __n = 1)
     195  	{ deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); }
     196  
     197        template<typename _Up, typename... _CtorArgs>
     198  	[[nodiscard]] _Up*
     199  	new_object(_CtorArgs&&... __ctor_args)
     200  	{
     201  	  _Up* __p = allocate_object<_Up>();
     202  	  __try
     203  	    {
     204  	      construct(__p, std::forward<_CtorArgs>(__ctor_args)...);
     205  	    }
     206  	  __catch (...)
     207  	    {
     208  	      deallocate_object(__p);
     209  	      __throw_exception_again;
     210  	    }
     211  	  return __p;
     212  	}
     213  
     214        template<typename _Up>
     215  	void
     216  	delete_object(_Up* __p)
     217  	{
     218  	  __p->~_Up();
     219  	  deallocate_object(__p);
     220  	}
     221  #endif // C++2a
     222  
     223  #if ! __cpp_lib_make_obj_using_allocator
     224        template<typename _Tp1, typename... _Args>
     225  	__attribute__((__nonnull__))
     226  	typename __not_pair<_Tp1>::type
     227  	construct(_Tp1* __p, _Args&&... __args)
     228  	{
     229  	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
     230  	  // 2969. polymorphic_allocator::construct() shouldn't pass resource()
     231  	  using __use_tag
     232  	    = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>;
     233  	  if constexpr (is_base_of_v<__uses_alloc0, __use_tag>)
     234  	    ::new(__p) _Tp1(std::forward<_Args>(__args)...);
     235  	  else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>)
     236  	    ::new(__p) _Tp1(allocator_arg, *this,
     237  			    std::forward<_Args>(__args)...);
     238  	  else
     239  	    ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this);
     240  	}
     241  
     242        template<typename _Tp1, typename _Tp2,
     243  	       typename... _Args1, typename... _Args2>
     244  	__attribute__((__nonnull__))
     245  	void
     246  	construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
     247  		  tuple<_Args1...> __x, tuple<_Args2...> __y)
     248  	{
     249  	  auto __x_tag =
     250  	    __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this);
     251  	  auto __y_tag =
     252  	    __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this);
     253  	  index_sequence_for<_Args1...> __x_i;
     254  	  index_sequence_for<_Args2...> __y_i;
     255  
     256  	  ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct,
     257  				      _S_construct_p(__x_tag, __x_i, __x),
     258  				      _S_construct_p(__y_tag, __y_i, __y));
     259  	}
     260  
     261        template<typename _Tp1, typename _Tp2>
     262  	__attribute__((__nonnull__))
     263  	void
     264  	construct(pair<_Tp1, _Tp2>* __p)
     265  	{ this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
     266  
     267        template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
     268  	__attribute__((__nonnull__))
     269  	void
     270  	construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y)
     271  	{
     272  	  this->construct(__p, piecewise_construct,
     273  	      std::forward_as_tuple(std::forward<_Up>(__x)),
     274  	      std::forward_as_tuple(std::forward<_Vp>(__y)));
     275  	}
     276  
     277        template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
     278  	__attribute__((__nonnull__))
     279  	void
     280  	construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr)
     281  	{
     282  	  this->construct(__p, piecewise_construct,
     283  	      std::forward_as_tuple(__pr.first),
     284  	      std::forward_as_tuple(__pr.second));
     285  	}
     286  
     287        template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
     288  	__attribute__((__nonnull__))
     289  	void
     290  	construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr)
     291  	{
     292  	  this->construct(__p, piecewise_construct,
     293  	      std::forward_as_tuple(std::forward<_Up>(__pr.first)),
     294  	      std::forward_as_tuple(std::forward<_Vp>(__pr.second)));
     295  	}
     296  #else // make_obj_using_allocator
     297        template<typename _Tp1, typename... _Args>
     298  	__attribute__((__nonnull__))
     299  	void
     300  	construct(_Tp1* __p, _Args&&... __args)
     301  	{
     302  	  std::uninitialized_construct_using_allocator(__p, *this,
     303  	      std::forward<_Args>(__args)...);
     304  	}
     305  #endif
     306  
     307        template<typename _Up>
     308  	_GLIBCXX20_DEPRECATED_SUGGEST("allocator_traits::destroy")
     309  	__attribute__((__nonnull__))
     310  	void
     311  	destroy(_Up* __p)
     312  	{ __p->~_Up(); }
     313  
     314        polymorphic_allocator
     315        select_on_container_copy_construction() const noexcept
     316        { return polymorphic_allocator(); }
     317  
     318        memory_resource*
     319        resource() const noexcept
     320        __attribute__((__returns_nonnull__))
     321        { return _M_resource; }
     322  
     323        // _GLIBCXX_RESOLVE_LIB_DEFECTS
     324        // 3683. operator== for polymorphic_allocator cannot deduce template arg
     325        [[nodiscard]]
     326        friend bool
     327        operator==(const polymorphic_allocator& __a,
     328  		 const polymorphic_allocator& __b) noexcept
     329        { return *__a.resource() == *__b.resource(); }
     330  
     331  #if __cpp_impl_three_way_comparison < 201907L
     332        [[nodiscard]]
     333        friend bool
     334        operator!=(const polymorphic_allocator& __a,
     335  		 const polymorphic_allocator& __b) noexcept
     336        { return !(__a == __b); }
     337  #endif
     338  
     339      private:
     340  #if ! __cpp_lib_make_obj_using_allocator
     341        using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
     342        using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
     343  
     344        template<typename _Ind, typename... _Args>
     345  	static tuple<_Args&&...>
     346  	_S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
     347  	{ return std::move(__t); }
     348  
     349        template<size_t... _Ind, typename... _Args>
     350  	static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...>
     351  	_S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>,
     352  		       tuple<_Args...>& __t)
     353  	{
     354  	  return {
     355  	      allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))...
     356  	  };
     357  	}
     358  
     359        template<size_t... _Ind, typename... _Args>
     360  	static tuple<_Args&&..., polymorphic_allocator>
     361  	_S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>,
     362  		       tuple<_Args...>& __t)
     363  	{ return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; }
     364  #endif
     365  
     366        memory_resource* _M_resource;
     367      };
     368  
     369    template<typename _Tp1, typename _Tp2>
     370      [[nodiscard]]
     371      inline bool
     372      operator==(const polymorphic_allocator<_Tp1>& __a,
     373  	       const polymorphic_allocator<_Tp2>& __b) noexcept
     374      { return *__a.resource() == *__b.resource(); }
     375  
     376  #if __cpp_impl_three_way_comparison < 201907L
     377    template<typename _Tp1, typename _Tp2>
     378      [[nodiscard]]
     379      inline bool
     380      operator!=(const polymorphic_allocator<_Tp1>& __a,
     381  	       const polymorphic_allocator<_Tp2>& __b) noexcept
     382      { return !(__a == __b); }
     383  #endif
     384  
     385  } // namespace pmr
     386  
     387    template<typename _Alloc> struct allocator_traits;
     388  
     389    /// Partial specialization for std::pmr::polymorphic_allocator
     390    template<typename _Tp>
     391      struct allocator_traits<pmr::polymorphic_allocator<_Tp>>
     392      {
     393        /// The allocator type
     394        using allocator_type = pmr::polymorphic_allocator<_Tp>;
     395  
     396        /// The allocated type
     397        using value_type = _Tp;
     398  
     399        /// The allocator's pointer type.
     400        using pointer = _Tp*;
     401  
     402        /// The allocator's const pointer type.
     403        using const_pointer = const _Tp*;
     404  
     405        /// The allocator's void pointer type.
     406        using void_pointer = void*;
     407  
     408        /// The allocator's const void pointer type.
     409        using const_void_pointer = const void*;
     410  
     411        /// The allocator's difference type
     412        using difference_type = std::ptrdiff_t;
     413  
     414        /// The allocator's size type
     415        using size_type = std::size_t;
     416  
     417        /** @{
     418         * A `polymorphic_allocator` does not propagate when a
     419         * container is copied, moved, or swapped.
     420         */
     421        using propagate_on_container_copy_assignment = false_type;
     422        using propagate_on_container_move_assignment = false_type;
     423        using propagate_on_container_swap = false_type;
     424  
     425        static allocator_type
     426        select_on_container_copy_construction(const allocator_type&) noexcept
     427        { return allocator_type(); }
     428        /// @}
     429  
     430        /// Whether all instances of the allocator type compare equal.
     431        using is_always_equal = false_type;
     432  
     433        template<typename _Up>
     434  	using rebind_alloc = pmr::polymorphic_allocator<_Up>;
     435  
     436        template<typename _Up>
     437  	using rebind_traits = allocator_traits<pmr::polymorphic_allocator<_Up>>;
     438  
     439        /**
     440         *  @brief  Allocate memory.
     441         *  @param  __a  An allocator.
     442         *  @param  __n  The number of objects to allocate space for.
     443         *
     444         *  Calls `a.allocate(n)`.
     445        */
     446        [[nodiscard]] static pointer
     447        allocate(allocator_type& __a, size_type __n)
     448        { return __a.allocate(__n); }
     449  
     450        /**
     451         *  @brief  Allocate memory.
     452         *  @param  __a  An allocator.
     453         *  @param  __n  The number of objects to allocate space for.
     454         *  @return Memory of suitable size and alignment for `n` objects
     455         *          of type `value_type`.
     456         *
     457         *  The third parameter is ignored..
     458         *
     459         *  Returns `a.allocate(n)`.
     460        */
     461        [[nodiscard]] static pointer
     462        allocate(allocator_type& __a, size_type __n, const_void_pointer)
     463        { return __a.allocate(__n); }
     464  
     465        /**
     466         *  @brief  Deallocate memory.
     467         *  @param  __a  An allocator.
     468         *  @param  __p  Pointer to the memory to deallocate.
     469         *  @param  __n  The number of objects space was allocated for.
     470         *
     471         *  Calls `a.deallocate(p, n)`.
     472        */
     473        static void
     474        deallocate(allocator_type& __a, pointer __p, size_type __n)
     475        { __a.deallocate(__p, __n); }
     476  
     477        /**
     478         *  @brief  Construct an object of type `_Up`
     479         *  @param  __a  An allocator.
     480         *  @param  __p  Pointer to memory of suitable size and alignment for
     481         *	       an object of type `_Up`.
     482         *  @param  __args Constructor arguments.
     483         *
     484         *  Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
     485         *  in C++11, C++14 and C++17. Changed in C++20 to call
     486         *  `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
     487        */
     488        template<typename _Up, typename... _Args>
     489  	static void
     490  	construct(allocator_type& __a, _Up* __p, _Args&&... __args)
     491  	{ __a.construct(__p, std::forward<_Args>(__args)...); }
     492  
     493        /**
     494         *  @brief  Destroy an object of type `_Up`
     495         *  @param  __a  An allocator.
     496         *  @param  __p  Pointer to the object to destroy
     497         *
     498         *  Calls `p->_Up()`.
     499        */
     500        template<typename _Up>
     501  	static _GLIBCXX20_CONSTEXPR void
     502  	destroy(allocator_type&, _Up* __p)
     503  	noexcept(is_nothrow_destructible<_Up>::value)
     504  	{ __p->~_Up(); }
     505  
     506        /**
     507         *  @brief  The maximum supported allocation size
     508         *  @return `numeric_limits<size_t>::max() / sizeof(value_type)`
     509        */
     510        static _GLIBCXX20_CONSTEXPR size_type
     511        max_size(const allocator_type&) noexcept
     512        { return size_t(-1) / sizeof(value_type); }
     513      };
     514  
     515  _GLIBCXX_END_NAMESPACE_VERSION
     516  } // namespace std
     517  
     518  #endif // C++17
     519  #endif // _GLIBCXX_MEMORY_RESOURCE_H