]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. |
2 | // Copyright (C) 2014-2016 Andrzej Krzemienski. | |
3 | // | |
4 | // Use, modification, and distribution is subject to the Boost Software | |
5 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
6 | // http://www.boost.org/LICENSE_1_0.txt) | |
7 | // | |
8 | // See http://www.boost.org/libs/optional for documentation. | |
9 | // | |
10 | // You are welcome to contact the maintainer at: | |
11 | // akrzemi1@gmail.com | |
12 | ||
13 | #ifndef BOOST_OPTIONAL_DETAIL_OLD_OPTIONAL_IMPLEMENTATION_AJK_28JAN2015_HPP | |
14 | #define BOOST_OPTIONAL_DETAIL_OLD_OPTIONAL_IMPLEMENTATION_AJK_28JAN2015_HPP | |
15 | ||
16 | #include <boost/detail/reference_content.hpp> | |
17 | #include <boost/mpl/bool.hpp> | |
18 | #include <boost/mpl/if.hpp> | |
19 | #include <boost/mpl/not.hpp> | |
20 | #include <boost/type_traits/is_reference.hpp> | |
21 | ||
22 | namespace boost { | |
23 | ||
24 | namespace optional_detail { | |
25 | ||
26 | ||
27 | template<class T> | |
28 | struct types_when_isnt_ref | |
29 | { | |
30 | typedef T const& reference_const_type ; | |
31 | typedef T & reference_type ; | |
32 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
33 | typedef T && rval_reference_type ; | |
34 | typedef T && reference_type_of_temporary_wrapper; | |
35 | #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES | |
36 | // GCC 4.4 has support for an early draft of rvalue references. The conforming version below | |
37 | // causes warnings about returning references to a temporary. | |
38 | static T&& move(T&& r) { return r; } | |
39 | #else | |
40 | static rval_reference_type move(reference_type r) { return boost::move(r); } | |
41 | #endif | |
42 | #endif | |
43 | typedef T const* pointer_const_type ; | |
44 | typedef T * pointer_type ; | |
45 | typedef T const& argument_type ; | |
46 | } ; | |
47 | ||
48 | template<class T> | |
49 | struct types_when_is_ref | |
50 | { | |
51 | typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type raw_type ; | |
52 | ||
53 | typedef raw_type& reference_const_type ; | |
54 | typedef raw_type& reference_type ; | |
55 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
56 | typedef BOOST_DEDUCED_TYPENAME remove_const<raw_type>::type&& rval_reference_type ; | |
57 | typedef raw_type& reference_type_of_temporary_wrapper; | |
58 | static reference_type move(reference_type r) { return r; } | |
59 | #endif | |
60 | typedef raw_type* pointer_const_type ; | |
61 | typedef raw_type* pointer_type ; | |
62 | typedef raw_type& argument_type ; | |
63 | } ; | |
64 | ||
65 | template <class To, class From> | |
66 | void prevent_binding_rvalue_ref_to_optional_lvalue_ref() | |
67 | { | |
68 | #ifndef BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES | |
69 | BOOST_STATIC_ASSERT_MSG( | |
70 | !boost::is_lvalue_reference<To>::value || !boost::is_rvalue_reference<From>::value, | |
71 | "binding rvalue references to optional lvalue references is disallowed"); | |
72 | #endif | |
73 | } | |
74 | ||
75 | struct optional_tag {} ; | |
76 | ||
77 | template<class T> | |
78 | class optional_base : public optional_tag | |
79 | { | |
80 | private : | |
81 | ||
82 | typedef | |
83 | #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) | |
84 | BOOST_DEDUCED_TYPENAME | |
85 | #endif | |
86 | ::boost::detail::make_reference_content<T>::type internal_type ; | |
87 | ||
88 | typedef aligned_storage<internal_type> storage_type ; | |
89 | ||
90 | typedef types_when_isnt_ref<T> types_when_not_ref ; | |
91 | typedef types_when_is_ref<T> types_when_ref ; | |
92 | ||
93 | typedef optional_base<T> this_type ; | |
94 | ||
95 | protected : | |
96 | ||
97 | typedef T value_type ; | |
98 | ||
99 | typedef mpl::true_ is_reference_tag ; | |
100 | typedef mpl::false_ is_not_reference_tag ; | |
101 | ||
102 | typedef BOOST_DEDUCED_TYPENAME is_reference<T>::type is_reference_predicate ; | |
103 | ||
104 | public: | |
105 | typedef BOOST_DEDUCED_TYPENAME mpl::if_<is_reference_predicate,types_when_ref,types_when_not_ref>::type types ; | |
106 | ||
107 | protected: | |
108 | typedef BOOST_DEDUCED_TYPENAME types::reference_type reference_type ; | |
109 | typedef BOOST_DEDUCED_TYPENAME types::reference_const_type reference_const_type ; | |
110 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
111 | typedef BOOST_DEDUCED_TYPENAME types::rval_reference_type rval_reference_type ; | |
112 | typedef BOOST_DEDUCED_TYPENAME types::reference_type_of_temporary_wrapper reference_type_of_temporary_wrapper ; | |
113 | #endif | |
114 | typedef BOOST_DEDUCED_TYPENAME types::pointer_type pointer_type ; | |
115 | typedef BOOST_DEDUCED_TYPENAME types::pointer_const_type pointer_const_type ; | |
116 | typedef BOOST_DEDUCED_TYPENAME types::argument_type argument_type ; | |
117 | ||
118 | // Creates an optional<T> uninitialized. | |
119 | // No-throw | |
120 | optional_base() | |
121 | : | |
122 | m_initialized(false) {} | |
123 | ||
124 | // Creates an optional<T> uninitialized. | |
125 | // No-throw | |
126 | optional_base ( none_t ) | |
127 | : | |
128 | m_initialized(false) {} | |
129 | ||
130 | // Creates an optional<T> initialized with 'val'. | |
131 | // Can throw if T::T(T const&) does | |
132 | optional_base ( argument_type val ) | |
133 | : | |
134 | m_initialized(false) | |
135 | { | |
136 | construct(val); | |
137 | } | |
138 | ||
139 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
140 | // move-construct an optional<T> initialized from an rvalue-ref to 'val'. | |
141 | // Can throw if T::T(T&&) does | |
142 | optional_base ( rval_reference_type val ) | |
143 | : | |
144 | m_initialized(false) | |
145 | { | |
146 | construct( boost::move(val) ); | |
147 | } | |
148 | #endif | |
149 | ||
150 | // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional<T>. | |
151 | // Can throw if T::T(T const&) does | |
152 | optional_base ( bool cond, argument_type val ) | |
153 | : | |
154 | m_initialized(false) | |
155 | { | |
156 | if ( cond ) | |
157 | construct(val); | |
158 | } | |
159 | ||
160 | // Creates a deep copy of another optional<T> | |
161 | // Can throw if T::T(T const&) does | |
162 | optional_base ( optional_base const& rhs ) | |
163 | : | |
164 | m_initialized(false) | |
165 | { | |
166 | if ( rhs.is_initialized() ) | |
167 | construct(rhs.get_impl()); | |
168 | } | |
169 | ||
170 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
171 | // Creates a deep move of another optional<T> | |
172 | // Can throw if T::T(T&&) does | |
173 | optional_base ( optional_base&& rhs ) | |
174 | : | |
175 | m_initialized(false) | |
176 | { | |
177 | if ( rhs.is_initialized() ) | |
178 | construct( boost::move(rhs.get_impl()) ); | |
179 | } | |
180 | #endif | |
181 | ||
182 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
183 | ||
184 | template<class Expr, class PtrExpr> | |
185 | explicit optional_base ( Expr&& expr, PtrExpr const* tag ) | |
186 | : | |
187 | m_initialized(false) | |
188 | { | |
189 | construct(boost::forward<Expr>(expr),tag); | |
190 | } | |
191 | ||
192 | #else | |
193 | // This is used for both converting and in-place constructions. | |
194 | // Derived classes use the 'tag' to select the appropriate | |
195 | // implementation (the correct 'construct()' overload) | |
196 | template<class Expr> | |
197 | explicit optional_base ( Expr const& expr, Expr const* tag ) | |
198 | : | |
199 | m_initialized(false) | |
200 | { | |
201 | construct(expr,tag); | |
202 | } | |
203 | ||
204 | #endif | |
205 | ||
206 | ||
207 | // No-throw (assuming T::~T() doesn't) | |
208 | ~optional_base() { destroy() ; } | |
209 | ||
210 | // Assigns from another optional<T> (deep-copies the rhs value) | |
211 | void assign ( optional_base const& rhs ) | |
212 | { | |
213 | if (is_initialized()) | |
214 | { | |
215 | if ( rhs.is_initialized() ) | |
216 | assign_value(rhs.get_impl(), is_reference_predicate() ); | |
217 | else destroy(); | |
218 | } | |
219 | else | |
220 | { | |
221 | if ( rhs.is_initialized() ) | |
222 | construct(rhs.get_impl()); | |
223 | } | |
224 | } | |
225 | ||
226 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
227 | // Assigns from another optional<T> (deep-moves the rhs value) | |
228 | void assign ( optional_base&& rhs ) | |
229 | { | |
230 | if (is_initialized()) | |
231 | { | |
232 | if ( rhs.is_initialized() ) | |
233 | assign_value(boost::move(rhs.get_impl()), is_reference_predicate() ); | |
234 | else destroy(); | |
235 | } | |
236 | else | |
237 | { | |
238 | if ( rhs.is_initialized() ) | |
239 | construct(boost::move(rhs.get_impl())); | |
240 | } | |
241 | } | |
242 | #endif | |
243 | ||
244 | // Assigns from another _convertible_ optional<U> (deep-copies the rhs value) | |
245 | template<class U> | |
246 | void assign ( optional<U> const& rhs ) | |
247 | { | |
248 | if (is_initialized()) | |
249 | { | |
250 | if ( rhs.is_initialized() ) | |
251 | #ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES | |
252 | assign_value(rhs.get(), is_reference_predicate() ); | |
253 | #else | |
254 | assign_value(static_cast<value_type>(rhs.get()), is_reference_predicate() ); | |
255 | #endif | |
256 | ||
257 | else destroy(); | |
258 | } | |
259 | else | |
260 | { | |
261 | if ( rhs.is_initialized() ) | |
262 | #ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES | |
263 | construct(rhs.get()); | |
264 | #else | |
265 | construct(static_cast<value_type>(rhs.get())); | |
266 | #endif | |
267 | } | |
268 | } | |
269 | ||
270 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
271 | // move-assigns from another _convertible_ optional<U> (deep-moves from the rhs value) | |
272 | template<class U> | |
273 | void assign ( optional<U>&& rhs ) | |
274 | { | |
275 | typedef BOOST_DEDUCED_TYPENAME optional<U>::rval_reference_type ref_type; | |
276 | if (is_initialized()) | |
277 | { | |
278 | if ( rhs.is_initialized() ) | |
279 | assign_value(static_cast<ref_type>(rhs.get()), is_reference_predicate() ); | |
280 | else destroy(); | |
281 | } | |
282 | else | |
283 | { | |
284 | if ( rhs.is_initialized() ) | |
285 | construct(static_cast<ref_type>(rhs.get())); | |
286 | } | |
287 | } | |
288 | #endif | |
289 | ||
290 | // Assigns from a T (deep-copies the rhs value) | |
291 | void assign ( argument_type val ) | |
292 | { | |
293 | if (is_initialized()) | |
294 | assign_value(val, is_reference_predicate() ); | |
295 | else construct(val); | |
296 | } | |
297 | ||
298 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
299 | // Assigns from a T (deep-moves the rhs value) | |
300 | void assign ( rval_reference_type val ) | |
301 | { | |
302 | if (is_initialized()) | |
303 | assign_value( boost::move(val), is_reference_predicate() ); | |
304 | else construct( boost::move(val) ); | |
305 | } | |
306 | #endif | |
307 | ||
308 | // Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED | |
309 | // No-throw (assuming T::~T() doesn't) | |
310 | void assign ( none_t ) BOOST_NOEXCEPT { destroy(); } | |
311 | ||
312 | #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT | |
313 | ||
314 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
315 | template<class Expr, class ExprPtr> | |
316 | void assign_expr ( Expr&& expr, ExprPtr const* tag ) | |
317 | { | |
318 | if (is_initialized()) | |
319 | assign_expr_to_initialized(boost::forward<Expr>(expr),tag); | |
320 | else construct(boost::forward<Expr>(expr),tag); | |
321 | } | |
322 | #else | |
323 | template<class Expr> | |
324 | void assign_expr ( Expr const& expr, Expr const* tag ) | |
325 | { | |
326 | if (is_initialized()) | |
327 | assign_expr_to_initialized(expr,tag); | |
328 | else construct(expr,tag); | |
329 | } | |
330 | #endif | |
331 | ||
332 | #endif | |
333 | ||
334 | public : | |
335 | ||
336 | // **DEPPRECATED** Destroys the current value, if any, leaving this UNINITIALIZED | |
337 | // No-throw (assuming T::~T() doesn't) | |
338 | void reset() BOOST_NOEXCEPT { destroy(); } | |
339 | ||
340 | // **DEPPRECATED** Replaces the current value -if any- with 'val' | |
341 | void reset ( argument_type val ) { assign(val); } | |
342 | ||
343 | // Returns a pointer to the value if this is initialized, otherwise, | |
344 | // returns NULL. | |
345 | // No-throw | |
346 | pointer_const_type get_ptr() const { return m_initialized ? get_ptr_impl() : 0 ; } | |
347 | pointer_type get_ptr() { return m_initialized ? get_ptr_impl() : 0 ; } | |
348 | ||
349 | bool is_initialized() const { return m_initialized ; } | |
350 | ||
351 | protected : | |
352 | ||
353 | void construct ( argument_type val ) | |
354 | { | |
355 | ::new (m_storage.address()) internal_type(val) ; | |
356 | m_initialized = true ; | |
357 | } | |
358 | ||
359 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
360 | void construct ( rval_reference_type val ) | |
361 | { | |
362 | ::new (m_storage.address()) internal_type( types::move(val) ) ; | |
363 | m_initialized = true ; | |
364 | } | |
365 | #endif | |
366 | ||
367 | ||
368 | #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) | |
369 | // Constructs in-place | |
370 | // upon exception *this is always uninitialized | |
371 | template<class... Args> | |
372 | void emplace_assign ( Args&&... args ) | |
373 | { | |
374 | destroy(); | |
375 | ::new (m_storage.address()) internal_type( boost::forward<Args>(args)... ); | |
376 | m_initialized = true ; | |
377 | } | |
378 | #elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) | |
379 | template<class Arg> | |
380 | void emplace_assign ( Arg&& arg ) | |
381 | { | |
382 | destroy(); | |
383 | ::new (m_storage.address()) internal_type( boost::forward<Arg>(arg) ); | |
384 | m_initialized = true ; | |
385 | } | |
386 | ||
387 | void emplace_assign () | |
388 | { | |
389 | destroy(); | |
390 | ::new (m_storage.address()) internal_type(); | |
391 | m_initialized = true ; | |
392 | } | |
393 | #else | |
394 | template<class Arg> | |
395 | void emplace_assign ( const Arg& arg ) | |
396 | { | |
397 | destroy(); | |
398 | ::new (m_storage.address()) internal_type( arg ); | |
399 | m_initialized = true ; | |
400 | } | |
401 | ||
402 | template<class Arg> | |
403 | void emplace_assign ( Arg& arg ) | |
404 | { | |
405 | destroy(); | |
406 | ::new (m_storage.address()) internal_type( arg ); | |
407 | m_initialized = true ; | |
408 | } | |
409 | ||
410 | void emplace_assign () | |
411 | { | |
412 | destroy(); | |
413 | ::new (m_storage.address()) internal_type(); | |
414 | m_initialized = true ; | |
415 | } | |
416 | #endif | |
417 | ||
418 | #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT | |
419 | ||
420 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
421 | // Constructs in-place using the given factory | |
422 | template<class Expr> | |
423 | void construct ( Expr&& factory, in_place_factory_base const* ) | |
424 | { | |
425 | BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ; | |
426 | boost_optional_detail::construct<value_type>(factory, m_storage.address()); | |
427 | m_initialized = true ; | |
428 | } | |
429 | ||
430 | // Constructs in-place using the given typed factory | |
431 | template<class Expr> | |
432 | void construct ( Expr&& factory, typed_in_place_factory_base const* ) | |
433 | { | |
434 | BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ; | |
435 | factory.apply(m_storage.address()) ; | |
436 | m_initialized = true ; | |
437 | } | |
438 | ||
439 | template<class Expr> | |
440 | void assign_expr_to_initialized ( Expr&& factory, in_place_factory_base const* tag ) | |
441 | { | |
442 | destroy(); | |
443 | construct(factory,tag); | |
444 | } | |
445 | ||
446 | // Constructs in-place using the given typed factory | |
447 | template<class Expr> | |
448 | void assign_expr_to_initialized ( Expr&& factory, typed_in_place_factory_base const* tag ) | |
449 | { | |
450 | destroy(); | |
451 | construct(factory,tag); | |
452 | } | |
453 | ||
454 | #else | |
455 | // Constructs in-place using the given factory | |
456 | template<class Expr> | |
457 | void construct ( Expr const& factory, in_place_factory_base const* ) | |
458 | { | |
459 | BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ; | |
460 | boost_optional_detail::construct<value_type>(factory, m_storage.address()); | |
461 | m_initialized = true ; | |
462 | } | |
463 | ||
464 | // Constructs in-place using the given typed factory | |
465 | template<class Expr> | |
466 | void construct ( Expr const& factory, typed_in_place_factory_base const* ) | |
467 | { | |
468 | BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ; | |
469 | factory.apply(m_storage.address()) ; | |
470 | m_initialized = true ; | |
471 | } | |
472 | ||
473 | template<class Expr> | |
474 | void assign_expr_to_initialized ( Expr const& factory, in_place_factory_base const* tag ) | |
475 | { | |
476 | destroy(); | |
477 | construct(factory,tag); | |
478 | } | |
479 | ||
480 | // Constructs in-place using the given typed factory | |
481 | template<class Expr> | |
482 | void assign_expr_to_initialized ( Expr const& factory, typed_in_place_factory_base const* tag ) | |
483 | { | |
484 | destroy(); | |
485 | construct(factory,tag); | |
486 | } | |
487 | #endif | |
488 | ||
489 | #endif | |
490 | ||
491 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
492 | // Constructs using any expression implicitly convertible to the single argument | |
493 | // of a one-argument T constructor. | |
494 | // Converting constructions of optional<T> from optional<U> uses this function with | |
495 | // 'Expr' being of type 'U' and relying on a converting constructor of T from U. | |
496 | template<class Expr> | |
497 | void construct ( Expr&& expr, void const* ) | |
498 | { | |
499 | new (m_storage.address()) internal_type(boost::forward<Expr>(expr)) ; | |
500 | m_initialized = true ; | |
501 | } | |
502 | ||
503 | // Assigns using a form any expression implicitly convertible to the single argument | |
504 | // of a T's assignment operator. | |
505 | // Converting assignments of optional<T> from optional<U> uses this function with | |
506 | // 'Expr' being of type 'U' and relying on a converting assignment of T from U. | |
507 | template<class Expr> | |
508 | void assign_expr_to_initialized ( Expr&& expr, void const* ) | |
509 | { | |
510 | assign_value(boost::forward<Expr>(expr), is_reference_predicate()); | |
511 | } | |
512 | #else | |
513 | // Constructs using any expression implicitly convertible to the single argument | |
514 | // of a one-argument T constructor. | |
515 | // Converting constructions of optional<T> from optional<U> uses this function with | |
516 | // 'Expr' being of type 'U' and relying on a converting constructor of T from U. | |
517 | template<class Expr> | |
518 | void construct ( Expr const& expr, void const* ) | |
519 | { | |
520 | new (m_storage.address()) internal_type(expr) ; | |
521 | m_initialized = true ; | |
522 | } | |
523 | ||
524 | // Assigns using a form any expression implicitly convertible to the single argument | |
525 | // of a T's assignment operator. | |
526 | // Converting assignments of optional<T> from optional<U> uses this function with | |
527 | // 'Expr' being of type 'U' and relying on a converting assignment of T from U. | |
528 | template<class Expr> | |
529 | void assign_expr_to_initialized ( Expr const& expr, void const* ) | |
530 | { | |
531 | assign_value(expr, is_reference_predicate()); | |
532 | } | |
533 | ||
534 | #endif | |
535 | ||
536 | #ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION | |
537 | // BCB5.64 (and probably lower versions) workaround. | |
538 | // The in-place factories are supported by means of catch-all constructors | |
539 | // and assignment operators (the functions are parameterized in terms of | |
540 | // an arbitrary 'Expr' type) | |
541 | // This compiler incorrectly resolves the overload set and sinks optional<T> and optional<U> | |
542 | // to the 'Expr'-taking functions even though explicit overloads are present for them. | |
543 | // Thus, the following overload is needed to properly handle the case when the 'lhs' | |
544 | // is another optional. | |
545 | // | |
546 | // For VC<=70 compilers this workaround dosen't work becasue the comnpiler issues and error | |
547 | // instead of choosing the wrong overload | |
548 | // | |
549 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
550 | // Notice that 'Expr' will be optional<T> or optional<U> (but not optional_base<..>) | |
551 | template<class Expr> | |
552 | void construct ( Expr&& expr, optional_tag const* ) | |
553 | { | |
554 | if ( expr.is_initialized() ) | |
555 | { | |
556 | // An exception can be thrown here. | |
557 | // It it happens, THIS will be left uninitialized. | |
558 | new (m_storage.address()) internal_type(types::move(expr.get())) ; | |
559 | m_initialized = true ; | |
560 | } | |
561 | } | |
562 | #else | |
563 | // Notice that 'Expr' will be optional<T> or optional<U> (but not optional_base<..>) | |
564 | template<class Expr> | |
565 | void construct ( Expr const& expr, optional_tag const* ) | |
566 | { | |
567 | if ( expr.is_initialized() ) | |
568 | { | |
569 | // An exception can be thrown here. | |
570 | // It it happens, THIS will be left uninitialized. | |
571 | new (m_storage.address()) internal_type(expr.get()) ; | |
572 | m_initialized = true ; | |
573 | } | |
574 | } | |
575 | #endif | |
576 | #endif // defined BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION | |
577 | ||
578 | void assign_value ( argument_type val, is_not_reference_tag ) { get_impl() = val; } | |
579 | void assign_value ( argument_type val, is_reference_tag ) { construct(val); } | |
580 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
581 | void assign_value ( rval_reference_type val, is_not_reference_tag ) { get_impl() = static_cast<rval_reference_type>(val); } | |
582 | void assign_value ( rval_reference_type val, is_reference_tag ) { construct( static_cast<rval_reference_type>(val) ); } | |
583 | #endif | |
584 | ||
585 | void destroy() | |
586 | { | |
587 | if ( m_initialized ) | |
588 | destroy_impl(is_reference_predicate()) ; | |
589 | } | |
590 | ||
591 | reference_const_type get_impl() const { return dereference(get_object(), is_reference_predicate() ) ; } | |
592 | reference_type get_impl() { return dereference(get_object(), is_reference_predicate() ) ; } | |
593 | ||
594 | pointer_const_type get_ptr_impl() const { return cast_ptr(get_object(), is_reference_predicate() ) ; } | |
595 | pointer_type get_ptr_impl() { return cast_ptr(get_object(), is_reference_predicate() ) ; } | |
596 | ||
597 | private : | |
598 | ||
599 | // internal_type can be either T or reference_content<T> | |
600 | #if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS) | |
601 | // This workaround is supposed to silence GCC warnings about broken strict aliasing rules | |
602 | internal_type const* get_object() const | |
603 | { | |
604 | union { void const* ap_pvoid; internal_type const* as_ptype; } caster = { m_storage.address() }; | |
605 | return caster.as_ptype; | |
606 | } | |
607 | internal_type * get_object() | |
608 | { | |
609 | union { void* ap_pvoid; internal_type* as_ptype; } caster = { m_storage.address() }; | |
610 | return caster.as_ptype; | |
611 | } | |
612 | #else | |
613 | internal_type const* get_object() const { return static_cast<internal_type const*>(m_storage.address()); } | |
614 | internal_type * get_object() { return static_cast<internal_type *> (m_storage.address()); } | |
615 | #endif | |
616 | ||
617 | // reference_content<T> lacks an implicit conversion to T&, so the following is needed to obtain a proper reference. | |
618 | reference_const_type dereference( internal_type const* p, is_not_reference_tag ) const { return *p ; } | |
619 | reference_type dereference( internal_type* p, is_not_reference_tag ) { return *p ; } | |
620 | reference_const_type dereference( internal_type const* p, is_reference_tag ) const { return p->get() ; } | |
621 | reference_type dereference( internal_type* p, is_reference_tag ) { return p->get() ; } | |
622 | ||
623 | #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581)) | |
624 | void destroy_impl ( is_not_reference_tag ) { get_ptr_impl()->internal_type::~internal_type() ; m_initialized = false ; } | |
625 | #else | |
626 | void destroy_impl ( is_not_reference_tag ) { get_ptr_impl()->~T() ; m_initialized = false ; } | |
627 | #endif | |
628 | ||
629 | void destroy_impl ( is_reference_tag ) { m_initialized = false ; } | |
630 | ||
631 | // If T is of reference type, trying to get a pointer to the held value must result in a compile-time error. | |
632 | // Decent compilers should disallow conversions from reference_content<T>* to T*, but just in case, | |
633 | // the following olverloads are used to filter out the case and guarantee an error in case of T being a reference. | |
634 | pointer_const_type cast_ptr( internal_type const* p, is_not_reference_tag ) const { return p ; } | |
635 | pointer_type cast_ptr( internal_type * p, is_not_reference_tag ) { return p ; } | |
636 | pointer_const_type cast_ptr( internal_type const* p, is_reference_tag ) const { return &p->get() ; } | |
637 | pointer_type cast_ptr( internal_type * p, is_reference_tag ) { return &p->get() ; } | |
638 | ||
639 | bool m_initialized ; | |
640 | storage_type m_storage ; | |
641 | } ; | |
642 | ||
643 | } // namespace optional_detail | |
644 | ||
645 | template<class T> | |
646 | class optional : public optional_detail::optional_base<T> | |
647 | { | |
648 | typedef optional_detail::optional_base<T> base ; | |
649 | ||
650 | public : | |
651 | ||
652 | typedef optional<T> this_type ; | |
653 | ||
654 | typedef BOOST_DEDUCED_TYPENAME base::value_type value_type ; | |
655 | typedef BOOST_DEDUCED_TYPENAME base::reference_type reference_type ; | |
656 | typedef BOOST_DEDUCED_TYPENAME base::reference_const_type reference_const_type ; | |
657 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
658 | typedef BOOST_DEDUCED_TYPENAME base::rval_reference_type rval_reference_type ; | |
659 | typedef BOOST_DEDUCED_TYPENAME base::reference_type_of_temporary_wrapper reference_type_of_temporary_wrapper ; | |
660 | #endif | |
661 | typedef BOOST_DEDUCED_TYPENAME base::pointer_type pointer_type ; | |
662 | typedef BOOST_DEDUCED_TYPENAME base::pointer_const_type pointer_const_type ; | |
663 | typedef BOOST_DEDUCED_TYPENAME base::argument_type argument_type ; | |
664 | ||
665 | // Creates an optional<T> uninitialized. | |
666 | // No-throw | |
667 | optional() BOOST_NOEXCEPT : base() {} | |
668 | ||
669 | // Creates an optional<T> uninitialized. | |
670 | // No-throw | |
671 | optional( none_t none_ ) BOOST_NOEXCEPT : base(none_) {} | |
672 | ||
673 | // Creates an optional<T> initialized with 'val'. | |
674 | // Can throw if T::T(T const&) does | |
675 | optional ( argument_type val ) : base(val) {} | |
676 | ||
677 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
678 | // Creates an optional<T> initialized with 'move(val)'. | |
679 | // Can throw if T::T(T &&) does | |
680 | optional ( rval_reference_type val ) : base( boost::forward<T>(val) ) | |
681 | {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, rval_reference_type>();} | |
682 | #endif | |
683 | ||
684 | // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. | |
685 | // Can throw if T::T(T const&) does | |
686 | optional ( bool cond, argument_type val ) : base(cond,val) {} | |
687 | ||
688 | // NOTE: MSVC needs templated versions first | |
689 | ||
690 | // Creates a deep copy of another convertible optional<U> | |
691 | // Requires a valid conversion from U to T. | |
692 | // Can throw if T::T(U const&) does | |
693 | template<class U> | |
694 | explicit optional ( optional<U> const& rhs ) | |
695 | : | |
696 | base() | |
697 | { | |
698 | if ( rhs.is_initialized() ) | |
699 | this->construct(rhs.get()); | |
700 | } | |
701 | ||
702 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
703 | // Creates a deep move of another convertible optional<U> | |
704 | // Requires a valid conversion from U to T. | |
705 | // Can throw if T::T(U&&) does | |
706 | template<class U> | |
707 | explicit optional ( optional<U> && rhs ) | |
708 | : | |
709 | base() | |
710 | { | |
711 | if ( rhs.is_initialized() ) | |
712 | this->construct( boost::move(rhs.get()) ); | |
713 | } | |
714 | #endif | |
715 | ||
716 | #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT | |
717 | // Creates an optional<T> with an expression which can be either | |
718 | // (a) An instance of InPlaceFactory (i.e. in_place(a,b,...,n); | |
719 | // (b) An instance of TypedInPlaceFactory ( i.e. in_place<T>(a,b,...,n); | |
720 | // (c) Any expression implicitly convertible to the single type | |
721 | // of a one-argument T's constructor. | |
722 | // (d*) Weak compilers (BCB) might also resolved Expr as optional<T> and optional<U> | |
723 | // even though explicit overloads are present for these. | |
724 | // Depending on the above some T ctor is called. | |
725 | // Can throw if the resolved T ctor throws. | |
726 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
727 | ||
728 | ||
729 | template<class Expr> | |
730 | explicit optional ( Expr&& expr, | |
731 | BOOST_DEDUCED_TYPENAME boost::disable_if_c< | |
732 | (boost::is_base_of<optional_detail::optional_tag, BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type>::value) || | |
733 | boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type, none_t>::value >::type* = 0 | |
734 | ) | |
735 | : base(boost::forward<Expr>(expr),boost::addressof(expr)) | |
736 | {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, Expr&&>();} | |
737 | ||
738 | #else | |
739 | template<class Expr> | |
740 | explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {} | |
741 | #endif // !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
742 | #endif // !defined BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT | |
743 | ||
744 | // Creates a deep copy of another optional<T> | |
745 | // Can throw if T::T(T const&) does | |
746 | optional ( optional const& rhs ) : base( static_cast<base const&>(rhs) ) {} | |
747 | ||
748 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
749 | // Creates a deep move of another optional<T> | |
750 | // Can throw if T::T(T&&) does | |
751 | optional ( optional && rhs ) | |
752 | BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value) | |
753 | : base( boost::move(rhs) ) | |
754 | {} | |
755 | ||
756 | #endif | |
757 | // No-throw (assuming T::~T() doesn't) | |
758 | ~optional() {} | |
759 | ||
760 | #if !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) | |
761 | // Assigns from an expression. See corresponding constructor. | |
762 | // Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED | |
763 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
764 | ||
765 | template<class Expr> | |
766 | BOOST_DEDUCED_TYPENAME boost::disable_if_c< | |
767 | boost::is_base_of<optional_detail::optional_tag, BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type>::value || | |
768 | boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type, none_t>::value, | |
769 | optional& | |
770 | >::type | |
771 | operator= ( Expr&& expr ) | |
772 | { | |
773 | optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, Expr&&>(); | |
774 | this->assign_expr(boost::forward<Expr>(expr),boost::addressof(expr)); | |
775 | return *this ; | |
776 | } | |
777 | ||
778 | #else | |
779 | template<class Expr> | |
780 | optional& operator= ( Expr const& expr ) | |
781 | { | |
782 | this->assign_expr(expr,boost::addressof(expr)); | |
783 | return *this ; | |
784 | } | |
785 | #endif // !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
786 | #endif // !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) | |
787 | ||
788 | // Copy-assigns from another convertible optional<U> (converts && deep-copies the rhs value) | |
789 | // Requires a valid conversion from U to T. | |
790 | // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED | |
791 | template<class U> | |
792 | optional& operator= ( optional<U> const& rhs ) | |
793 | { | |
794 | this->assign(rhs); | |
795 | return *this ; | |
796 | } | |
797 | ||
798 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
799 | // Move-assigns from another convertible optional<U> (converts && deep-moves the rhs value) | |
800 | // Requires a valid conversion from U to T. | |
801 | // Basic Guarantee: If T::T( U && ) throws, this is left UNINITIALIZED | |
802 | template<class U> | |
803 | optional& operator= ( optional<U> && rhs ) | |
804 | { | |
805 | this->assign(boost::move(rhs)); | |
806 | return *this ; | |
807 | } | |
808 | #endif | |
809 | ||
810 | // Assigns from another optional<T> (deep-copies the rhs value) | |
811 | // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED | |
812 | // (NOTE: On BCB, this operator is not actually called and left is left UNMODIFIED in case of a throw) | |
813 | optional& operator= ( optional const& rhs ) | |
814 | { | |
815 | this->assign( static_cast<base const&>(rhs) ) ; | |
816 | return *this ; | |
817 | } | |
818 | ||
819 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
820 | // Assigns from another optional<T> (deep-moves the rhs value) | |
821 | optional& operator= ( optional && rhs ) | |
822 | BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && ::boost::is_nothrow_move_assignable<T>::value) | |
823 | { | |
824 | this->assign( static_cast<base &&>(rhs) ) ; | |
825 | return *this ; | |
826 | } | |
827 | #endif | |
828 | ||
829 | // Assigns from a T (deep-copies the rhs value) | |
830 | // Basic Guarantee: If T::( T const& ) throws, this is left UNINITIALIZED | |
831 | optional& operator= ( argument_type val ) | |
832 | { | |
833 | this->assign( val ) ; | |
834 | return *this ; | |
835 | } | |
836 | ||
837 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
838 | // Assigns from a T (deep-moves the rhs value) | |
839 | optional& operator= ( rval_reference_type val ) | |
840 | { | |
841 | optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, rval_reference_type>(); | |
842 | this->assign( boost::move(val) ) ; | |
843 | return *this ; | |
844 | } | |
845 | #endif | |
846 | ||
847 | // Assigns from a "none" | |
848 | // Which destroys the current value, if any, leaving this UNINITIALIZED | |
849 | // No-throw (assuming T::~T() doesn't) | |
850 | optional& operator= ( none_t none_ ) BOOST_NOEXCEPT | |
851 | { | |
852 | this->assign( none_ ) ; | |
853 | return *this ; | |
854 | } | |
855 | ||
856 | #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) | |
857 | // Constructs in-place | |
858 | // upon exception *this is always uninitialized | |
859 | template<class... Args> | |
860 | void emplace ( Args&&... args ) | |
861 | { | |
862 | this->emplace_assign( boost::forward<Args>(args)... ); | |
863 | } | |
864 | #elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) | |
865 | template<class Arg> | |
866 | void emplace ( Arg&& arg ) | |
867 | { | |
868 | this->emplace_assign( boost::forward<Arg>(arg) ); | |
869 | } | |
870 | ||
871 | void emplace () | |
872 | { | |
873 | this->emplace_assign(); | |
874 | } | |
875 | #else | |
876 | template<class Arg> | |
877 | void emplace ( const Arg& arg ) | |
878 | { | |
879 | this->emplace_assign( arg ); | |
880 | } | |
881 | ||
882 | template<class Arg> | |
883 | void emplace ( Arg& arg ) | |
884 | { | |
885 | this->emplace_assign( arg ); | |
886 | } | |
887 | ||
888 | void emplace () | |
889 | { | |
890 | this->emplace_assign(); | |
891 | } | |
892 | #endif | |
893 | ||
894 | void swap( optional & arg ) | |
895 | BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && ::boost::is_nothrow_move_assignable<T>::value) | |
896 | { | |
897 | // allow for Koenig lookup | |
898 | boost::swap(*this, arg); | |
899 | } | |
900 | ||
901 | ||
902 | // Returns a reference to the value if this is initialized, otherwise, | |
903 | // the behaviour is UNDEFINED | |
904 | // No-throw | |
905 | reference_const_type get() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); } | |
906 | reference_type get() { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); } | |
907 | ||
908 | // Returns a copy of the value if this is initialized, 'v' otherwise | |
909 | reference_const_type get_value_or ( reference_const_type v ) const { return this->is_initialized() ? get() : v ; } | |
910 | reference_type get_value_or ( reference_type v ) { return this->is_initialized() ? get() : v ; } | |
911 | ||
912 | // Returns a pointer to the value if this is initialized, otherwise, | |
913 | // the behaviour is UNDEFINED | |
914 | // No-throw | |
915 | pointer_const_type operator->() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_ptr_impl() ; } | |
916 | pointer_type operator->() { BOOST_ASSERT(this->is_initialized()) ; return this->get_ptr_impl() ; } | |
917 | ||
918 | // Returns a reference to the value if this is initialized, otherwise, | |
919 | // the behaviour is UNDEFINED | |
920 | // No-throw | |
921 | #if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) | |
922 | reference_const_type operator *() const& { return this->get() ; } | |
923 | reference_type operator *() & { return this->get() ; } | |
924 | reference_type_of_temporary_wrapper operator *() && { return base::types::move(this->get()) ; } | |
925 | #else | |
926 | reference_const_type operator *() const { return this->get() ; } | |
927 | reference_type operator *() { return this->get() ; } | |
928 | #endif // !defined BOOST_NO_CXX11_REF_QUALIFIERS | |
929 | ||
930 | #if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) | |
931 | reference_const_type value() const& | |
932 | { | |
933 | if (this->is_initialized()) | |
934 | return this->get() ; | |
935 | else | |
936 | throw_exception(bad_optional_access()); | |
937 | } | |
938 | ||
939 | reference_type value() & | |
940 | { | |
941 | if (this->is_initialized()) | |
942 | return this->get() ; | |
943 | else | |
944 | throw_exception(bad_optional_access()); | |
945 | } | |
946 | ||
947 | reference_type_of_temporary_wrapper value() && | |
948 | { | |
949 | if (this->is_initialized()) | |
950 | return base::types::move(this->get()) ; | |
951 | else | |
952 | throw_exception(bad_optional_access()); | |
953 | } | |
954 | ||
955 | #else | |
956 | reference_const_type value() const | |
957 | { | |
958 | if (this->is_initialized()) | |
959 | return this->get() ; | |
960 | else | |
961 | throw_exception(bad_optional_access()); | |
962 | } | |
963 | ||
964 | reference_type value() | |
965 | { | |
966 | if (this->is_initialized()) | |
967 | return this->get() ; | |
968 | else | |
969 | throw_exception(bad_optional_access()); | |
970 | } | |
971 | #endif | |
972 | ||
973 | ||
974 | #ifndef BOOST_NO_CXX11_REF_QUALIFIERS | |
975 | template <class U> | |
976 | value_type value_or ( U&& v ) const& | |
977 | { | |
978 | if (this->is_initialized()) | |
979 | return get(); | |
980 | else | |
981 | return boost::forward<U>(v); | |
982 | } | |
983 | ||
984 | template <class U> | |
985 | value_type value_or ( U&& v ) && | |
986 | { | |
987 | if (this->is_initialized()) | |
988 | return base::types::move(get()); | |
989 | else | |
990 | return boost::forward<U>(v); | |
991 | } | |
992 | #elif !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES | |
993 | template <class U> | |
994 | value_type value_or ( U&& v ) const | |
995 | { | |
996 | if (this->is_initialized()) | |
997 | return get(); | |
998 | else | |
999 | return boost::forward<U>(v); | |
1000 | } | |
1001 | #else | |
1002 | template <class U> | |
1003 | value_type value_or ( U const& v ) const | |
1004 | { | |
1005 | if (this->is_initialized()) | |
1006 | return get(); | |
1007 | else | |
1008 | return v; | |
1009 | } | |
1010 | ||
1011 | template <class U> | |
1012 | value_type value_or ( U& v ) const | |
1013 | { | |
1014 | if (this->is_initialized()) | |
1015 | return get(); | |
1016 | else | |
1017 | return v; | |
1018 | } | |
1019 | #endif | |
1020 | ||
1021 | ||
1022 | #ifndef BOOST_NO_CXX11_REF_QUALIFIERS | |
1023 | template <typename F> | |
1024 | value_type value_or_eval ( F f ) const& | |
1025 | { | |
1026 | if (this->is_initialized()) | |
1027 | return get(); | |
1028 | else | |
1029 | return f(); | |
1030 | } | |
1031 | ||
1032 | template <typename F> | |
1033 | value_type value_or_eval ( F f ) && | |
1034 | { | |
1035 | if (this->is_initialized()) | |
1036 | return base::types::move(get()); | |
1037 | else | |
1038 | return f(); | |
1039 | } | |
1040 | #else | |
1041 | template <typename F> | |
1042 | value_type value_or_eval ( F f ) const | |
1043 | { | |
1044 | if (this->is_initialized()) | |
1045 | return get(); | |
1046 | else | |
1047 | return f(); | |
1048 | } | |
1049 | #endif | |
1050 | ||
1051 | bool operator!() const BOOST_NOEXCEPT { return !this->is_initialized() ; } | |
1052 | ||
1053 | BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT() | |
1054 | } ; | |
1055 | ||
1056 | } // namespace boost | |
1057 | ||
1058 | ||
1059 | #endif // header guard |