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_BEGIN_NAMESPACE_LFTS_PMR
     86 
     87 // Round __s up to next multiple of __a.
     88 inline _LIBCPP_INLINE_VISIBILITY
     89 size_t __aligned_allocation_size(size_t __s, size_t __a) _NOEXCEPT
     90 {
     91     _LIBCPP_ASSERT(__s + __a > __s, "aligned allocation size overflows");
     92     return (__s + __a - 1) & ~(__a - 1);
     93 }
     94 
     95 // 8.5, memory.resource
     96 class _LIBCPP_TEMPLATE_VIS memory_resource
     97 {
     98     static const size_t __max_align = alignof(max_align_t);
     99 
    100 // 8.5.2, memory.resource.public
    101 public:
    102     virtual ~memory_resource() = default;
    103 
    104     _LIBCPP_INLINE_VISIBILITY
    105     void* allocate(size_t __bytes, size_t __align = __max_align)
    106         { return do_allocate(__bytes, __align); }
    107 
    108     _LIBCPP_INLINE_VISIBILITY
    109     void deallocate(void * __p, size_t __bytes, size_t __align = __max_align)
    110         { do_deallocate(__p, __bytes, __align); }
    111 
    112     _LIBCPP_INLINE_VISIBILITY
    113     bool is_equal(memory_resource const & __other) const _NOEXCEPT
    114         { return do_is_equal(__other); }
    115 
    116 // 8.5.3, memory.resource.priv
    117 protected:
    118     virtual void* do_allocate(size_t, size_t) = 0;
    119     virtual void do_deallocate(void*, size_t, size_t) = 0;
    120     virtual bool do_is_equal(memory_resource const &) const _NOEXCEPT = 0;
    121 };
    122 
    123 // 8.5.4, memory.resource.eq
    124 inline _LIBCPP_INLINE_VISIBILITY
    125 bool operator==(memory_resource const & __lhs,
    126                 memory_resource const & __rhs) _NOEXCEPT
    127 {
    128     return &__lhs == &__rhs || __lhs.is_equal(__rhs);
    129 }
    130 
    131 inline _LIBCPP_INLINE_VISIBILITY
    132 bool operator!=(memory_resource const & __lhs,
    133                 memory_resource const & __rhs) _NOEXCEPT
    134 {
    135     return !(__lhs == __rhs);
    136 }
    137 
    138 _LIBCPP_FUNC_VIS
    139 memory_resource * new_delete_resource() _NOEXCEPT;
    140 
    141 _LIBCPP_FUNC_VIS
    142 memory_resource * null_memory_resource() _NOEXCEPT;
    143 
    144 _LIBCPP_FUNC_VIS
    145 memory_resource * get_default_resource() _NOEXCEPT;
    146 
    147 _LIBCPP_FUNC_VIS
    148 memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT;
    149 
    150 // 8.6, memory.polymorphic.allocator.class
    151 
    152 // 8.6.1, memory.polymorphic.allocator.overview
    153 template <class _ValueType>
    154 class _LIBCPP_TEMPLATE_VIS polymorphic_allocator
    155 {
    156 public:
    157     typedef _ValueType value_type;
    158 
    159     // 8.6.2, memory.polymorphic.allocator.ctor
    160     _LIBCPP_INLINE_VISIBILITY
    161     polymorphic_allocator() _NOEXCEPT
    162       : __res_(_VSTD_LFTS_PMR::get_default_resource())
    163     {}
    164 
    165     _LIBCPP_INLINE_VISIBILITY
    166     polymorphic_allocator(memory_resource * __r) _NOEXCEPT
    167       : __res_(__r)
    168     {}
    169 
    170     polymorphic_allocator(polymorphic_allocator const &) = default;
    171 
    172     template <class _Tp>
    173     _LIBCPP_INLINE_VISIBILITY
    174     polymorphic_allocator(polymorphic_allocator<_Tp> const & __other) _NOEXCEPT
    175       : __res_(__other.resource())
    176     {}
    177 
    178     polymorphic_allocator &
    179     operator=(polymorphic_allocator const &) = delete;
    180 
    181     // 8.6.3, memory.polymorphic.allocator.mem
    182     _LIBCPP_INLINE_VISIBILITY
    183     _ValueType* allocate(size_t __n) {
    184         if (__n > __max_size()) {
    185             __throw_length_error(
    186                 "std::experimental::pmr::polymorphic_allocator<T>::allocate(size_t n)"
    187                 " 'n' exceeds maximum supported size");
    188         }
    189         return static_cast<_ValueType*>(
    190             __res_->allocate(__n * sizeof(_ValueType), alignof(_ValueType))
    191         );
    192     }
    193 
    194     _LIBCPP_INLINE_VISIBILITY
    195     void deallocate(_ValueType * __p, size_t __n) _NOEXCEPT {
    196         _LIBCPP_ASSERT(__n <= __max_size(),
    197                        "deallocate called for size which exceeds max_size()");
    198         __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType));
    199     }
    200 
    201     template <class _Tp, class ..._Ts>
    202     _LIBCPP_INLINE_VISIBILITY
    203     void construct(_Tp* __p, _Ts &&... __args)
    204     {
    205         _VSTD_LFTS::__lfts_user_alloc_construct(
    206             __p, resource(), _VSTD::forward<_Ts>(__args)...
    207           );
    208     }
    209 
    210     template <class _T1, class _T2, class ..._Args1, class ..._Args2>
    211     _LIBCPP_INLINE_VISIBILITY
    212     void construct(pair<_T1, _T2>* __p, piecewise_construct_t,
    213                    tuple<_Args1...> __x, tuple<_Args2...> __y)
    214     {
    215         ::new ((void*)__p) pair<_T1, _T2>(piecewise_construct
    216           , __transform_tuple(
    217               typename __lfts_uses_alloc_ctor<
    218                   _T1, memory_resource*, _Args1...
    219               >::type()
    220             , _VSTD::move(__x)
    221             , typename __make_tuple_indices<sizeof...(_Args1)>::type{}
    222           )
    223           , __transform_tuple(
    224               typename __lfts_uses_alloc_ctor<
    225                   _T2, memory_resource*, _Args2...
    226               >::type()
    227             , _VSTD::move(__y)
    228             , typename __make_tuple_indices<sizeof...(_Args2)>::type{}
    229           )
    230         );
    231     }
    232 
    233     template <class _T1, class _T2>
    234     _LIBCPP_INLINE_VISIBILITY
    235     void construct(pair<_T1, _T2>* __p) {
    236         construct(__p, piecewise_construct, tuple<>(), tuple<>());
    237     }
    238 
    239     template <class _T1, class _T2, class _Up, class _Vp>
    240     _LIBCPP_INLINE_VISIBILITY
    241     void construct(pair<_T1, _T2> * __p, _Up && __u, _Vp && __v) {
    242         construct(__p, piecewise_construct
    243           , _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__u))
    244           , _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__v)));
    245     }
    246 
    247     template <class _T1, class _T2, class _U1, class _U2>
    248     _LIBCPP_INLINE_VISIBILITY
    249     void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> const & __pr) {
    250         construct(__p, piecewise_construct
    251             , _VSTD::forward_as_tuple(__pr.first)
    252             , _VSTD::forward_as_tuple(__pr.second));
    253     }
    254 
    255     template <class _T1, class _T2, class _U1, class _U2>
    256     _LIBCPP_INLINE_VISIBILITY
    257     void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> && __pr){
    258         construct(__p, piecewise_construct
    259             , _VSTD::forward_as_tuple(_VSTD::forward<_U1>(__pr.first))
    260             , _VSTD::forward_as_tuple(_VSTD::forward<_U2>(__pr.second)));
    261     }
    262 
    263     template <class _Tp>
    264     _LIBCPP_INLINE_VISIBILITY
    265     void destroy(_Tp * __p) _NOEXCEPT
    266         { __p->~_Tp(); }
    267 
    268     _LIBCPP_INLINE_VISIBILITY
    269     polymorphic_allocator
    270     select_on_container_copy_construction() const _NOEXCEPT
    271         { return polymorphic_allocator(); }
    272 
    273     _LIBCPP_INLINE_VISIBILITY
    274     memory_resource * resource() const _NOEXCEPT
    275         { return __res_; }
    276 
    277 private:
    278     template <class ..._Args, size_t ..._Idx>
    279     _LIBCPP_INLINE_VISIBILITY
    280     tuple<_Args&&...>
    281     __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t,
    282                       __tuple_indices<_Idx...>) const
    283     {
    284         return _VSTD::forward_as_tuple(_VSTD::get<_Idx>(_VSTD::move(__t))...);
    285     }
    286 
    287     template <class ..._Args, size_t ..._Idx>
    288     _LIBCPP_INLINE_VISIBILITY
    289     tuple<allocator_arg_t const&, memory_resource*, _Args&&...>
    290     __transform_tuple(integral_constant<int, 1>, tuple<_Args...> && __t,
    291                       __tuple_indices<_Idx...>) const
    292     {
    293         using _Tup = tuple<allocator_arg_t const&, memory_resource*, _Args&&...>;
    294         return _Tup(allocator_arg, resource(),
    295                     _VSTD::get<_Idx>(_VSTD::move(__t))...);
    296     }
    297 
    298     template <class ..._Args, size_t ..._Idx>
    299     _LIBCPP_INLINE_VISIBILITY
    300     tuple<_Args&&..., memory_resource*>
    301     __transform_tuple(integral_constant<int, 2>, tuple<_Args...> && __t,
    302                       __tuple_indices<_Idx...>) const
    303     {
    304         using _Tup = tuple<_Args&&..., memory_resource*>;
    305         return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., resource());
    306     }
    307 
    308     _LIBCPP_INLINE_VISIBILITY
    309     size_t __max_size() const _NOEXCEPT
    310         { return numeric_limits<size_t>::max() / sizeof(value_type); }
    311 
    312     memory_resource * __res_;
    313 };
    314 
    315 // 8.6.4, memory.polymorphic.allocator.eq
    316 
    317 template <class _Tp, class _Up>
    318 inline _LIBCPP_INLINE_VISIBILITY
    319 bool operator==(polymorphic_allocator<_Tp> const & __lhs,
    320                 polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT
    321 {
    322     return *__lhs.resource() == *__rhs.resource();
    323 }
    324 
    325 template <class _Tp, class _Up>
    326 inline _LIBCPP_INLINE_VISIBILITY
    327 bool operator!=(polymorphic_allocator<_Tp> const & __lhs,
    328                 polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT
    329 {
    330     return !(__lhs == __rhs);
    331 }
    332 
    333 // 8.7, memory.resource.adaptor
    334 
    335 // 8.7.1, memory.resource.adaptor.overview
    336 template <class _CharAlloc>
    337 class _LIBCPP_TEMPLATE_VIS __resource_adaptor_imp
    338   : public memory_resource
    339 {
    340     using _CTraits = allocator_traits<_CharAlloc>;
    341     static_assert(is_same<typename _CTraits::value_type, char>::value
    342                && is_same<typename _CTraits::pointer, char*>::value
    343                && is_same<typename _CTraits::void_pointer, void*>::value, "");
    344 
    345     static const size_t _MaxAlign = alignof(max_align_t);
    346 
    347     using _Alloc = typename _CTraits::template rebind_alloc<
    348             typename aligned_storage<_MaxAlign, _MaxAlign>::type
    349         >;
    350 
    351     using _ValueType = typename _Alloc::value_type;
    352 
    353     _Alloc __alloc_;
    354 
    355 public:
    356     typedef _CharAlloc allocator_type;
    357 
    358     __resource_adaptor_imp() = default;
    359     __resource_adaptor_imp(__resource_adaptor_imp const &) = default;
    360     __resource_adaptor_imp(__resource_adaptor_imp &&) = default;
    361 
    362     // 8.7.2, memory.resource.adaptor.ctor
    363 
    364     _LIBCPP_INLINE_VISIBILITY
    365     explicit __resource_adaptor_imp(allocator_type const & __a)
    366       : __alloc_(__a)
    367     {}
    368 
    369     _LIBCPP_INLINE_VISIBILITY
    370     explicit __resource_adaptor_imp(allocator_type && __a)
    371       : __alloc_(_VSTD::move(__a))
    372     {}
    373 
    374     __resource_adaptor_imp &
    375     operator=(__resource_adaptor_imp const &) = default;
    376 
    377     _LIBCPP_INLINE_VISIBILITY
    378     allocator_type get_allocator() const
    379     { return __alloc_; }
    380 
    381 // 8.7.3, memory.resource.adaptor.mem
    382 protected:
    383     virtual void * do_allocate(size_t __bytes, size_t)
    384     {
    385         if (__bytes > __max_size()) {
    386             __throw_length_error(
    387                 "std::experimental::pmr::resource_adaptor<T>::do_allocate(size_t bytes, size_t align)"
    388                 " 'bytes' exceeds maximum supported size");
    389         }
    390         size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
    391         return __alloc_.allocate(__s);
    392     }
    393 
    394     virtual void do_deallocate(void * __p, size_t __bytes, size_t)
    395     {
    396         _LIBCPP_ASSERT(__bytes <= __max_size(),
    397             "do_deallocate called for size which exceeds the maximum allocation size");
    398         size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
    399         __alloc_.deallocate((_ValueType*)__p, __s);
    400     }
    401 
    402     virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT {
    403         __resource_adaptor_imp const * __p
    404           = dynamic_cast<__resource_adaptor_imp const *>(&__other);
    405         return __p  ? __alloc_ == __p->__alloc_ : false;
    406     }
    407 
    408 private:
    409     _LIBCPP_INLINE_VISIBILITY
    410     size_t __max_size() const _NOEXCEPT {
    411         return numeric_limits<size_t>::max() - _MaxAlign;
    412     }
    413 };
    414 
    415 template <class _Alloc>
    416 using resource_adaptor = __resource_adaptor_imp<
    417     typename allocator_traits<_Alloc>::template rebind_alloc<char>
    418   >;
    419 
    420 _LIBCPP_END_NAMESPACE_LFTS_PMR
    421 
    422 #endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */
    423