Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-31 09:56:58

0001 /* Copyright 2016-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_VALUE_HOLDER_HPP
0010 #define BOOST_POLY_COLLECTION_DETAIL_VALUE_HOLDER_HPP
0011 
0012 #if defined(_MSC_VER)
0013 #pragma once
0014 #endif
0015 
0016 #include <boost/core/addressof.hpp>
0017 #include <boost/poly_collection/detail/is_constructible.hpp>
0018 #include <boost/poly_collection/detail/is_equality_comparable.hpp>
0019 #include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp>
0020 #include <boost/poly_collection/exception.hpp>
0021 #include <new>
0022 #include <memory>
0023 #include <type_traits>
0024 #include <utility>
0025 
0026 namespace boost{
0027 
0028 namespace poly_collection{
0029 
0030 namespace detail{
0031 
0032 /* Segments of a poly_collection maintain vectors of value_holder<T>
0033  * rather than directly T. This serves several purposes:
0034  *  - value_holder<T> is copy constructible and equality comparable even if T
0035  *    is not: executing the corresponding op results in a reporting exception
0036  *    being thrown. This allows the segment to offer its full virtual
0037  *    interface regardless of the properties of the concrete class contained.
0038  *  - value_holder<T> emulates move assignment when T is not move assignable
0039  *    (nothrow move constructibility required); this happens most notably with
0040  *    lambda functions, whose assignment operator is deleted by standard
0041  *    mandate [expr.prim.lambda]/20 even if the compiler generated one would
0042  *    work (capture by value).
0043  *  - value_holder ctors accept a first allocator arg passed by
0044  *    boost::poly_collection::detail::allocator_adaptor, for purposes
0045  *    explained there.
0046  *
0047  * A pointer to value_holder_base<T> can be reinterpret_cast'ed to T*.
0048  * Emplacing is explicitly signalled with value_holder_emplacing_ctor to
0049  * protect us from greedy T's constructible from anything (like
0050  * boost::type_erasure::any).
0051  */
0052 
0053 struct value_holder_emplacing_ctor_t{};
0054 constexpr value_holder_emplacing_ctor_t value_holder_emplacing_ctor=
0055   value_holder_emplacing_ctor_t();
0056 
0057 template<typename T>
0058 class value_holder_base
0059 {
0060 protected:
0061   typename std::aligned_storage<sizeof(T),alignof(T)>::type s;
0062 };
0063 
0064 template<typename T>
0065 class value_holder:public value_holder_base<T>
0066 {
0067   template<typename U>
0068   using enable_if_not_emplacing_ctor_t=typename std::enable_if<
0069     !std::is_same<
0070       typename std::decay<U>::type,value_holder_emplacing_ctor_t
0071     >::value
0072   >::type*;
0073 
0074   using is_nothrow_move_constructible=std::is_nothrow_move_constructible<T>;
0075   using is_copy_constructible=std::is_copy_constructible<T>;
0076   using is_nothrow_copy_constructible=std::is_nothrow_copy_constructible<T>;
0077   using is_move_assignable=std::is_move_assignable<T>;
0078   using is_nothrow_move_assignable=std::is_nothrow_move_assignable<T>;
0079   using is_equality_comparable=detail::is_equality_comparable<T>;
0080   using is_nothrow_equality_comparable=
0081     detail::is_nothrow_equality_comparable<T>;
0082 
0083   T*       data()noexcept{return reinterpret_cast<T*>(&this->s);}
0084   const T* data()const noexcept
0085                 {return reinterpret_cast<const T*>(&this->s);}
0086 
0087   T&       value()noexcept{return *static_cast<T*>(data());}
0088   const T& value()const noexcept{return *static_cast<const T*>(data());}
0089 
0090 public:
0091   template<
0092     typename Allocator,
0093     enable_if_not_emplacing_ctor_t<Allocator> =nullptr
0094   >
0095   value_holder(Allocator& al,const T& x)
0096     noexcept(is_nothrow_copy_constructible::value)
0097     {copy(al,x);}
0098   template<
0099     typename Allocator,
0100     enable_if_not_emplacing_ctor_t<Allocator> =nullptr
0101   >
0102   value_holder(Allocator& al,T&& x)
0103     noexcept(is_nothrow_move_constructible::value)
0104     {std::allocator_traits<Allocator>::construct(al,data(),std::move(x));}
0105   template<
0106     typename Allocator,typename... Args,
0107     enable_if_not_emplacing_ctor_t<Allocator> =nullptr
0108   >
0109   value_holder(Allocator& al,value_holder_emplacing_ctor_t,Args&&... args)
0110     {std::allocator_traits<Allocator>::construct(
0111       al,data(),std::forward<Args>(args)...);}
0112   template<
0113     typename Allocator,
0114     enable_if_not_emplacing_ctor_t<Allocator> =nullptr
0115   >
0116   value_holder(Allocator& al,const value_holder& x)
0117     noexcept(is_nothrow_copy_constructible::value)
0118     {copy(al,x.value());}
0119   template<
0120     typename Allocator,
0121     enable_if_not_emplacing_ctor_t<Allocator> =nullptr
0122   >
0123   value_holder(Allocator& al,value_holder&& x)
0124     noexcept(is_nothrow_move_constructible::value)
0125     {std::allocator_traits<Allocator>::construct(
0126       al,data(),std::move(x.value()));}
0127 
0128   /* stdlib implementations in current use are notoriously lacking at
0129    * complying with [container.requirements.general]/3, so we keep the
0130    * following to make their life easier.
0131    */
0132 
0133   value_holder(const T& x)
0134     noexcept(is_nothrow_copy_constructible::value)
0135     {copy(x);}
0136   value_holder(T&& x)
0137     noexcept(is_nothrow_move_constructible::value)
0138     {::new ((void*)data()) T(std::move(x));}
0139   template<typename... Args>
0140   value_holder(value_holder_emplacing_ctor_t,Args&&... args)
0141     {::new ((void*)data()) T(std::forward<Args>(args)...);}
0142   value_holder(const value_holder& x)
0143     noexcept(is_nothrow_copy_constructible::value)
0144     {copy(x.value());}
0145   value_holder(value_holder&& x)
0146     noexcept(is_nothrow_move_constructible::value)
0147     {::new ((void*)data()) T(std::move(x.value()));}
0148  
0149   value_holder& operator=(const value_holder& x)=delete;
0150   value_holder& operator=(value_holder&& x)
0151     noexcept(is_nothrow_move_assignable::value||!is_move_assignable::value)
0152     /* if 2nd clause: nothrow move constructibility required */
0153   {
0154     move_assign(std::move(x.value()));
0155     return *this;
0156   }
0157 
0158   ~value_holder()noexcept{value().~T();}
0159 
0160   friend bool operator==(const value_holder& x,const value_holder& y)
0161     noexcept(is_nothrow_equality_comparable::value)
0162   {
0163     return x.equal(y.value());
0164   }
0165 
0166 private:
0167   template<typename Allocator>
0168   void copy(Allocator& al,const T& x){copy(al,x,is_copy_constructible{});}
0169 
0170   template<typename Allocator>
0171   void copy(Allocator& al,const T& x,std::true_type)
0172   {
0173     std::allocator_traits<Allocator>::construct(al,data(),x);
0174   }
0175 
0176   template<typename Allocator>
0177   void copy(Allocator&,const T&,std::false_type)
0178   {
0179     throw not_copy_constructible{typeid(T)};
0180   }
0181 
0182   void copy(const T& x){copy(x,is_copy_constructible{});}
0183 
0184   void copy(const T& x,std::true_type)
0185   {
0186     ::new (data()) T(x);
0187   }
0188 
0189   void copy(const T&,std::false_type)
0190   {
0191     throw not_copy_constructible{typeid(T)};
0192   }
0193 
0194   void move_assign(T&& x){move_assign(std::move(x),is_move_assignable{});}
0195 
0196   void move_assign(T&& x,std::true_type)
0197   {
0198     value()=std::move(x);    
0199   }
0200 
0201   void move_assign(T&& x,std::false_type)
0202   {
0203     /* emulated assignment */
0204 
0205     static_assert(is_nothrow_move_constructible::value,
0206       "type should be move assignable or nothrow move constructible");
0207 
0208     if(data()!=boost::addressof(x)){
0209       value().~T();
0210       ::new (data()) T(std::move(x));
0211     }
0212   }
0213 
0214   bool equal(const T& x)const{return equal(x,is_equality_comparable{});}
0215 
0216   bool equal(const T& x,std::true_type)const
0217   {
0218     return value()==x;
0219   }
0220 
0221   bool equal(const T&,std::false_type)const
0222   {
0223     throw not_equality_comparable{typeid(T)};
0224   }
0225 };
0226 
0227 } /* namespace poly_collection::detail */
0228 
0229 } /* namespace poly_collection */
0230 
0231 } /* namespace boost */
0232 
0233 #endif