File indexing completed on 2025-01-31 09:56:58
0001
0002
0003
0004
0005
0006
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
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
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
0129
0130
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
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
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 }
0228
0229 }
0230
0231 }
0232
0233 #endif