]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/poly_collection/detail/value_holder.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / poly_collection / detail / value_holder.hpp
1 /* Copyright 2016-2017 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
5 *
6 * See http://www.boost.org/libs/poly_collection for library home page.
7 */
8
9 #ifndef BOOST_POLY_COLLECTION_DETAIL_VALUE_HOLDER_HPP
10 #define BOOST_POLY_COLLECTION_DETAIL_VALUE_HOLDER_HPP
11
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15
16 #include <boost/core/addressof.hpp>
17 #include <boost/poly_collection/detail/is_constructible.hpp>
18 #include <boost/poly_collection/detail/is_equality_comparable.hpp>
19 #include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp>
20 #include <boost/poly_collection/exception.hpp>
21 #include <new>
22 #include <memory>
23 #include <type_traits>
24 #include <utility>
25
26 namespace boost{
27
28 namespace poly_collection{
29
30 namespace detail{
31
32 /* Segments of a poly_collection maintain vectors of value_holder<T>
33 * rather than directly T. This serves several purposes:
34 * - value_holder<T> is copy constructible and equality comparable even if T
35 * is not: executing the corresponding op results in a reporting exception
36 * being thrown. This allows the segment to offer its full virtual
37 * interface regardless of the properties of the concrete class contained.
38 * - value_holder<T> emulates move assignment when T is not move assignable
39 * (nothrow move constructibility required); this happens most notably with
40 * lambda functions, whose assignment operator is deleted by standard
41 * mandate [expr.prim.lambda]/20 even if the compiler generated one would
42 * work (capture by value).
43 * - To comply with [container.requirements.general]/3 (or, more precisely,
44 * its natural extension to polymorphic containers), value_holder ctors
45 * accept a first allocator arg passed by value_holder_allocator_adaptor,
46 * which must therefore be used in the vectors of value_holder's.
47 *
48 * A pointer to value_holder_base<T> can be reinterpret_cast'ed to T*.
49 * Emplacing is explicitly signalled with value_holder_emplacing_ctor to
50 * protect us from greedy T's constructible from anything (like
51 * boost::type_erasure::any).
52 */
53
54 struct value_holder_emplacing_ctor_t{};
55 constexpr value_holder_emplacing_ctor_t value_holder_emplacing_ctor=
56 value_holder_emplacing_ctor_t();
57
58 template<typename T>
59 class value_holder_base
60 {
61 protected:
62 typename std::aligned_storage<sizeof(T),alignof(T)>::type s;
63 };
64
65 template<typename T>
66 class value_holder:public value_holder_base<T>
67 {
68 template<typename U>
69 using enable_if_not_emplacing_ctor_t=typename std::enable_if<
70 !std::is_same<
71 typename std::decay<U>::type,value_holder_emplacing_ctor_t
72 >::value
73 >::type*;
74
75 using is_nothrow_move_constructible=std::is_nothrow_move_constructible<T>;
76 using is_copy_constructible=std::is_copy_constructible<T>;
77 using is_nothrow_copy_constructible=std::is_nothrow_copy_constructible<T>;
78 using is_move_assignable=std::is_move_assignable<T>;
79 using is_nothrow_move_assignable=std::is_nothrow_move_assignable<T>;
80 using is_equality_comparable=detail::is_equality_comparable<T>;
81 using is_nothrow_equality_comparable=
82 detail::is_nothrow_equality_comparable<T>;
83
84 T* data()noexcept{return reinterpret_cast<T*>(&this->s);}
85 const T* data()const noexcept
86 {return reinterpret_cast<const T*>(&this->s);}
87
88 T& value()noexcept{return *static_cast<T*>(data());}
89 const T& value()const noexcept{return *static_cast<const T*>(data());}
90
91 public:
92 template<
93 typename Allocator,
94 enable_if_not_emplacing_ctor_t<Allocator> =nullptr
95 >
96 value_holder(Allocator& al,const T& x)
97 noexcept(is_nothrow_copy_constructible::value)
98 {copy(al,x);}
99 template<
100 typename Allocator,
101 enable_if_not_emplacing_ctor_t<Allocator> =nullptr
102 >
103 value_holder(Allocator& al,T&& x)
104 noexcept(is_nothrow_move_constructible::value)
105 {std::allocator_traits<Allocator>::construct(al,data(),std::move(x));}
106 template<
107 typename Allocator,typename... Args,
108 enable_if_not_emplacing_ctor_t<Allocator> =nullptr
109 >
110 value_holder(Allocator& al,value_holder_emplacing_ctor_t,Args&&... args)
111 {std::allocator_traits<Allocator>::construct(
112 al,data(),std::forward<Args>(args)...);}
113 template<
114 typename Allocator,
115 enable_if_not_emplacing_ctor_t<Allocator> =nullptr
116 >
117 value_holder(Allocator& al,const value_holder& x)
118 noexcept(is_nothrow_copy_constructible::value)
119 {copy(al,x.value());}
120 template<
121 typename Allocator,
122 enable_if_not_emplacing_ctor_t<Allocator> =nullptr
123 >
124 value_holder(Allocator& al,value_holder&& x)
125 noexcept(is_nothrow_move_constructible::value)
126 {std::allocator_traits<Allocator>::construct(
127 al,data(),std::move(x.value()));}
128
129 /* stdlib implementations in current use are notoriously lacking at
130 * complying with [container.requirements.general]/3, so we keep the
131 * following to make their life easier.
132 */
133
134 value_holder(const T& x)
135 noexcept(is_nothrow_copy_constructible::value)
136 {copy(x);}
137 value_holder(T&& x)
138 noexcept(is_nothrow_move_constructible::value)
139 {::new ((void*)data()) T(std::move(x));}
140 template<typename... Args>
141 value_holder(value_holder_emplacing_ctor_t,Args&&... args)
142 {::new ((void*)data()) T(std::forward<Args>(args)...);}
143 value_holder(const value_holder& x)
144 noexcept(is_nothrow_copy_constructible::value)
145 {copy(x.value());}
146 value_holder(value_holder&& x)
147 noexcept(is_nothrow_move_constructible::value)
148 {::new ((void*)data()) T(std::move(x.value()));}
149
150 value_holder& operator=(const value_holder& x)=delete;
151 value_holder& operator=(value_holder&& x)
152 noexcept(is_nothrow_move_assignable::value||!is_move_assignable::value)
153 /* if 2nd clause: nothrow move constructibility required */
154 {
155 move_assign(std::move(x.value()));
156 return *this;
157 }
158
159 ~value_holder()noexcept{value().~T();}
160
161 friend bool operator==(const value_holder& x,const value_holder& y)
162 noexcept(is_nothrow_equality_comparable::value)
163 {
164 return x.equal(y.value());
165 }
166
167 private:
168 template<typename Allocator>
169 void copy(Allocator& al,const T& x){copy(al,x,is_copy_constructible{});}
170
171 template<typename Allocator>
172 void copy(Allocator& al,const T& x,std::true_type)
173 {
174 std::allocator_traits<Allocator>::construct(al,data(),x);
175 }
176
177 template<typename Allocator>
178 void copy(Allocator&,const T&,std::false_type)
179 {
180 throw not_copy_constructible{typeid(T)};
181 }
182
183 void copy(const T& x){copy(x,is_copy_constructible{});}
184
185 void copy(const T& x,std::true_type)
186 {
187 ::new (data()) T(x);
188 }
189
190 void copy(const T&,std::false_type)
191 {
192 throw not_copy_constructible{typeid(T)};
193 }
194
195 void move_assign(T&& x){move_assign(std::move(x),is_move_assignable{});}
196
197 void move_assign(T&& x,std::true_type)
198 {
199 value()=std::move(x);
200 }
201
202 void move_assign(T&& x,std::false_type)
203 {
204 /* emulated assignment */
205
206 static_assert(is_nothrow_move_constructible::value,
207 "type should be move assignable or nothrow move constructible");
208
209 if(data()!=boost::addressof(x)){
210 value().~T();
211 ::new (data()) T(std::move(x));
212 }
213 }
214
215 bool equal(const T& x)const{return equal(x,is_equality_comparable{});}
216
217 bool equal(const T& x,std::true_type)const
218 {
219 return value()==x;
220 }
221
222 bool equal(const T&,std::false_type)const
223 {
224 throw not_equality_comparable{typeid(T)};
225 }
226 };
227
228 template<typename Allocator>
229 struct value_holder_allocator_adaptor:Allocator
230 {
231 using traits=std::allocator_traits<Allocator>;
232
233 using value_type=typename traits::value_type;
234 using size_type=typename traits::size_type;
235 using difference_type=typename traits::difference_type;
236 using pointer=typename traits::pointer;
237 using const_pointer=typename traits::const_pointer;
238 using void_pointer=typename traits::void_pointer;
239 using const_void_pointer=typename traits::const_void_pointer;
240 using propagate_on_container_copy_assignment=
241 typename traits::propagate_on_container_copy_assignment;
242 using propagate_on_container_move_assignment=
243 typename traits::propagate_on_container_move_assignment;
244 using propagate_on_container_swap=
245 typename traits::propagate_on_container_swap;
246
247 template<typename U>
248 struct rebind
249 {
250 using other=value_holder_allocator_adaptor<
251 typename traits::template rebind_alloc<U>>;
252 };
253
254 value_holder_allocator_adaptor()=default;
255 value_holder_allocator_adaptor(
256 const value_holder_allocator_adaptor&)=default;
257
258 template<
259 typename Allocator2,
260 typename std::enable_if<
261 is_constructible<Allocator,Allocator2>::value
262 >::type* =nullptr
263 >
264 value_holder_allocator_adaptor(const Allocator2& x)noexcept:Allocator{x}{}
265
266 template<
267 typename Allocator2,
268 typename std::enable_if<
269 is_constructible<Allocator,Allocator2>::value
270 >::type* =nullptr
271 >
272 value_holder_allocator_adaptor(
273 const value_holder_allocator_adaptor<Allocator2>& x)noexcept:
274 Allocator{static_cast<const Allocator2&>(x)}{}
275
276 value_holder_allocator_adaptor& operator=(
277 const value_holder_allocator_adaptor&)=default;
278
279 template<typename T,typename... Args>
280 void construct(T* p,Args&&... args)
281 {
282 ::new ((void*)p) T(std::forward<Args>(args)...);
283 }
284
285 template<typename T,typename... Args>
286 void construct(value_holder<T>* p,Args&&... args)
287 {
288 ::new ((void*)p) value_holder<T>(
289 static_cast<Allocator&>(*this),std::forward<Args>(args)...);
290 }
291
292 template<typename T>
293 void destroy(T* p)
294 {
295 p->~T();
296 }
297
298 template<typename T>
299 void destroy(value_holder<T>* p)
300 {
301 traits::destroy(
302 static_cast<Allocator&>(*this),
303 reinterpret_cast<T*>(static_cast<value_holder_base<T>*>(p)));
304 }
305 };
306
307 } /* namespace poly_collection::detail */
308
309 } /* namespace poly_collection */
310
311 } /* namespace boost */
312
313 #endif