Home | History | Annotate | Download | only in bits
      1 // Allocator traits -*- C++ -*-
      2 
      3 // Copyright (C) 2011-2014 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 bits/alloc_traits.h
     26  *  This is an internal header file, included by other library headers.
     27  *  Do not attempt to use it directly. @headername{memory}
     28  */
     29 
     30 #ifndef _ALLOC_TRAITS_H
     31 #define _ALLOC_TRAITS_H 1
     32 
     33 #if __cplusplus >= 201103L
     34 
     35 #include <bits/memoryfwd.h>
     36 #include <bits/ptr_traits.h>
     37 #include <ext/numeric_traits.h>
     38 
     39 namespace std _GLIBCXX_VISIBILITY(default)
     40 {
     41 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     42 
     43   template<typename _Alloc, typename _Tp>
     44     class __alloctr_rebind_helper
     45     {
     46       template<typename _Alloc2, typename _Tp2>
     47 	static constexpr true_type
     48 	_S_chk(typename _Alloc2::template rebind<_Tp2>::other*);
     49 
     50       template<typename, typename>
     51 	static constexpr false_type
     52 	_S_chk(...);
     53 
     54     public:
     55       using __type = decltype(_S_chk<_Alloc, _Tp>(nullptr));
     56     };
     57 
     58   template<typename _Alloc, typename _Tp,
     59 	   bool = __alloctr_rebind_helper<_Alloc, _Tp>::__type::value>
     60     struct __alloctr_rebind;
     61 
     62   template<typename _Alloc, typename _Tp>
     63     struct __alloctr_rebind<_Alloc, _Tp, true>
     64     {
     65       typedef typename _Alloc::template rebind<_Tp>::other __type;
     66     };
     67 
     68   template<template<typename, typename...> class _Alloc, typename _Tp,
     69 	   typename _Up, typename... _Args>
     70     struct __alloctr_rebind<_Alloc<_Up, _Args...>, _Tp, false>
     71     {
     72       typedef _Alloc<_Tp, _Args...> __type;
     73     };
     74 
     75   /**
     76    * @brief  Uniform interface to all allocator types.
     77    * @ingroup allocators
     78   */
     79   template<typename _Alloc>
     80     struct allocator_traits
     81     {
     82       /// The allocator type
     83       typedef _Alloc allocator_type;
     84       /// The allocated type
     85       typedef typename _Alloc::value_type value_type;
     86 
     87 #define _GLIBCXX_ALLOC_TR_NESTED_TYPE(_NTYPE, _ALT) \
     88   private: \
     89   template<typename _Tp> \
     90     static typename _Tp::_NTYPE _S_##_NTYPE##_helper(_Tp*); \
     91   static _ALT _S_##_NTYPE##_helper(...); \
     92     typedef decltype(_S_##_NTYPE##_helper((_Alloc*)0)) __##_NTYPE; \
     93   public:
     94 
     95 _GLIBCXX_ALLOC_TR_NESTED_TYPE(pointer, value_type*)
     96 
     97       /**
     98        * @brief   The allocator's pointer type.
     99        *
    100        * @c Alloc::pointer if that type exists, otherwise @c value_type*
    101       */
    102       typedef __pointer pointer;
    103 
    104 _GLIBCXX_ALLOC_TR_NESTED_TYPE(const_pointer,
    105   typename pointer_traits<pointer>::template rebind<const value_type>)
    106 
    107       /**
    108        * @brief   The allocator's const pointer type.
    109        *
    110        * @c Alloc::const_pointer if that type exists, otherwise
    111        * <tt> pointer_traits<pointer>::rebind<const value_type> </tt>
    112       */
    113       typedef __const_pointer const_pointer;
    114 
    115 _GLIBCXX_ALLOC_TR_NESTED_TYPE(void_pointer,
    116   typename pointer_traits<pointer>::template rebind<void>)
    117 
    118       /**
    119        * @brief   The allocator's void pointer type.
    120        *
    121        * @c Alloc::void_pointer if that type exists, otherwise
    122        * <tt> pointer_traits<pointer>::rebind<void> </tt>
    123       */
    124       typedef __void_pointer void_pointer;
    125 
    126 _GLIBCXX_ALLOC_TR_NESTED_TYPE(const_void_pointer,
    127   typename pointer_traits<pointer>::template rebind<const void>)
    128 
    129       /**
    130        * @brief   The allocator's const void pointer type.
    131        *
    132        * @c Alloc::const_void_pointer if that type exists, otherwise
    133        * <tt> pointer_traits<pointer>::rebind<const void> </tt>
    134       */
    135       typedef __const_void_pointer const_void_pointer;
    136 
    137 _GLIBCXX_ALLOC_TR_NESTED_TYPE(difference_type,
    138 			      typename pointer_traits<pointer>::difference_type)
    139 
    140       /**
    141        * @brief   The allocator's difference type
    142        *
    143        * @c Alloc::difference_type if that type exists, otherwise
    144        * <tt> pointer_traits<pointer>::difference_type </tt>
    145       */
    146       typedef __difference_type difference_type;
    147 
    148 _GLIBCXX_ALLOC_TR_NESTED_TYPE(size_type,
    149 			      typename make_unsigned<difference_type>::type)
    150 
    151       /**
    152        * @brief   The allocator's size type
    153        *
    154        * @c Alloc::size_type if that type exists, otherwise
    155        * <tt> make_unsigned<difference_type>::type </tt>
    156       */
    157       typedef __size_type size_type;
    158 
    159 _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_copy_assignment,
    160 			      false_type)
    161 
    162       /**
    163        * @brief   How the allocator is propagated on copy assignment
    164        *
    165        * @c Alloc::propagate_on_container_copy_assignment if that type exists,
    166        * otherwise @c false_type
    167       */
    168       typedef __propagate_on_container_copy_assignment
    169 	propagate_on_container_copy_assignment;
    170 
    171 _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_move_assignment,
    172 			      false_type)
    173 
    174       /**
    175        * @brief   How the allocator is propagated on move assignment
    176        *
    177        * @c Alloc::propagate_on_container_move_assignment if that type exists,
    178        * otherwise @c false_type
    179       */
    180       typedef __propagate_on_container_move_assignment
    181 	propagate_on_container_move_assignment;
    182 
    183 _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
    184 			      false_type)
    185 
    186       /**
    187        * @brief   How the allocator is propagated on swap
    188        *
    189        * @c Alloc::propagate_on_container_swap if that type exists,
    190        * otherwise @c false_type
    191       */
    192       typedef __propagate_on_container_swap propagate_on_container_swap;
    193 
    194 #undef _GLIBCXX_ALLOC_TR_NESTED_TYPE
    195 
    196       template<typename _Tp>
    197 	using rebind_alloc = typename __alloctr_rebind<_Alloc, _Tp>::__type;
    198       template<typename _Tp>
    199 	using rebind_traits = allocator_traits<rebind_alloc<_Tp>>;
    200 
    201     private:
    202       template<typename _Alloc2>
    203 	struct __allocate_helper
    204 	{
    205 	  template<typename _Alloc3,
    206 	    typename = decltype(std::declval<_Alloc3*>()->allocate(
    207 		  std::declval<size_type>(),
    208 		  std::declval<const_void_pointer>()))>
    209 	    static true_type __test(int);
    210 
    211 	  template<typename>
    212 	    static false_type __test(...);
    213 
    214 	  using type = decltype(__test<_Alloc>(0));
    215 	};
    216 
    217       template<typename _Alloc2>
    218 	using __has_allocate = typename __allocate_helper<_Alloc2>::type;
    219 
    220       template<typename _Alloc2,
    221 	       typename = _Require<__has_allocate<_Alloc2>>>
    222 	static pointer
    223 	_S_allocate(_Alloc2& __a, size_type __n, const_void_pointer __hint)
    224 	{ return __a.allocate(__n, __hint); }
    225 
    226       template<typename _Alloc2, typename _UnusedHint,
    227 	       typename = _Require<__not_<__has_allocate<_Alloc2>>>>
    228 	static pointer
    229 	_S_allocate(_Alloc2& __a, size_type __n, _UnusedHint)
    230 	{ return __a.allocate(__n); }
    231 
    232       template<typename _Tp, typename... _Args>
    233 	struct __construct_helper
    234 	{
    235 	  template<typename _Alloc2,
    236 	    typename = decltype(std::declval<_Alloc2*>()->construct(
    237 		  std::declval<_Tp*>(), std::declval<_Args>()...))>
    238 	    static true_type __test(int);
    239 
    240 	  template<typename>
    241 	    static false_type __test(...);
    242 
    243 	  using type = decltype(__test<_Alloc>(0));
    244 	};
    245 
    246       template<typename _Tp, typename... _Args>
    247 	using __has_construct
    248 	  = typename __construct_helper<_Tp, _Args...>::type;
    249 
    250       template<typename _Tp, typename... _Args>
    251 	static _Require<__has_construct<_Tp, _Args...>>
    252 	_S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
    253 	{ __a.construct(__p, std::forward<_Args>(__args)...); }
    254 
    255       template<typename _Tp, typename... _Args>
    256 	static
    257 	_Require<__and_<__not_<__has_construct<_Tp, _Args...>>,
    258 			       is_constructible<_Tp, _Args...>>>
    259 	_S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
    260 	{ ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
    261 
    262       template<typename _Tp>
    263 	struct __destroy_helper
    264 	{
    265 	  template<typename _Alloc2,
    266 	    typename = decltype(std::declval<_Alloc2*>()->destroy(
    267 		  std::declval<_Tp*>()))>
    268 	    static true_type __test(int);
    269 
    270 	  template<typename>
    271 	    static false_type __test(...);
    272 
    273 	  using type = decltype(__test<_Alloc>(0));
    274 	};
    275 
    276       template<typename _Tp>
    277 	using __has_destroy = typename __destroy_helper<_Tp>::type;
    278 
    279       template<typename _Tp>
    280 	static _Require<__has_destroy<_Tp>>
    281 	_S_destroy(_Alloc& __a, _Tp* __p)
    282 	{ __a.destroy(__p); }
    283 
    284       template<typename _Tp>
    285 	static _Require<__not_<__has_destroy<_Tp>>>
    286 	_S_destroy(_Alloc&, _Tp* __p)
    287 	{ __p->~_Tp(); }
    288 
    289       template<typename _Alloc2>
    290 	struct __maxsize_helper
    291 	{
    292 	  template<typename _Alloc3,
    293 	    typename = decltype(std::declval<_Alloc3*>()->max_size())>
    294 	    static true_type __test(int);
    295 
    296 	  template<typename>
    297 	    static false_type __test(...);
    298 
    299 	  using type = decltype(__test<_Alloc2>(0));
    300 	};
    301 
    302       template<typename _Alloc2>
    303 	using __has_max_size = typename __maxsize_helper<_Alloc2>::type;
    304 
    305       template<typename _Alloc2,
    306 	       typename = _Require<__has_max_size<_Alloc2>>>
    307 	static size_type
    308 	_S_max_size(_Alloc2& __a, int)
    309 	{ return __a.max_size(); }
    310 
    311       template<typename _Alloc2,
    312 	       typename = _Require<__not_<__has_max_size<_Alloc2>>>>
    313 	static size_type
    314 	_S_max_size(_Alloc2&, ...)
    315 	{ return __gnu_cxx::__numeric_traits<size_type>::__max; }
    316 
    317       template<typename _Alloc2>
    318 	struct __select_helper
    319 	{
    320 	  template<typename _Alloc3, typename
    321 	    = decltype(std::declval<_Alloc3*>()
    322 		->select_on_container_copy_construction())>
    323 	    static true_type __test(int);
    324 
    325 	  template<typename>
    326 	    static false_type __test(...);
    327 
    328 	  using type = decltype(__test<_Alloc2>(0));
    329 	};
    330 
    331       template<typename _Alloc2>
    332 	using __has_soccc = typename __select_helper<_Alloc2>::type;
    333 
    334       template<typename _Alloc2,
    335 	       typename = _Require<__has_soccc<_Alloc2>>>
    336 	static _Alloc2
    337 	_S_select(_Alloc2& __a, int)
    338 	{ return __a.select_on_container_copy_construction(); }
    339 
    340       template<typename _Alloc2,
    341 	       typename = _Require<__not_<__has_soccc<_Alloc2>>>>
    342 	static _Alloc2
    343 	_S_select(_Alloc2& __a, ...)
    344 	{ return __a; }
    345 
    346     public:
    347 
    348       /**
    349        *  @brief  Allocate memory.
    350        *  @param  __a  An allocator.
    351        *  @param  __n  The number of objects to allocate space for.
    352        *
    353        *  Calls @c a.allocate(n)
    354       */
    355       static pointer
    356       allocate(_Alloc& __a, size_type __n)
    357       { return __a.allocate(__n); }
    358 
    359       /**
    360        *  @brief  Allocate memory.
    361        *  @param  __a  An allocator.
    362        *  @param  __n  The number of objects to allocate space for.
    363        *  @param  __hint Aid to locality.
    364        *  @return Memory of suitable size and alignment for @a n objects
    365        *          of type @c value_type
    366        *
    367        *  Returns <tt> a.allocate(n, hint) </tt> if that expression is
    368        *  well-formed, otherwise returns @c a.allocate(n)
    369       */
    370       static pointer
    371       allocate(_Alloc& __a, size_type __n, const_void_pointer __hint)
    372       { return _S_allocate(__a, __n, __hint); }
    373 
    374       /**
    375        *  @brief  Deallocate memory.
    376        *  @param  __a  An allocator.
    377        *  @param  __p  Pointer to the memory to deallocate.
    378        *  @param  __n  The number of objects space was allocated for.
    379        *
    380        *  Calls <tt> a.deallocate(p, n) </tt>
    381       */
    382       static void deallocate(_Alloc& __a, pointer __p, size_type __n)
    383       { __a.deallocate(__p, __n); }
    384 
    385       /**
    386        *  @brief  Construct an object of type @a _Tp
    387        *  @param  __a  An allocator.
    388        *  @param  __p  Pointer to memory of suitable size and alignment for Tp
    389        *  @param  __args Constructor arguments.
    390        *
    391        *  Calls <tt> __a.construct(__p, std::forward<Args>(__args)...) </tt>
    392        *  if that expression is well-formed, otherwise uses placement-new
    393        *  to construct an object of type @a _Tp at location @a __p from the
    394        *  arguments @a __args...
    395       */
    396       template<typename _Tp, typename... _Args>
    397 	static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
    398 	-> decltype(_S_construct(__a, __p, std::forward<_Args>(__args)...))
    399 	{ _S_construct(__a, __p, std::forward<_Args>(__args)...); }
    400 
    401       /**
    402        *  @brief  Destroy an object of type @a _Tp
    403        *  @param  __a  An allocator.
    404        *  @param  __p  Pointer to the object to destroy
    405        *
    406        *  Calls @c __a.destroy(__p) if that expression is well-formed,
    407        *  otherwise calls @c __p->~_Tp()
    408       */
    409       template <class _Tp>
    410 	static void destroy(_Alloc& __a, _Tp* __p)
    411 	{ _S_destroy(__a, __p); }
    412 
    413       /**
    414        *  @brief  The maximum supported allocation size
    415        *  @param  __a  An allocator.
    416        *  @return @c __a.max_size() or @c numeric_limits<size_type>::max()
    417        *
    418        *  Returns @c __a.max_size() if that expression is well-formed,
    419        *  otherwise returns @c numeric_limits<size_type>::max()
    420       */
    421       static size_type max_size(const _Alloc& __a) noexcept
    422       { return _S_max_size(__a, 0); }
    423 
    424       /**
    425        *  @brief  Obtain an allocator to use when copying a container.
    426        *  @param  __rhs  An allocator.
    427        *  @return @c __rhs.select_on_container_copy_construction() or @a __rhs
    428        *
    429        *  Returns @c __rhs.select_on_container_copy_construction() if that
    430        *  expression is well-formed, otherwise returns @a __rhs
    431       */
    432       static _Alloc
    433       select_on_container_copy_construction(const _Alloc& __rhs)
    434       { return _S_select(__rhs, 0); }
    435     };
    436 
    437   template<typename _Alloc>
    438     inline void
    439     __do_alloc_on_copy(_Alloc& __one, const _Alloc& __two, true_type)
    440     { __one = __two; }
    441 
    442   template<typename _Alloc>
    443     inline void
    444     __do_alloc_on_copy(_Alloc&, const _Alloc&, false_type)
    445     { }
    446 
    447   template<typename _Alloc>
    448     inline void __alloc_on_copy(_Alloc& __one, const _Alloc& __two)
    449     {
    450       typedef allocator_traits<_Alloc> __traits;
    451       typedef typename __traits::propagate_on_container_copy_assignment __pocca;
    452       __do_alloc_on_copy(__one, __two, __pocca());
    453     }
    454 
    455   template<typename _Alloc>
    456     inline _Alloc __alloc_on_copy(const _Alloc& __a)
    457     {
    458       typedef allocator_traits<_Alloc> __traits;
    459       return __traits::select_on_container_copy_construction(__a);
    460     }
    461 
    462   template<typename _Alloc>
    463     inline void __do_alloc_on_move(_Alloc& __one, _Alloc& __two, true_type)
    464     { __one = std::move(__two); }
    465 
    466   template<typename _Alloc>
    467     inline void __do_alloc_on_move(_Alloc&, _Alloc&, false_type)
    468     { }
    469 
    470   template<typename _Alloc>
    471     inline void __alloc_on_move(_Alloc& __one, _Alloc& __two)
    472     {
    473       typedef allocator_traits<_Alloc> __traits;
    474       typedef typename __traits::propagate_on_container_move_assignment __pocma;
    475       __do_alloc_on_move(__one, __two, __pocma());
    476     }
    477 
    478   template<typename _Alloc>
    479     inline void __do_alloc_on_swap(_Alloc& __one, _Alloc& __two, true_type)
    480     {
    481       using std::swap;
    482       swap(__one, __two);
    483     }
    484 
    485   template<typename _Alloc>
    486     inline void __do_alloc_on_swap(_Alloc&, _Alloc&, false_type)
    487     { }
    488 
    489   template<typename _Alloc>
    490     inline void __alloc_on_swap(_Alloc& __one, _Alloc& __two)
    491     {
    492       typedef allocator_traits<_Alloc> __traits;
    493       typedef typename __traits::propagate_on_container_swap __pocs;
    494       __do_alloc_on_swap(__one, __two, __pocs());
    495     }
    496 
    497   template<typename _Alloc>
    498     class __is_copy_insertable_impl
    499     {
    500       typedef allocator_traits<_Alloc> _Traits;
    501 
    502       template<typename _Up, typename
    503 	       = decltype(_Traits::construct(std::declval<_Alloc&>(),
    504 					     std::declval<_Up*>(),
    505 					     std::declval<const _Up&>()))>
    506 	static true_type
    507 	_M_select(int);
    508 
    509       template<typename _Up>
    510 	static false_type
    511 	_M_select(...);
    512 
    513     public:
    514       typedef decltype(_M_select<typename _Alloc::value_type>(0)) type;
    515     };
    516 
    517   // true if _Alloc::value_type is CopyInsertable into containers using _Alloc
    518   template<typename _Alloc>
    519     struct __is_copy_insertable
    520     : __is_copy_insertable_impl<_Alloc>::type
    521     { };
    522 
    523   // std::allocator<_Tp> just requires CopyConstructible
    524   template<typename _Tp>
    525     struct __is_copy_insertable<allocator<_Tp>>
    526     : is_copy_constructible<_Tp>
    527     { };
    528 
    529 _GLIBCXX_END_NAMESPACE_VERSION
    530 } // namespace std
    531 
    532 #endif
    533 #endif
    534