xref: /dflybsd-src/contrib/gcc-8.0/libstdc++-v3/include/experimental/memory_resource (revision 95059079af47f9a66a175f374f2da1a5020e3255)
138fd1498Szrj// <experimental/memory_resource> -*- C++ -*-
238fd1498Szrj
338fd1498Szrj// Copyright (C) 2015-2018 Free Software Foundation, Inc.
438fd1498Szrj//
538fd1498Szrj// This file is part of the GNU ISO C++ Library.  This library is free
638fd1498Szrj// software; you can redistribute it and/or modify it under the
738fd1498Szrj// terms of the GNU General Public License as published by the
838fd1498Szrj// Free Software Foundation; either version 3, or (at your option)
938fd1498Szrj// any later version.
1038fd1498Szrj
1138fd1498Szrj// This library is distributed in the hope that it will be useful,
1238fd1498Szrj// but WITHOUT ANY WARRANTY; without even the implied warranty of
1338fd1498Szrj// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1438fd1498Szrj// GNU General Public License for more details.
1538fd1498Szrj
1638fd1498Szrj// Under Section 7 of GPL version 3, you are granted additional
1738fd1498Szrj// permissions described in the GCC Runtime Library Exception, version
1838fd1498Szrj// 3.1, as published by the Free Software Foundation.
1938fd1498Szrj
2038fd1498Szrj// You should have received a copy of the GNU General Public License and
2138fd1498Szrj// a copy of the GCC Runtime Library Exception along with this program;
2238fd1498Szrj// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2338fd1498Szrj// <http://www.gnu.org/licenses/>.
2438fd1498Szrj
2538fd1498Szrj/** @file experimental/memory_resource
2638fd1498Szrj *  This is a TS C++ Library header.
2738fd1498Szrj */
2838fd1498Szrj
2938fd1498Szrj#ifndef _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE
3038fd1498Szrj#define _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE 1
3138fd1498Szrj
3238fd1498Szrj#include <memory>
3338fd1498Szrj#include <new>
3438fd1498Szrj#include <atomic>
3538fd1498Szrj#include <cstddef>
3638fd1498Szrj#include <experimental/bits/lfts_config.h>
3738fd1498Szrj
3838fd1498Szrjnamespace std {
3938fd1498Szrj_GLIBCXX_BEGIN_NAMESPACE_VERSION
4038fd1498Szrj
4138fd1498Szrjnamespace experimental {
4238fd1498Szrjinline namespace fundamentals_v2 {
4338fd1498Szrjnamespace pmr {
4438fd1498Szrj#define __cpp_lib_experimental_memory_resources 201402L
4538fd1498Szrj
4638fd1498Szrj  class memory_resource;
4738fd1498Szrj
4838fd1498Szrj  template <typename _Tp>
4938fd1498Szrj    class polymorphic_allocator;
5038fd1498Szrj
5138fd1498Szrj  template <typename _Alloc>
5238fd1498Szrj    class __resource_adaptor_imp;
5338fd1498Szrj
5438fd1498Szrj  template <typename _Alloc>
5538fd1498Szrj    using resource_adaptor = __resource_adaptor_imp<
5638fd1498Szrj      typename allocator_traits<_Alloc>::template rebind_alloc<char>>;
5738fd1498Szrj
5838fd1498Szrj  template <typename _Tp>
5938fd1498Szrj    struct __uses_allocator_construction_helper;
6038fd1498Szrj
6138fd1498Szrj  // Global memory resources
6238fd1498Szrj  memory_resource* new_delete_resource() noexcept;
6338fd1498Szrj  memory_resource* null_memory_resource() noexcept;
6438fd1498Szrj
6538fd1498Szrj  // The default memory resource
6638fd1498Szrj  memory_resource* get_default_resource() noexcept;
6738fd1498Szrj  memory_resource* set_default_resource(memory_resource* __r) noexcept;
6838fd1498Szrj
6938fd1498Szrj  // Standard memory resources
7038fd1498Szrj
7138fd1498Szrj  // 8.5 Class memory_resource
7238fd1498Szrj  class memory_resource
7338fd1498Szrj  {
7438fd1498Szrj  protected:
7538fd1498Szrj    static constexpr size_t _S_max_align = alignof(max_align_t);
7638fd1498Szrj
7738fd1498Szrj  public:
7838fd1498Szrj    virtual ~memory_resource() { }
7938fd1498Szrj
8038fd1498Szrj    void*
8138fd1498Szrj    allocate(size_t __bytes, size_t __alignment = _S_max_align)
8238fd1498Szrj    { return do_allocate(__bytes, __alignment); }
8338fd1498Szrj
8438fd1498Szrj    void
8538fd1498Szrj    deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
8638fd1498Szrj    { return do_deallocate(__p, __bytes, __alignment); }
8738fd1498Szrj
8838fd1498Szrj    bool
8938fd1498Szrj    is_equal(const memory_resource& __other) const noexcept
9038fd1498Szrj    { return do_is_equal(__other); }
9138fd1498Szrj
9238fd1498Szrj  protected:
9338fd1498Szrj    virtual void*
9438fd1498Szrj    do_allocate(size_t __bytes, size_t __alignment) = 0;
9538fd1498Szrj
9638fd1498Szrj    virtual void
9738fd1498Szrj    do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;
9838fd1498Szrj
9938fd1498Szrj    virtual bool
10038fd1498Szrj    do_is_equal(const memory_resource& __other) const noexcept = 0;
10138fd1498Szrj  };
10238fd1498Szrj
10338fd1498Szrj  inline bool
10438fd1498Szrj  operator==(const memory_resource& __a,
10538fd1498Szrj	     const memory_resource& __b) noexcept
10638fd1498Szrj  { return &__a == &__b || __a.is_equal(__b); }
10738fd1498Szrj
10838fd1498Szrj  inline bool
10938fd1498Szrj  operator!=(const memory_resource& __a,
11038fd1498Szrj	     const memory_resource& __b) noexcept
11138fd1498Szrj  { return !(__a == __b); }
11238fd1498Szrj
11338fd1498Szrj
11438fd1498Szrj  // 8.6 Class template polymorphic_allocator
11538fd1498Szrj  template <class _Tp>
11638fd1498Szrj    class polymorphic_allocator
11738fd1498Szrj    {
11838fd1498Szrj      using __uses_alloc1_ = __uses_alloc1<memory_resource*>;
11938fd1498Szrj      using __uses_alloc2_ = __uses_alloc2<memory_resource*>;
12038fd1498Szrj
12138fd1498Szrj      template<typename _Tp1, typename... _Args>
12238fd1498Szrj	void
12338fd1498Szrj	_M_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args)
12438fd1498Szrj	{ ::new(__p) _Tp1(std::forward<_Args>(__args)...); }
12538fd1498Szrj
12638fd1498Szrj      template<typename _Tp1, typename... _Args>
12738fd1498Szrj	void
12838fd1498Szrj	_M_construct(__uses_alloc1_, _Tp1* __p, _Args&&...  __args)
12938fd1498Szrj	{ ::new(__p) _Tp1(allocator_arg, this->resource(),
13038fd1498Szrj			  std::forward<_Args>(__args)...); }
13138fd1498Szrj
13238fd1498Szrj      template<typename _Tp1, typename... _Args>
13338fd1498Szrj	void
13438fd1498Szrj	_M_construct(__uses_alloc2_, _Tp1* __p, _Args&&...  __args)
13538fd1498Szrj	{ ::new(__p) _Tp1(std::forward<_Args>(__args)...,
13638fd1498Szrj			  this->resource()); }
13738fd1498Szrj
13838fd1498Szrj    public:
13938fd1498Szrj      using value_type = _Tp;
14038fd1498Szrj
14138fd1498Szrj      polymorphic_allocator() noexcept
14238fd1498Szrj      : _M_resource(get_default_resource())
14338fd1498Szrj      { }
14438fd1498Szrj
14538fd1498Szrj      polymorphic_allocator(memory_resource* __r)
14638fd1498Szrj      : _M_resource(__r)
14738fd1498Szrj      { _GLIBCXX_DEBUG_ASSERT(__r); }
14838fd1498Szrj
14938fd1498Szrj      polymorphic_allocator(const polymorphic_allocator& __other) = default;
15038fd1498Szrj
15138fd1498Szrj      template <typename _Up>
15238fd1498Szrj	polymorphic_allocator(const polymorphic_allocator<_Up>&
15338fd1498Szrj			      __other) noexcept
15438fd1498Szrj	: _M_resource(__other.resource())
15538fd1498Szrj	{ }
15638fd1498Szrj
15738fd1498Szrj      polymorphic_allocator&
15838fd1498Szrj	operator=(const polymorphic_allocator& __rhs) = default;
15938fd1498Szrj
16038fd1498Szrj      _Tp* allocate(size_t __n)
16138fd1498Szrj      { return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
16238fd1498Szrj						       alignof(_Tp))); }
16338fd1498Szrj
16438fd1498Szrj      void deallocate(_Tp* __p, size_t __n)
16538fd1498Szrj      { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
16638fd1498Szrj
16738fd1498Szrj      template <typename _Tp1, typename... _Args> //used here
16838fd1498Szrj	void construct(_Tp1* __p, _Args&&... __args)
16938fd1498Szrj	{
17038fd1498Szrj	  memory_resource* const __resource = this->resource();
17138fd1498Szrj	  auto __use_tag
17238fd1498Szrj	    = __use_alloc<_Tp1, memory_resource*, _Args...>(__resource);
17338fd1498Szrj	  _M_construct(__use_tag, __p, std::forward<_Args>(__args)...);
17438fd1498Szrj	}
17538fd1498Szrj
17638fd1498Szrj      // Specializations for pair using piecewise construction
17738fd1498Szrj      template <typename _Tp1, typename _Tp2,
17838fd1498Szrj	       typename... _Args1, typename... _Args2>
17938fd1498Szrj	void construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
18038fd1498Szrj		       tuple<_Args1...> __x,
18138fd1498Szrj		       tuple<_Args2...> __y)
18238fd1498Szrj	{
18338fd1498Szrj	  memory_resource* const __resource = this->resource();
18438fd1498Szrj	  auto __x_use_tag =
18538fd1498Szrj	    __use_alloc<_Tp1, memory_resource*, _Args1...>(__resource);
18638fd1498Szrj	  auto __y_use_tag =
18738fd1498Szrj	    __use_alloc<_Tp2, memory_resource*, _Args2...>(__resource);
18838fd1498Szrj
18938fd1498Szrj	  ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct,
19038fd1498Szrj					   _M_construct_p(__x_use_tag, __x),
19138fd1498Szrj					   _M_construct_p(__y_use_tag, __y));
19238fd1498Szrj	}
19338fd1498Szrj
19438fd1498Szrj      template <typename _Tp1, typename _Tp2>
19538fd1498Szrj	void construct(pair<_Tp1,_Tp2>* __p)
19638fd1498Szrj	{ this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
19738fd1498Szrj
19838fd1498Szrj      template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
19938fd1498Szrj	void construct(pair<_Tp1,_Tp2>* __p, _Up&& __x, _Vp&& __y)
20038fd1498Szrj	{ this->construct(__p, piecewise_construct,
20138fd1498Szrj			  forward_as_tuple(std::forward<_Up>(__x)),
20238fd1498Szrj			  forward_as_tuple(std::forward<_Vp>(__y))); }
20338fd1498Szrj
20438fd1498Szrj      template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
20538fd1498Szrj	void construct(pair<_Tp1,_Tp2>* __p, const std::pair<_Up, _Vp>& __pr)
20638fd1498Szrj	{ this->construct(__p, piecewise_construct, forward_as_tuple(__pr.first),
20738fd1498Szrj			  forward_as_tuple(__pr.second)); }
20838fd1498Szrj
20938fd1498Szrj      template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
21038fd1498Szrj	void construct(pair<_Tp1,_Tp2>* __p, pair<_Up, _Vp>&& __pr)
21138fd1498Szrj	{ this->construct(__p, piecewise_construct,
21238fd1498Szrj			  forward_as_tuple(std::forward<_Up>(__pr.first)),
21338fd1498Szrj			  forward_as_tuple(std::forward<_Vp>(__pr.second))); }
21438fd1498Szrj
21538fd1498Szrj      template <typename _Up>
21638fd1498Szrj	void destroy(_Up* __p)
21738fd1498Szrj	{ __p->~_Up(); }
21838fd1498Szrj
21938fd1498Szrj      // Return a default-constructed allocator (no allocator propagation)
22038fd1498Szrj      polymorphic_allocator select_on_container_copy_construction() const
22138fd1498Szrj      { return polymorphic_allocator(); }
22238fd1498Szrj
22338fd1498Szrj      memory_resource* resource() const
22438fd1498Szrj      { return _M_resource; }
22538fd1498Szrj
22638fd1498Szrj    private:
22738fd1498Szrj      template<typename _Tuple>
22838fd1498Szrj	_Tuple&&
22938fd1498Szrj	_M_construct_p(__uses_alloc0, _Tuple& __t)
23038fd1498Szrj	{ return std::move(__t); }
23138fd1498Szrj
23238fd1498Szrj      template<typename... _Args>
23338fd1498Szrj	decltype(auto)
23438fd1498Szrj	_M_construct_p(__uses_alloc1_ __ua, tuple<_Args...>& __t)
23538fd1498Szrj	{ return tuple_cat(make_tuple(allocator_arg, *(__ua._M_a)),
23638fd1498Szrj			   std::move(__t)); }
23738fd1498Szrj
23838fd1498Szrj      template<typename... _Args>
23938fd1498Szrj	decltype(auto)
24038fd1498Szrj	_M_construct_p(__uses_alloc2_ __ua, tuple<_Args...>& __t)
24138fd1498Szrj	{ return tuple_cat(std::move(__t), make_tuple(*(__ua._M_a))); }
24238fd1498Szrj
24338fd1498Szrj      memory_resource* _M_resource;
24438fd1498Szrj    };
24538fd1498Szrj
24638fd1498Szrj  template <class _Tp1, class _Tp2>
24738fd1498Szrj    bool operator==(const polymorphic_allocator<_Tp1>& __a,
24838fd1498Szrj		    const polymorphic_allocator<_Tp2>& __b) noexcept
24938fd1498Szrj    { return *__a.resource() == *__b.resource(); }
25038fd1498Szrj
25138fd1498Szrj  template <class _Tp1, class _Tp2>
25238fd1498Szrj    bool operator!=(const polymorphic_allocator<_Tp1>& __a,
25338fd1498Szrj		    const polymorphic_allocator<_Tp2>& __b) noexcept
25438fd1498Szrj    { return !(__a == __b); }
25538fd1498Szrj
25638fd1498Szrj  // 8.7.1 __resource_adaptor_imp
25738fd1498Szrj  template <typename _Alloc>
25838fd1498Szrj    class __resource_adaptor_imp : public memory_resource
25938fd1498Szrj    {
260*58e805e6Szrj      static_assert(is_same<char,
261*58e805e6Szrj	  typename allocator_traits<_Alloc>::value_type>::value,
262*58e805e6Szrj	  "Allocator's value_type is char");
263*58e805e6Szrj      static_assert(is_same<char*,
264*58e805e6Szrj	  typename allocator_traits<_Alloc>::pointer>::value,
265*58e805e6Szrj	  "Allocator's pointer type is value_type*");
266*58e805e6Szrj      static_assert(is_same<const char*,
267*58e805e6Szrj	  typename allocator_traits<_Alloc>::const_pointer>::value,
268*58e805e6Szrj	  "Allocator's const_pointer type is value_type const*");
269*58e805e6Szrj      static_assert(is_same<void*,
270*58e805e6Szrj	  typename allocator_traits<_Alloc>::void_pointer>::value,
271*58e805e6Szrj	  "Allocator's void_pointer type is void*");
272*58e805e6Szrj      static_assert(is_same<const void*,
273*58e805e6Szrj	  typename allocator_traits<_Alloc>::const_void_pointer>::value,
274*58e805e6Szrj	  "Allocator's const_void_pointer type is void const*");
275*58e805e6Szrj
27638fd1498Szrj    public:
27738fd1498Szrj      using allocator_type = _Alloc;
27838fd1498Szrj
27938fd1498Szrj      __resource_adaptor_imp() = default;
28038fd1498Szrj      __resource_adaptor_imp(const __resource_adaptor_imp&) = default;
28138fd1498Szrj      __resource_adaptor_imp(__resource_adaptor_imp&&) = default;
28238fd1498Szrj
28338fd1498Szrj      explicit __resource_adaptor_imp(const _Alloc& __a2)
28438fd1498Szrj      : _M_alloc(__a2)
28538fd1498Szrj      { }
28638fd1498Szrj
28738fd1498Szrj      explicit __resource_adaptor_imp(_Alloc&& __a2)
28838fd1498Szrj      : _M_alloc(std::move(__a2))
28938fd1498Szrj      { }
29038fd1498Szrj
29138fd1498Szrj      __resource_adaptor_imp&
29238fd1498Szrj      operator=(const __resource_adaptor_imp&) = default;
29338fd1498Szrj
294*58e805e6Szrj      allocator_type get_allocator() const noexcept { return _M_alloc; }
29538fd1498Szrj
29638fd1498Szrj    protected:
29738fd1498Szrj      virtual void*
29838fd1498Szrj      do_allocate(size_t __bytes, size_t __alignment)
29938fd1498Szrj      {
30038fd1498Szrj	using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>;
30138fd1498Szrj	size_t __new_size = _S_aligned_size(__bytes,
30238fd1498Szrj					    _S_supported(__alignment) ?
30338fd1498Szrj					    __alignment : _S_max_align);
30438fd1498Szrj	return _Aligned_alloc(_M_alloc).allocate(__new_size);
30538fd1498Szrj      }
30638fd1498Szrj
30738fd1498Szrj      virtual void
30838fd1498Szrj      do_deallocate(void* __p, size_t __bytes, size_t __alignment)
30938fd1498Szrj      {
31038fd1498Szrj	using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>;
31138fd1498Szrj	size_t __new_size = _S_aligned_size(__bytes,
31238fd1498Szrj					    _S_supported(__alignment) ?
31338fd1498Szrj					    __alignment : _S_max_align);
31438fd1498Szrj	using _Ptr = typename allocator_traits<_Aligned_alloc>::pointer;
31538fd1498Szrj	_Aligned_alloc(_M_alloc).deallocate(static_cast<_Ptr>(__p),
31638fd1498Szrj					    __new_size);
31738fd1498Szrj      }
31838fd1498Szrj
31938fd1498Szrj      virtual bool
32038fd1498Szrj      do_is_equal(const memory_resource& __other) const noexcept
32138fd1498Szrj      {
32238fd1498Szrj	auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other);
32338fd1498Szrj	return __p ? (_M_alloc == __p->_M_alloc) : false;
32438fd1498Szrj      }
32538fd1498Szrj
32638fd1498Szrj    private:
32738fd1498Szrj      // Calculate Aligned Size
32838fd1498Szrj      // Returns a size that is larger than or equal to __size and divisible
329*58e805e6Szrj      // by __alignment, where __alignment is required to be a power of 2.
33038fd1498Szrj      static size_t
33138fd1498Szrj      _S_aligned_size(size_t __size, size_t __alignment)
33238fd1498Szrj      { return ((__size - 1)|(__alignment - 1)) + 1; }
33338fd1498Szrj
33438fd1498Szrj      // Determine whether alignment meets one of those preconditions:
335*58e805e6Szrj      // 1. Equal to Zero
33638fd1498Szrj      // 2. Is power of two
33738fd1498Szrj      static bool
33838fd1498Szrj      _S_supported (size_t __x)
33938fd1498Szrj      { return ((__x != 0) && !(__x & (__x - 1))); }
34038fd1498Szrj
34138fd1498Szrj      _Alloc _M_alloc;
34238fd1498Szrj    };
34338fd1498Szrj
34438fd1498Szrj  // Global memory resources
34538fd1498Szrj
34638fd1498Szrj  inline memory_resource*
34738fd1498Szrj  new_delete_resource() noexcept
34838fd1498Szrj  {
349*58e805e6Szrj    using type = resource_adaptor<std::allocator<char>>;
350*58e805e6Szrj    alignas(type) static unsigned char __buf[sizeof(type)];
351*58e805e6Szrj    static type* __r = new(__buf) type;
352*58e805e6Szrj    return __r;
35338fd1498Szrj  }
35438fd1498Szrj
35538fd1498Szrj  inline memory_resource*
35638fd1498Szrj  null_memory_resource() noexcept
35738fd1498Szrj  {
358*58e805e6Szrj    class type final : public memory_resource
359*58e805e6Szrj    {
360*58e805e6Szrj      void*
361*58e805e6Szrj      do_allocate(size_t, size_t) override
362*58e805e6Szrj      { std::__throw_bad_alloc(); }
363*58e805e6Szrj
364*58e805e6Szrj      void
365*58e805e6Szrj      do_deallocate(void*, size_t, size_t) noexcept override
366*58e805e6Szrj      { }
367*58e805e6Szrj
368*58e805e6Szrj      bool
369*58e805e6Szrj      do_is_equal(const memory_resource& __other) const noexcept override
370*58e805e6Szrj      { return this == &__other; }
371*58e805e6Szrj    };
372*58e805e6Szrj
373*58e805e6Szrj    alignas(type) static unsigned char __buf[sizeof(type)];
374*58e805e6Szrj    static type* __r = new(__buf) type;
375*58e805e6Szrj    return __r;
37638fd1498Szrj  }
37738fd1498Szrj
37838fd1498Szrj  // The default memory resource
379*58e805e6Szrj
380*58e805e6Szrj  inline std::atomic<memory_resource*>&
381*58e805e6Szrj  __get_default_resource()
382*58e805e6Szrj  {
383*58e805e6Szrj    using type = atomic<memory_resource*>;
384*58e805e6Szrj    alignas(type) static unsigned char __buf[sizeof(type)];
385*58e805e6Szrj    static type* __r = new(__buf) type(new_delete_resource());
386*58e805e6Szrj    return *__r;
387*58e805e6Szrj  }
388*58e805e6Szrj
38938fd1498Szrj  inline memory_resource*
39038fd1498Szrj  get_default_resource() noexcept
39138fd1498Szrj  { return __get_default_resource().load(); }
39238fd1498Szrj
39338fd1498Szrj  inline memory_resource*
39438fd1498Szrj  set_default_resource(memory_resource* __r) noexcept
39538fd1498Szrj  {
39638fd1498Szrj    if (__r == nullptr)
39738fd1498Szrj      __r = new_delete_resource();
39838fd1498Szrj    return __get_default_resource().exchange(__r);
39938fd1498Szrj  }
40038fd1498Szrj} // namespace pmr
40138fd1498Szrj} // namespace fundamentals_v2
40238fd1498Szrj} // namespace experimental
40338fd1498Szrj
40438fd1498Szrj_GLIBCXX_END_NAMESPACE_VERSION
40538fd1498Szrj} // namespace std
40638fd1498Szrj
40738fd1498Szrj#endif
408