Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:22:15

0001 /* Copyright 2018 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>*,...) 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>) 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>
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... Args>
0148   void construct(value_holder<T>* p,Args&&... args)
0149   {
0150     ::new ((void*)p) value_holder<T>(allocator(),std::forward<Args>(args)...);
0151   }
0152 
0153   template<typename T1,typename T2,typename... Args1,typename... Args2>
0154   void construct(
0155     std::pair<T1,T2>* p,std::piecewise_construct_t,
0156     std::tuple<Args1...> x,std::tuple<Args2...> y)
0157   {
0158     ::new ((void*)p) std::pair<T1,T2>(
0159        std::piecewise_construct,
0160        transform_tuple(
0161          uses_alloc_ctor<T1,allocator_adaptor&,Args1...>{},
0162          std::move(x),
0163          mp11::make_index_sequence<sizeof...(Args1)>{}),
0164        transform_tuple(
0165          uses_alloc_ctor<T2,allocator_adaptor&,Args2...>{},
0166          std::move(y),
0167          mp11::make_index_sequence<sizeof...(Args2)>{})
0168     );
0169   }
0170 
0171   template<typename T1,typename T2>
0172   void construct(std::pair<T1,T2>* p)
0173   {
0174     construct(p,std::piecewise_construct,std::tuple<>{},std::tuple<>{});
0175   }
0176 
0177   template<typename T1,typename T2,typename U,typename V>
0178   void construct(std::pair<T1,T2>* p,U&& x,V&& y)
0179   {
0180     construct(
0181       p,std::piecewise_construct,
0182       std::forward_as_tuple(std::forward<U>(x)),
0183       std::forward_as_tuple(std::forward<V>(y)));
0184   }
0185 
0186   template<typename T1,typename T2,typename U,typename V>
0187   void construct(std::pair<T1,T2>* p,const std::pair<U,V>& x)
0188   {
0189     construct(
0190       p,std::piecewise_construct,
0191       std::forward_as_tuple(x.first),std::forward_as_tuple(x.second));
0192   }
0193 
0194   template<typename T1,typename T2,typename U,typename V>
0195   void construct(std::pair<T1,T2>* p,std::pair<U,V>&& x)
0196   {
0197     construct(
0198       p,std::piecewise_construct,
0199       std::forward_as_tuple(std::forward<U>(x.first)),
0200       std::forward_as_tuple(std::forward<V>(x.second)));
0201   }
0202 
0203   template<typename T>
0204   void destroy(T* p)
0205   {
0206     p->~T();
0207   }
0208 
0209   template<typename T>
0210   void destroy(value_holder<T>* p)
0211   {
0212     traits::destroy(
0213       allocator(),
0214       reinterpret_cast<T*>(static_cast<value_holder_base<T>*>(p)));
0215   }
0216 
0217   allocator_adaptor
0218   select_on_container_copy_construction()const noexcept
0219   {
0220     return traits::select_on_container_copy_construction(allocator());
0221   }
0222 
0223 private:
0224   template<typename T,typename... Args>
0225   void construct_(
0226     std::integral_constant<int,0>,  /* doesn't use allocator */
0227     T* p,Args&&... args)
0228   {
0229     ::new ((void*)p) T(std::forward<Args>(args)...);
0230   }
0231 
0232   template<typename T,typename... Args>
0233   void construct_(
0234     std::integral_constant<int,1>, /* with std::allocator_arg */
0235     T* p,Args&&... args)
0236   {
0237     ::new ((void*)p) T(std::allocator_arg,*this,std::forward<Args>(args)...);
0238   }  
0239 
0240   template<typename T,typename... Args>
0241   void construct_(
0242     std::integral_constant<int,2>, /* allocator at the end */
0243     T* p,Args&&... args)
0244   {
0245     ::new ((void*)p) T(std::forward<Args>(args)...,*this);
0246   }
0247 
0248   template<typename... Args,std::size_t... I>
0249   std::tuple<Args&&...> transform_tuple(
0250     std::integral_constant<int,0>,  /* doesn't use allocator */
0251     std::tuple<Args...>&& t,mp11::index_sequence<I...>)
0252   {
0253     return std::tuple<Args&&...>(std::get<I>(std::move(t))...);
0254   }
0255 
0256   template<typename... Args,std::size_t... I>
0257   std::tuple<std::allocator_arg_t,allocator_adaptor&,Args&&...>
0258   transform_tuple(
0259     std::integral_constant<int,1>, /* with std::allocator_arg */
0260     std::tuple<Args...>&& t,mp11::index_sequence<I...>)
0261   {
0262     return std::tuple<
0263       std::allocator_arg_t,allocator_adaptor&,Args&&...>(
0264       std::allocator_arg,*this,std::get<I>(std::move(t))...);
0265   }
0266 
0267   template<typename... Args,std::size_t... I>
0268   std::tuple<Args&&...,allocator_adaptor&>
0269   transform_tuple(
0270     std::integral_constant<int,2>, /* allocator at the end */
0271     std::tuple<Args...>&& t,mp11::index_sequence<I...>)
0272   {
0273     return std::tuple<Args&&...,allocator_adaptor&>(
0274       std::get<I>(std::move(t))...,*this);
0275   }
0276 };
0277 
0278 template<typename Allocator1,typename Allocator2>
0279 bool operator==(
0280   const allocator_adaptor<Allocator1>& x,
0281   const allocator_adaptor<Allocator2>& y)noexcept
0282 {
0283   return x.allocator()==y.allocator();
0284 }
0285 
0286 template<typename Allocator1,typename Allocator2>
0287 bool operator!=(
0288   const allocator_adaptor<Allocator1>& x,
0289   const allocator_adaptor<Allocator2>& y)noexcept
0290 {
0291   return !(x==y);
0292 }
0293 
0294 } /* namespace poly_collection::detail */
0295 
0296 } /* namespace poly_collection */
0297 
0298 } /* namespace boost */
0299 
0300 #endif