Home | History | Annotate | Download | only in experimental
      1 // -*- C++ -*-
      2 //===------------------------ memory_resource -----------------------------===//
      3 //
      4 //                     The LLVM Compiler Infrastructure
      5 //
      6 // This file is distributed under the University of Illinois Open Source
      7 // License. See LICENSE.TXT for details.
      8 //
      9 //===----------------------------------------------------------------------===//
     10 
     11 #ifndef _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE
     12 #define _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE
     13 
     14 /**
     15     experimental/memory_resource synopsis
     16 
     17 // C++1y
     18 
     19 namespace std {
     20 namespace experimental {
     21 inline namespace fundamentals_v1 {
     22 namespace pmr {
     23 
     24   class memory_resource;
     25 
     26   bool operator==(const memory_resource& a,
     27                   const memory_resource& b) noexcept;
     28   bool operator!=(const memory_resource& a,
     29                   const memory_resource& b) noexcept;
     30 
     31   template <class Tp> class polymorphic_allocator;
     32 
     33   template <class T1, class T2>
     34   bool operator==(const polymorphic_allocator<T1>& a,
     35                   const polymorphic_allocator<T2>& b) noexcept;
     36   template <class T1, class T2>
     37   bool operator!=(const polymorphic_allocator<T1>& a,
     38                   const polymorphic_allocator<T2>& b) noexcept;
     39 
     40   // The name resource_adaptor_imp is for exposition only.
     41   template <class Allocator> class resource_adaptor_imp;
     42 
     43   template <class Allocator>
     44     using resource_adaptor = resource_adaptor_imp<
     45       allocator_traits<Allocator>::rebind_alloc<char>>;
     46 
     47   // Global memory resources
     48   memory_resource* new_delete_resource() noexcept;
     49   memory_resource* null_memory_resource() noexcept;
     50 
     51   // The default memory resource
     52   memory_resource* set_default_resource(memory_resource* r) noexcept;
     53   memory_resource* get_default_resource() noexcept;
     54 
     55   // Standard memory resources
     56   struct pool_options;
     57   class synchronized_pool_resource;
     58   class unsynchronized_pool_resource;
     59   class monotonic_buffer_resource;
     60 
     61 } // namespace pmr
     62 } // namespace fundamentals_v1
     63 } // namespace experimental
     64 } // namespace std
     65 
     66  */
     67 
     68 #include <experimental/__config>
     69 #include <experimental/__memory>
     70 #include <limits>
     71 #include <memory>
     72 #include <new>
     73 #include <stdexcept>
     74 #include <tuple>
     75 #include <type_traits>
     76 #include <utility>
     77 #include <cstddef>
     78 #include <cstdlib>
     79 #include <__debug>
     80 
     81 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
     82 #pragma GCC system_header
     83 #endif
     84 
     85 _LIBCPP_PUSH_MACROS
     86 #include <__undef_macros>
     87 
     88 _LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
     89 
     90 // Round __s up to next multiple of __a.
     91 inline _LIBCPP_INLINE_VISIBILITY
     92 size_t __aligned_allocation_size(size_t __s, size_t __a) _NOEXCEPT
     93 {
     94     _LIBCPP_ASSERT(__s + __a > __s, "aligned allocation size overflows");
     95     return (__s + __a - 1) & ~(__a - 1);
     96 }
     97 
     98 // 8.5, memory.resource
     99 class _LIBCPP_TEMPLATE_VIS memory_resource
    100 {
    101     static const size_t __max_align = alignof(max_align_t);
    102 
    103 // 8.5.2, memory.resource.public
    104 public:
    105     virtual ~memory_resource() = default;
    106 
    107     _LIBCPP_INLINE_VISIBILITY
    108     void* allocate(size_t __bytes, size_t __align = __max_align)
    109         { return do_allocate(__bytes, __align); }
    110 
    111     _LIBCPP_INLINE_VISIBILITY
    112     void deallocate(void * __p, size_t __bytes, size_t __align = __max_align)
    113         { do_deallocate(__p, __bytes, __align); }
    114 
    115     _LIBCPP_INLINE_VISIBILITY
    116     bool is_equal(memory_resource const & __other) const _NOEXCEPT
    117         { return do_is_equal(__other); }
    118 
    119 // 8.5.3, memory.resource.priv
    120 protected:
    121     virtual void* do_allocate(size_t, size_t) = 0;
    122     virtual void do_deallocate(void*, size_t, size_t) = 0;
    123     virtual bool do_is_equal(memory_resource const &) const _NOEXCEPT = 0;
    124 };
    125 
    126 // 8.5.4, memory.resource.eq
    127 inline _LIBCPP_INLINE_VISIBILITY
    128 bool operator==(memory_resource const & __lhs,
    129                 memory_resource const & __rhs) _NOEXCEPT
    130 {
    131     return &__lhs == &__rhs || __lhs.is_equal(__rhs);
    132 }
    133 
    134 inline _LIBCPP_INLINE_VISIBILITY
    135 bool operator!=(memory_resource const & __lhs,
    136                 memory_resource const & __rhs) _NOEXCEPT
    137 {
    138     return !(__lhs == __rhs);
    139 }
    140 
    141 _LIBCPP_FUNC_VIS
    142 memory_resource * new_delete_resource() _NOEXCEPT;
    143 
    144 _LIBCPP_FUNC_VIS
    145 memory_resource * null_memory_resource() _NOEXCEPT;
    146 
    147 _LIBCPP_FUNC_VIS
    148 memory_resource * get_default_resource() _NOEXCEPT;
    149 
    150 _LIBCPP_FUNC_VIS
    151 memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT;
    152 
    153 // 8.6, memory.polymorphic.allocator.class
    154 
    155 // 8.6.1, memory.polymorphic.allocator.overview
    156 template <class _ValueType>
    157 class _LIBCPP_TEMPLATE_VIS polymorphic_allocator
    158 {
    159 public:
    160     typedef _ValueType value_type;
    161 
    162     // 8.6.2, memory.polymorphic.allocator.ctor
    163     _LIBCPP_INLINE_VISIBILITY
    164     polymorphic_allocator() _NOEXCEPT
    165       : __res_(_VSTD_LFTS_PMR::get_default_resource())
    166     {}
    167 
    168     _LIBCPP_INLINE_VISIBILITY
    169     polymorphic_allocator(memory_resource * __r) _NOEXCEPT
    170       : __res_(__r)
    171     {}
    172 
    173     polymorphic_allocator(polymorphic_allocator const &) = default;
    174 
    175     template <class _Tp>
    176     _LIBCPP_INLINE_VISIBILITY
    177     polymorphic_allocator(polymorphic_allocator<_Tp> const & __other) _NOEXCEPT
    178       : __res_(__other.resource())
    179     {}
    180 
    181     polymorphic_allocator &
    182     operator=(polymorphic_allocator const &) = delete;
    183 
    184     // 8.6.3, memory.polymorphic.allocator.mem
    185     _LIBCPP_INLINE_VISIBILITY
    186     _ValueType* allocate(size_t __n) {
    187         if (__n > __max_size()) {
    188             __throw_length_error(
    189                 "std::experimental::pmr::polymorphic_allocator<T>::allocate(size_t n)"
    190                 " 'n' exceeds maximum supported size");
    191         }
    192         return static_cast<_ValueType*>(
    193             __res_->allocate(__n * sizeof(_ValueType), alignof(_ValueType))
    194         );
    195     }
    196 
    197     _LIBCPP_INLINE_VISIBILITY
    198     void deallocate(_ValueType * __p, size_t __n) _NOEXCEPT {
    199         _LIBCPP_ASSERT(__n <= __max_size(),
    200                        "deallocate called for size which exceeds max_size()");
    201         __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType));
    202     }
    203 
    204     template <class _Tp, class ..._Ts>
    205     _LIBCPP_INLINE_VISIBILITY
    206     void construct(_Tp* __p, _Ts &&... __args)
    207     {
    208         _VSTD_LFTS::__lfts_user_alloc_construct(
    209             __p, resource(), _VSTD::forward<_Ts>(__args)...
    210           );
    211     }
    212 
    213     template <class _T1, class _T2, class ..._Args1, class ..._Args2>
    214     _LIBCPP_INLINE_VISIBILITY
    215     void construct(pair<_T1, _T2>* __p, piecewise_construct_t,
    216                    tuple<_Args1...> __x, tuple<_Args2...> __y)
    217     {
    218         ::new ((void*)__p) pair<_T1, _T2>(piecewise_construct
    219           , __transform_tuple(
    220               typename __lfts_uses_alloc_ctor<
    221                   _T1, memory_resource*, _Args1...
    222               >::type()
    223             , _VSTD::move(__x)
    224             , typename __make_tuple_indices<sizeof...(_Args1)>::type{}
    225           )
    226           , __transform_tuple(
    227               typename __lfts_uses_alloc_ctor<
    228                   _T2, memory_resource*, _Args2...
    229               >::type()
    230             , _VSTD::move(__y)
    231             , typename __make_tuple_indices<sizeof...(_Args2)>::type{}
    232           )
    233         );
    234     }
    235 
    236     template <class _T1, class _T2>
    237     _LIBCPP_INLINE_VISIBILITY
    238     void construct(pair<_T1, _T2>* __p) {
    239         construct(__p, piecewise_construct, tuple<>(), tuple<>());
    240     }
    241 
    242     template <class _T1, class _T2, class _Up, class _Vp>
    243     _LIBCPP_INLINE_VISIBILITY
    244     void construct(pair<_T1, _T2> * __p, _Up && __u, _Vp && __v) {
    245         construct(__p, piecewise_construct
    246           , _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__u))
    247           , _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__v)));
    248     }
    249 
    250     template <class _T1, class _T2, class _U1, class _U2>
    251     _LIBCPP_INLINE_VISIBILITY
    252     void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> const & __pr) {
    253         construct(__p, piecewise_construct
    254             , _VSTD::forward_as_tuple(__pr.first)
    255             , _VSTD::forward_as_tuple(__pr.second));
    256     }
    257 
    258     template <class _T1, class _T2, class _U1, class _U2>
    259     _LIBCPP_INLINE_VISIBILITY
    260     void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> && __pr){
    261         construct(__p, piecewise_construct
    262             , _VSTD::forward_as_tuple(_VSTD::forward<_U1>(__pr.first))
    263             , _VSTD::forward_as_tuple(_VSTD::forward<_U2>(__pr.second)));
    264     }
    265 
    266     template <class _Tp>
    267     _LIBCPP_INLINE_VISIBILITY
    268     void destroy(_Tp * __p) _NOEXCEPT
    269         { __p->~_Tp(); }
    270 
    271     _LIBCPP_INLINE_VISIBILITY
    272     polymorphic_allocator
    273     select_on_container_copy_construction() const _NOEXCEPT
    274         { return polymorphic_allocator(); }
    275 
    276     _LIBCPP_INLINE_VISIBILITY
    277     memory_resource * resource() const _NOEXCEPT
    278         { return __res_; }
    279 
    280 private:
    281     template <class ..._Args, size_t ..._Idx>
    282     _LIBCPP_INLINE_VISIBILITY
    283     tuple<_Args&&...>
    284     __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t,
    285                       __tuple_indices<_Idx...>) const
    286     {
    287         return _VSTD::forward_as_tuple(_VSTD::get<_Idx>(_VSTD::move(__t))...);
    288     }
    289 
    290     template <class ..._Args, size_t ..._Idx>
    291     _LIBCPP_INLINE_VISIBILITY
    292     tuple<allocator_arg_t const&, memory_resource*, _Args&&...>
    293     __transform_tuple(integral_constant<int, 1>, tuple<_Args...> && __t,
    294                       __tuple_indices<_Idx...>) const
    295     {
    296         using _Tup = tuple<allocator_arg_t const&, memory_resource*, _Args&&...>;
    297         return _Tup(allocator_arg, resource(),
    298                     _VSTD::get<_Idx>(_VSTD::move(__t))...);
    299     }
    300 
    301     template <class ..._Args, size_t ..._Idx>
    302     _LIBCPP_INLINE_VISIBILITY
    303     tuple<_Args&&..., memory_resource*>
    304     __transform_tuple(integral_constant<int, 2>, tuple<_Args...> && __t,
    305                       __tuple_indices<_Idx...>) const
    306     {
    307         using _Tup = tuple<_Args&&..., memory_resource*>;
    308         return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., resource());
    309     }
    310 
    311     _LIBCPP_INLINE_VISIBILITY
    312     size_t __max_size() const _NOEXCEPT
    313         { return numeric_limits<size_t>::max() / sizeof(value_type); }
    314 
    315     memory_resource * __res_;
    316 };
    317 
    318 // 8.6.4, memory.polymorphic.allocator.eq
    319 
    320 template <class _Tp, class _Up>
    321 inline _LIBCPP_INLINE_VISIBILITY
    322 bool operator==(polymorphic_allocator<_Tp> const & __lhs,
    323                 polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT
    324 {
    325     return *__lhs.resource() == *__rhs.resource();
    326 }
    327 
    328 template <class _Tp, class _Up>
    329 inline _LIBCPP_INLINE_VISIBILITY
    330 bool operator!=(polymorphic_allocator<_Tp> const & __lhs,
    331                 polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT
    332 {
    333     return !(__lhs == __rhs);
    334 }
    335 
    336 // 8.7, memory.resource.adaptor
    337 
    338 // 8.7.1, memory.resource.adaptor.overview
    339 template <class _CharAlloc>
    340 class _LIBCPP_TEMPLATE_VIS __resource_adaptor_imp
    341   : public memory_resource
    342 {
    343     using _CTraits = allocator_traits<_CharAlloc>;
    344     static_assert(is_same<typename _CTraits::value_type, char>::value
    345                && is_same<typename _CTraits::pointer, char*>::value
    346                && is_same<typename _CTraits::void_pointer, void*>::value, "");
    347 
    348     static const size_t _MaxAlign = alignof(max_align_t);
    349 
    350     using _Alloc = typename _CTraits::template rebind_alloc<
    351             typename aligned_storage<_MaxAlign, _MaxAlign>::type
    352         >;
    353 
    354     using _ValueType = typename _Alloc::value_type;
    355 
    356     _Alloc __alloc_;
    357 
    358 public:
    359     typedef _CharAlloc allocator_type;
    360 
    361     __resource_adaptor_imp() = default;
    362     __resource_adaptor_imp(__resource_adaptor_imp const &) = default;
    363     __resource_adaptor_imp(__resource_adaptor_imp &&) = default;
    364 
    365     // 8.7.2, memory.resource.adaptor.ctor
    366 
    367     _LIBCPP_INLINE_VISIBILITY
    368     explicit __resource_adaptor_imp(allocator_type const & __a)
    369       : __alloc_(__a)
    370     {}
    371 
    372     _LIBCPP_INLINE_VISIBILITY
    373     explicit __resource_adaptor_imp(allocator_type && __a)
    374       : __alloc_(_VSTD::move(__a))
    375     {}
    376 
    377     __resource_adaptor_imp &
    378     operator=(__resource_adaptor_imp const &) = default;
    379 
    380     _LIBCPP_INLINE_VISIBILITY
    381     allocator_type get_allocator() const
    382     { return __alloc_; }
    383 
    384 // 8.7.3, memory.resource.adaptor.mem
    385 protected:
    386     virtual void * do_allocate(size_t __bytes, size_t)
    387     {
    388         if (__bytes > __max_size()) {
    389             __throw_length_error(
    390                 "std::experimental::pmr::resource_adaptor<T>::do_allocate(size_t bytes, size_t align)"
    391                 " 'bytes' exceeds maximum supported size");
    392         }
    393         size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
    394         return __alloc_.allocate(__s);
    395     }
    396 
    397     virtual void do_deallocate(void * __p, size_t __bytes, size_t)
    398     {
    399         _LIBCPP_ASSERT(__bytes <= __max_size(),
    400             "do_deallocate called for size which exceeds the maximum allocation size");
    401         size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
    402         __alloc_.deallocate((_ValueType*)__p, __s);
    403     }
    404 
    405     virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT {
    406         __resource_adaptor_imp const * __p
    407           = dynamic_cast<__resource_adaptor_imp const *>(&__other);
    408         return __p  ? __alloc_ == __p->__alloc_ : false;
    409     }
    410 
    411 private:
    412     _LIBCPP_INLINE_VISIBILITY
    413     size_t __max_size() const _NOEXCEPT {
    414         return numeric_limits<size_t>::max() - _MaxAlign;
    415     }
    416 };
    417 
    418 template <class _Alloc>
    419 using resource_adaptor = __resource_adaptor_imp<
    420     typename allocator_traits<_Alloc>::template rebind_alloc<char>
    421   >;
    422 
    423 _LIBCPP_END_NAMESPACE_LFTS_PMR
    424 
    425 _LIBCPP_POP_MACROS
    426 
    427 #endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */
    428