Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:45:56

0001 /* Copyright 2018-2024 Joaquin M Lopez Munoz.
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * http://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * See http://www.boost.org/libs/poly_collection for library home page.
0007  */
0008 
0009 #ifndef BOOST_POLY_COLLECTION_DETAIL_ALLOCATOR_ADAPTOR_HPP
0010 #define BOOST_POLY_COLLECTION_DETAIL_ALLOCATOR_ADAPTOR_HPP
0011 
0012 #if defined(_MSC_VER)
0013 #pragma once
0014 #endif
0015 
0016 #include <boost/mp11/function.hpp>
0017 #include <boost/mp11/integer_sequence.hpp>
0018 #include <boost/poly_collection/detail/is_constructible.hpp>
0019 #include <new>
0020 #include <memory>
0021 #include <tuple>
0022 #include <type_traits>
0023 #include <utility>
0024 
0025 namespace boost{
0026 
0027 namespace poly_collection{
0028 
0029 namespace detail{
0030 
0031 /* [container.requirements.general]/3 state that containers must use the
0032  * allocator's construct/destroy member functions to construct/destroy
0033  * elements and *not at all* for any other type. Since poly_collection is
0034  * implemented as a multi-level structure of container and container-like
0035  * objects, we need to use an adaptor for the user-provided Allocator that
0036  * prevents intermediate entities from calling Allocator::[construct|destroy].
0037  * allocator_adaptor<Allocator> does this by taking advantage of the fact that
0038  * elements are ultimately held within a value_holder:
0039  *  - construct(value_holder<T,U>*,...) uses placement new construction and
0040  *    passes the wrapped Allocator object for value_holder<T> to use for
0041  *    its inner construction of T.
0042  *  - For the rest of types, construct uses placement new construction and
0043  *    passes down the adaptor object itself as an argument following an
0044  *    approach analogous to that of std::scoped_allocator_adaptor.
0045  *  - destroy(value_holder<T,U>) resorts to Allocator::destroy to destroy the
0046  *    contained T element.
0047  *  - For the rest of types, destroy(T) calls ~T directly.
0048  *
0049  * Code has been ripped and adapted from libc++'s implementation of
0050  * std::scoped_allocator_adaptor.
0051  */
0052 
0053 template<typename T>
0054 class value_holder_base;
0055 
0056 template<typename T,typename U>
0057 class value_holder;
0058 
0059 template<typename T,typename Allocator,typename... Args>
0060 struct uses_alloc_ctor_impl
0061 {
0062     using RawAllocator=typename std::remove_cv<
0063       typename std::remove_reference<Allocator>::type
0064     >::type;
0065 
0066     static const bool ua=std::uses_allocator<T,RawAllocator>::value;
0067     static const int  ic=is_constructible<
0068       T,std::allocator_arg_t,Allocator,Args...>::value?1:0;
0069     static const int  value=ua?2-ic:0;
0070 };
0071 
0072 template<typename T,typename Allocator,typename... Args>
0073 struct uses_alloc_ctor:
0074   std::integral_constant<int,uses_alloc_ctor_impl<T,Allocator,Args...>::value>
0075 {};
0076 
0077 template<typename Allocator,typename=void>
0078 struct allocator_is_always_equal:std::is_empty<Allocator>{};
0079 
0080 template<typename Allocator>
0081 struct allocator_is_always_equal<
0082   Allocator,
0083   mp11::mp_void<
0084     typename std::allocator_traits<Allocator>::is_always_equal
0085   >
0086 >:std::allocator_traits<Allocator>::is_always_equal{};
0087 
0088 template<typename Allocator>
0089 struct allocator_adaptor:Allocator
0090 {
0091   using traits=std::allocator_traits<Allocator>;
0092 
0093   using value_type=typename traits::value_type;
0094   using size_type=typename traits::size_type;
0095   using difference_type=typename traits::difference_type;
0096   using pointer=typename traits::pointer;
0097   using const_pointer=typename traits::const_pointer;
0098   using void_pointer=typename traits::void_pointer;
0099   using const_void_pointer=typename traits::const_void_pointer;
0100   using propagate_on_container_copy_assignment=
0101     typename traits::propagate_on_container_copy_assignment;
0102   using propagate_on_container_move_assignment=
0103     typename traits::propagate_on_container_move_assignment;
0104   using propagate_on_container_swap=
0105     typename traits::propagate_on_container_swap;
0106   using is_always_equal=typename allocator_is_always_equal<Allocator>::type;
0107 
0108   template<typename U>
0109   struct rebind
0110   {
0111     using other=allocator_adaptor<typename traits::template rebind_alloc<U>>;
0112   };
0113 
0114   allocator_adaptor()=default;
0115   allocator_adaptor(const allocator_adaptor&)=default;
0116 
0117   template<
0118     typename Allocator2,
0119     typename std::enable_if<
0120       is_constructible<Allocator,const Allocator2&>::value
0121     >::type* =nullptr
0122   >
0123   allocator_adaptor(const Allocator2& x)noexcept:Allocator{x}{}
0124 
0125   template<
0126     typename Allocator2,
0127     typename std::enable_if<
0128       is_constructible<Allocator,const Allocator2&>::value
0129     >::type* =nullptr
0130   >
0131   allocator_adaptor(const allocator_adaptor<Allocator2>& x)noexcept:
0132     Allocator{x.allocator()}{}
0133 
0134   allocator_adaptor& operator=(const allocator_adaptor&)=default;
0135 
0136   Allocator&       allocator()noexcept{return *this;}
0137   const Allocator& allocator()const noexcept{return *this;}
0138 
0139   template<typename T,typename... Args>
0140   void construct(T* p,Args&&... args)
0141   {
0142     construct_(
0143       uses_alloc_ctor<T,allocator_adaptor&,Args...>{},
0144       p,std::forward<Args>(args)...);
0145   }
0146 
0147   template<typename T,typename U,typename... Args>
0148   void construct(value_holder<T,U>* p,Args&&... args)
0149   {
0150     ::new ((void*)p) value_holder<T,U>(
0151       allocator(),std::forward<Args>(args)...);
0152   }
0153 
0154   template<typename T1,typename T2,typename... Args1,typename... Args2>
0155   void construct(
0156     std::pair<T1,T2>* p,std::piecewise_construct_t,
0157     std::tuple<Args1...> x,std::tuple<Args2...> y)
0158   {
0159     ::new ((void*)p) std::pair<T1,T2>(
0160        std::piecewise_construct,
0161        transform_tuple(
0162          uses_alloc_ctor<T1,allocator_adaptor&,Args1...>{},
0163          std::move(x),
0164          mp11::make_index_sequence<sizeof...(Args1)>{}),
0165        transform_tuple(
0166          uses_alloc_ctor<T2,allocator_adaptor&,Args2...>{},
0167          std::move(y),
0168          mp11::make_index_sequence<sizeof...(Args2)>{})
0169     );
0170   }
0171 
0172   template<typename T1,typename T2>
0173   void construct(std::pair<T1,T2>* p)
0174   {
0175     construct(p,std::piecewise_construct,std::tuple<>{},std::tuple<>{});
0176   }
0177 
0178   template<typename T1,typename T2,typename U,typename V>
0179   void construct(std::pair<T1,T2>* p,U&& x,V&& y)
0180   {
0181     construct(
0182       p,std::piecewise_construct,
0183       std::forward_as_tuple(std::forward<U>(x)),
0184       std::forward_as_tuple(std::forward<V>(y)));
0185   }
0186 
0187   template<typename T1,typename T2,typename U,typename V>
0188   void construct(std::pair<T1,T2>* p,const std::pair<U,V>& x)
0189   {
0190     construct(
0191       p,std::piecewise_construct,
0192       std::forward_as_tuple(x.first),std::forward_as_tuple(x.second));
0193   }
0194 
0195   template<typename T1,typename T2,typename U,typename V>
0196   void construct(std::pair<T1,T2>* p,std::pair<U,V>&& x)
0197   {
0198     construct(
0199       p,std::piecewise_construct,
0200       std::forward_as_tuple(std::forward<U>(x.first)),
0201       std::forward_as_tuple(std::forward<V>(x.second)));
0202   }
0203 
0204   template<typename T>
0205   void destroy(T* p)
0206   {
0207     p->~T();
0208   }
0209 
0210   template<typename T,typename U>
0211   void destroy(value_holder<T,U>* p)
0212   {
0213     traits::destroy(
0214       allocator(),
0215       reinterpret_cast<T*>(static_cast<value_holder_base<T>*>(p)));
0216   }
0217 
0218   allocator_adaptor
0219   select_on_container_copy_construction()const noexcept
0220   {
0221     return traits::select_on_container_copy_construction(allocator());
0222   }
0223 
0224 private:
0225   template<typename T,typename... Args>
0226   void construct_(
0227     std::integral_constant<int,0>,  /* doesn't use allocator */
0228     T* p,Args&&... args)
0229   {
0230     ::new ((void*)p) T(std::forward<Args>(args)...);
0231   }
0232 
0233   template<typename T,typename... Args>
0234   void construct_(
0235     std::integral_constant<int,1>, /* with std::allocator_arg */
0236     T* p,Args&&... args)
0237   {
0238     ::new ((void*)p) T(std::allocator_arg,*this,std::forward<Args>(args)...);
0239   }  
0240 
0241   template<typename T,typename... Args>
0242   void construct_(
0243     std::integral_constant<int,2>, /* allocator at the end */
0244     T* p,Args&&... args)
0245   {
0246     ::new ((void*)p) T(std::forward<Args>(args)...,*this);
0247   }
0248 
0249   template<typename... Args,std::size_t... I>
0250   std::tuple<Args&&...> transform_tuple(
0251     std::integral_constant<int,0>,  /* doesn't use allocator */
0252     std::tuple<Args...>&& t,mp11::index_sequence<I...>)
0253   {
0254     return std::tuple<Args&&...>(std::get<I>(std::move(t))...);
0255   }
0256 
0257   template<typename... Args,std::size_t... I>
0258   std::tuple<std::allocator_arg_t,allocator_adaptor&,Args&&...>
0259   transform_tuple(
0260     std::integral_constant<int,1>, /* with std::allocator_arg */
0261     std::tuple<Args...>&& t,mp11::index_sequence<I...>)
0262   {
0263     return std::tuple<
0264       std::allocator_arg_t,allocator_adaptor&,Args&&...>(
0265       std::allocator_arg,*this,std::get<I>(std::move(t))...);
0266   }
0267 
0268   template<typename... Args,std::size_t... I>
0269   std::tuple<Args&&...,allocator_adaptor&>
0270   transform_tuple(
0271     std::integral_constant<int,2>, /* allocator at the end */
0272     std::tuple<Args...>&& t,mp11::index_sequence<I...>)
0273   {
0274     return std::tuple<Args&&...,allocator_adaptor&>(
0275       std::get<I>(std::move(t))...,*this);
0276   }
0277 };
0278 
0279 template<typename Allocator1,typename Allocator2>
0280 bool operator==(
0281   const allocator_adaptor<Allocator1>& x,
0282   const allocator_adaptor<Allocator2>& y)noexcept
0283 {
0284   return x.allocator()==y.allocator();
0285 }
0286 
0287 template<typename Allocator1,typename Allocator2>
0288 bool operator!=(
0289   const allocator_adaptor<Allocator1>& x,
0290   const allocator_adaptor<Allocator2>& y)noexcept
0291 {
0292   return !(x==y);
0293 }
0294 
0295 } /* namespace poly_collection::detail */
0296 
0297 } /* namespace poly_collection */
0298 
0299 } /* namespace boost */
0300 
0301 #endif