1 | // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. |
2 | // Copyright (C) 2014, 2015 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 author at: |
11 | // fernando_cacciola@hotmail.com |
12 | // |
13 | // Revisions: |
14 | // 27 Apr 2008 (improved swap) Fernando Cacciola, Niels Dekker, Thorsten Ottosen |
15 | // 05 May 2014 (Added move semantics) Andrzej Krzemienski |
16 | // |
17 | #ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP |
18 | #define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP |
19 | |
20 | #include <new> |
21 | #include <iosfwd> |
22 | |
23 | #include <boost/config.hpp> |
24 | #include <boost/assert.hpp> |
25 | #include <boost/core/addressof.hpp> |
26 | #include <boost/core/enable_if.hpp> |
27 | #include <boost/core/explicit_operator_bool.hpp> |
28 | #include <boost/core/swap.hpp> |
29 | #include <boost/optional/bad_optional_access.hpp> |
30 | #include <boost/static_assert.hpp> |
31 | #include <boost/throw_exception.hpp> |
32 | #include <boost/type.hpp> |
33 | #include <boost/type_traits/alignment_of.hpp> |
34 | #include <boost/type_traits/has_nothrow_constructor.hpp> |
35 | #include <boost/type_traits/type_with_alignment.hpp> |
36 | #include <boost/type_traits/remove_const.hpp> |
37 | #include <boost/type_traits/remove_reference.hpp> |
38 | #include <boost/type_traits/decay.hpp> |
39 | #include <boost/type_traits/is_base_of.hpp> |
40 | #include <boost/type_traits/is_lvalue_reference.hpp> |
41 | #include <boost/type_traits/is_nothrow_move_assignable.hpp> |
42 | #include <boost/type_traits/is_nothrow_move_constructible.hpp> |
43 | #include <boost/type_traits/is_reference.hpp> |
44 | #include <boost/type_traits/is_rvalue_reference.hpp> |
45 | #include <boost/type_traits/is_same.hpp> |
46 | #include <boost/mpl/if.hpp> |
47 | #include <boost/mpl/bool.hpp> |
48 | #include <boost/mpl/not.hpp> |
49 | #include <boost/detail/reference_content.hpp> |
50 | #include <boost/move/utility.hpp> |
51 | #include <boost/none.hpp> |
52 | #include <boost/utility/compare_pointees.hpp> |
53 | |
54 | #include <boost/optional/optional_fwd.hpp> |
55 | |
56 | #if (defined BOOST_NO_CXX11_RVALUE_REFERENCES) || (defined BOOST_OPTIONAL_CONFIG_NO_RVALUE_REFERENCES) |
57 | #define BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
58 | #endif |
59 | |
60 | #if BOOST_WORKAROUND(BOOST_INTEL_CXX_VERSION,<=700) |
61 | // AFAICT only Intel 7 correctly resolves the overload set |
62 | // that includes the in-place factory taking functions, |
63 | // so for the other icc versions, in-place factory support |
64 | // is disabled |
65 | #define BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
66 | #endif |
67 | |
68 | #if BOOST_WORKAROUND(__BORLANDC__, <= 0x551) |
69 | // BCB (5.5.1) cannot parse the nested template struct in an inplace factory. |
70 | #define BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
71 | #endif |
72 | |
73 | #if !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) \ |
74 | && BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581) ) |
75 | // BCB (up to 5.64) has the following bug: |
76 | // If there is a member function/operator template of the form |
77 | // template<class Expr> mfunc( Expr expr ) ; |
78 | // some calls are resolved to this even if there are other better matches. |
79 | // The effect of this bug is that calls to converting ctors and assignments |
80 | // are incrorrectly sink to this general catch-all member function template as shown above. |
81 | #define BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION |
82 | #endif |
83 | |
84 | #if defined(__GNUC__) && !defined(__INTEL_COMPILER) |
85 | // GCC since 3.3 has may_alias attribute that helps to alleviate optimizer issues with |
86 | // regard to violation of the strict aliasing rules. The optional< T > storage type is marked |
87 | // with this attribute in order to let the compiler know that it will alias objects of type T |
88 | // and silence compilation warnings. |
89 | #define BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS |
90 | #endif |
91 | |
92 | // Daniel Wallin discovered that bind/apply.hpp badly interacts with the apply<> |
93 | // member template of a factory as used in the optional<> implementation. |
94 | // He proposed this simple fix which is to move the call to apply<> outside |
95 | // namespace boost. |
96 | namespace boost_optional_detail |
97 | { |
98 | template <class T, class Factory> |
99 | inline void construct(Factory const& factory, void* address) |
100 | { |
101 | factory.BOOST_NESTED_TEMPLATE apply<T>(address); |
102 | } |
103 | } |
104 | |
105 | |
106 | namespace boost { |
107 | |
108 | class in_place_factory_base ; |
109 | class typed_in_place_factory_base ; |
110 | |
111 | // This forward is needed to refer to namespace scope swap from the member swap |
112 | template<class T> void swap ( optional<T>& x, optional<T>& y ); |
113 | |
114 | namespace optional_detail { |
115 | // This local class is used instead of that in "aligned_storage.hpp" |
116 | // because I've found the 'official' class to ICE BCB5.5 |
117 | // when some types are used with optional<> |
118 | // (due to sizeof() passed down as a non-type template parameter) |
119 | template <class T> |
120 | class aligned_storage |
121 | { |
122 | // Borland ICEs if unnamed unions are used for this! |
123 | union |
124 | // This works around GCC warnings about breaking strict aliasing rules when casting storage address to T* |
125 | #if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS) |
126 | __attribute__((__may_alias__)) |
127 | #endif |
128 | dummy_u |
129 | { |
130 | char data[ sizeof(T) ]; |
131 | BOOST_DEDUCED_TYPENAME type_with_alignment< |
132 | ::boost::alignment_of<T>::value >::type aligner_; |
133 | } dummy_ ; |
134 | |
135 | public: |
136 | |
137 | #if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS) |
138 | void const* address() const { return &dummy_; } |
139 | void * address() { return &dummy_; } |
140 | #else |
141 | void const* address() const { return dummy_.data; } |
142 | void * address() { return dummy_.data; } |
143 | #endif |
144 | } ; |
145 | |
146 | template<class T> |
147 | struct types_when_isnt_ref |
148 | { |
149 | typedef T const& reference_const_type ; |
150 | typedef T & reference_type ; |
151 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
152 | typedef T && rval_reference_type ; |
153 | typedef T && reference_type_of_temporary_wrapper; |
154 | #ifdef BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES |
155 | // GCC 4.4 has support for an early draft of rvalue references. The conforming version below |
156 | // causes warnings about returning references to a temporary. |
157 | static T&& move(T&& r) { return r; } |
158 | #else |
159 | static rval_reference_type move(reference_type r) { return boost::move(r); } |
160 | #endif |
161 | #endif |
162 | typedef T const* pointer_const_type ; |
163 | typedef T * pointer_type ; |
164 | typedef T const& argument_type ; |
165 | } ; |
166 | |
167 | template<class T> |
168 | struct types_when_is_ref |
169 | { |
170 | typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type raw_type ; |
171 | |
172 | typedef raw_type& reference_const_type ; |
173 | typedef raw_type& reference_type ; |
174 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
175 | typedef BOOST_DEDUCED_TYPENAME remove_const<raw_type>::type&& rval_reference_type ; |
176 | typedef raw_type& reference_type_of_temporary_wrapper; |
177 | static reference_type move(reference_type r) { return r; } |
178 | #endif |
179 | typedef raw_type* pointer_const_type ; |
180 | typedef raw_type* pointer_type ; |
181 | typedef raw_type& argument_type ; |
182 | } ; |
183 | |
184 | template <class To, class From> |
185 | void prevent_binding_rvalue_ref_to_optional_lvalue_ref() |
186 | { |
187 | #ifndef BOOST_OPTIONAL_CONFIG_ALLOW_BINDING_TO_RVALUES |
188 | BOOST_STATIC_ASSERT_MSG( |
189 | !boost::is_lvalue_reference<To>::value || !boost::is_rvalue_reference<From>::value, |
190 | "binding rvalue references to optional lvalue references is disallowed" ); |
191 | #endif |
192 | } |
193 | |
194 | struct optional_tag {} ; |
195 | |
196 | template<class T> |
197 | class optional_base : public optional_tag |
198 | { |
199 | private : |
200 | |
201 | typedef |
202 | #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) |
203 | BOOST_DEDUCED_TYPENAME |
204 | #endif |
205 | ::boost::detail::make_reference_content<T>::type internal_type ; |
206 | |
207 | typedef aligned_storage<internal_type> storage_type ; |
208 | |
209 | typedef types_when_isnt_ref<T> types_when_not_ref ; |
210 | typedef types_when_is_ref<T> types_when_ref ; |
211 | |
212 | typedef optional_base<T> this_type ; |
213 | |
214 | protected : |
215 | |
216 | typedef T value_type ; |
217 | |
218 | typedef mpl::true_ is_reference_tag ; |
219 | typedef mpl::false_ is_not_reference_tag ; |
220 | |
221 | typedef BOOST_DEDUCED_TYPENAME is_reference<T>::type is_reference_predicate ; |
222 | |
223 | public: |
224 | typedef BOOST_DEDUCED_TYPENAME mpl::if_<is_reference_predicate,types_when_ref,types_when_not_ref>::type types ; |
225 | |
226 | protected: |
227 | typedef BOOST_DEDUCED_TYPENAME types::reference_type reference_type ; |
228 | typedef BOOST_DEDUCED_TYPENAME types::reference_const_type reference_const_type ; |
229 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
230 | typedef BOOST_DEDUCED_TYPENAME types::rval_reference_type rval_reference_type ; |
231 | typedef BOOST_DEDUCED_TYPENAME types::reference_type_of_temporary_wrapper reference_type_of_temporary_wrapper ; |
232 | #endif |
233 | typedef BOOST_DEDUCED_TYPENAME types::pointer_type pointer_type ; |
234 | typedef BOOST_DEDUCED_TYPENAME types::pointer_const_type pointer_const_type ; |
235 | typedef BOOST_DEDUCED_TYPENAME types::argument_type argument_type ; |
236 | |
237 | // Creates an optional<T> uninitialized. |
238 | // No-throw |
239 | optional_base() |
240 | : |
241 | m_initialized(false) {} |
242 | |
243 | // Creates an optional<T> uninitialized. |
244 | // No-throw |
245 | optional_base ( none_t ) |
246 | : |
247 | m_initialized(false) {} |
248 | |
249 | // Creates an optional<T> initialized with 'val'. |
250 | // Can throw if T::T(T const&) does |
251 | optional_base ( argument_type val ) |
252 | : |
253 | m_initialized(false) |
254 | { |
255 | construct(val); |
256 | } |
257 | |
258 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
259 | // move-construct an optional<T> initialized from an rvalue-ref to 'val'. |
260 | // Can throw if T::T(T&&) does |
261 | optional_base ( rval_reference_type val ) |
262 | : |
263 | m_initialized(false) |
264 | { |
265 | construct( boost::move(val) ); |
266 | } |
267 | #endif |
268 | |
269 | // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional<T>. |
270 | // Can throw if T::T(T const&) does |
271 | optional_base ( bool cond, argument_type val ) |
272 | : |
273 | m_initialized(false) |
274 | { |
275 | if ( cond ) |
276 | construct(val); |
277 | } |
278 | |
279 | // Creates a deep copy of another optional<T> |
280 | // Can throw if T::T(T const&) does |
281 | optional_base ( optional_base const& rhs ) |
282 | : |
283 | m_initialized(false) |
284 | { |
285 | if ( rhs.is_initialized() ) |
286 | construct(rhs.get_impl()); |
287 | } |
288 | |
289 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
290 | // Creates a deep move of another optional<T> |
291 | // Can throw if T::T(T&&) does |
292 | optional_base ( optional_base&& rhs ) |
293 | : |
294 | m_initialized(false) |
295 | { |
296 | if ( rhs.is_initialized() ) |
297 | construct( boost::move(rhs.get_impl()) ); |
298 | } |
299 | #endif |
300 | |
301 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
302 | |
303 | template<class Expr, class PtrExpr> |
304 | explicit optional_base ( Expr&& expr, PtrExpr const* tag ) |
305 | : |
306 | m_initialized(false) |
307 | { |
308 | construct(boost::forward<Expr>(expr),tag); |
309 | } |
310 | |
311 | #else |
312 | // This is used for both converting and in-place constructions. |
313 | // Derived classes use the 'tag' to select the appropriate |
314 | // implementation (the correct 'construct()' overload) |
315 | template<class Expr> |
316 | explicit optional_base ( Expr const& expr, Expr const* tag ) |
317 | : |
318 | m_initialized(false) |
319 | { |
320 | construct(expr,tag); |
321 | } |
322 | |
323 | #endif |
324 | |
325 | |
326 | // No-throw (assuming T::~T() doesn't) |
327 | ~optional_base() { destroy() ; } |
328 | |
329 | // Assigns from another optional<T> (deep-copies the rhs value) |
330 | void assign ( optional_base const& rhs ) |
331 | { |
332 | if (is_initialized()) |
333 | { |
334 | if ( rhs.is_initialized() ) |
335 | assign_value(rhs.get_impl(), is_reference_predicate() ); |
336 | else destroy(); |
337 | } |
338 | else |
339 | { |
340 | if ( rhs.is_initialized() ) |
341 | construct(rhs.get_impl()); |
342 | } |
343 | } |
344 | |
345 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
346 | // Assigns from another optional<T> (deep-moves the rhs value) |
347 | void assign ( optional_base&& rhs ) |
348 | { |
349 | if (is_initialized()) |
350 | { |
351 | if ( rhs.is_initialized() ) |
352 | assign_value(boost::move(rhs.get_impl()), is_reference_predicate() ); |
353 | else destroy(); |
354 | } |
355 | else |
356 | { |
357 | if ( rhs.is_initialized() ) |
358 | construct(boost::move(rhs.get_impl())); |
359 | } |
360 | } |
361 | #endif |
362 | |
363 | // Assigns from another _convertible_ optional<U> (deep-copies the rhs value) |
364 | template<class U> |
365 | void assign ( optional<U> const& rhs ) |
366 | { |
367 | if (is_initialized()) |
368 | { |
369 | if ( rhs.is_initialized() ) |
370 | #ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES |
371 | assign_value(rhs.get(), is_reference_predicate() ); |
372 | #else |
373 | assign_value(static_cast<value_type>(rhs.get()), is_reference_predicate() ); |
374 | #endif |
375 | |
376 | else destroy(); |
377 | } |
378 | else |
379 | { |
380 | if ( rhs.is_initialized() ) |
381 | #ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES |
382 | construct(rhs.get()); |
383 | #else |
384 | construct(static_cast<value_type>(rhs.get())); |
385 | #endif |
386 | } |
387 | } |
388 | |
389 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
390 | // move-assigns from another _convertible_ optional<U> (deep-moves from the rhs value) |
391 | template<class U> |
392 | void assign ( optional<U>&& rhs ) |
393 | { |
394 | typedef BOOST_DEDUCED_TYPENAME optional<U>::rval_reference_type ref_type; |
395 | if (is_initialized()) |
396 | { |
397 | if ( rhs.is_initialized() ) |
398 | assign_value(static_cast<ref_type>(rhs.get()), is_reference_predicate() ); |
399 | else destroy(); |
400 | } |
401 | else |
402 | { |
403 | if ( rhs.is_initialized() ) |
404 | construct(static_cast<ref_type>(rhs.get())); |
405 | } |
406 | } |
407 | #endif |
408 | |
409 | // Assigns from a T (deep-copies the rhs value) |
410 | void assign ( argument_type val ) |
411 | { |
412 | if (is_initialized()) |
413 | assign_value(val, is_reference_predicate() ); |
414 | else construct(val); |
415 | } |
416 | |
417 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
418 | // Assigns from a T (deep-moves the rhs value) |
419 | void assign ( rval_reference_type val ) |
420 | { |
421 | if (is_initialized()) |
422 | assign_value( boost::move(val), is_reference_predicate() ); |
423 | else construct( boost::move(val) ); |
424 | } |
425 | #endif |
426 | |
427 | // Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED |
428 | // No-throw (assuming T::~T() doesn't) |
429 | void assign ( none_t ) BOOST_NOEXCEPT { destroy(); } |
430 | |
431 | #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
432 | |
433 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
434 | template<class Expr, class ExprPtr> |
435 | void assign_expr ( Expr&& expr, ExprPtr const* tag ) |
436 | { |
437 | if (is_initialized()) |
438 | assign_expr_to_initialized(boost::forward<Expr>(expr),tag); |
439 | else construct(boost::forward<Expr>(expr),tag); |
440 | } |
441 | #else |
442 | template<class Expr> |
443 | void assign_expr ( Expr const& expr, Expr const* tag ) |
444 | { |
445 | if (is_initialized()) |
446 | assign_expr_to_initialized(expr,tag); |
447 | else construct(expr,tag); |
448 | } |
449 | #endif |
450 | |
451 | #endif |
452 | |
453 | public : |
454 | |
455 | // **DEPPRECATED** Destroys the current value, if any, leaving this UNINITIALIZED |
456 | // No-throw (assuming T::~T() doesn't) |
457 | void reset() BOOST_NOEXCEPT { destroy(); } |
458 | |
459 | // **DEPPRECATED** Replaces the current value -if any- with 'val' |
460 | void reset ( argument_type val ) { assign(val); } |
461 | |
462 | // Returns a pointer to the value if this is initialized, otherwise, |
463 | // returns NULL. |
464 | // No-throw |
465 | pointer_const_type get_ptr() const { return m_initialized ? get_ptr_impl() : 0 ; } |
466 | pointer_type get_ptr() { return m_initialized ? get_ptr_impl() : 0 ; } |
467 | |
468 | bool is_initialized() const { return m_initialized ; } |
469 | |
470 | protected : |
471 | |
472 | void construct ( argument_type val ) |
473 | { |
474 | ::new (m_storage.address()) internal_type(val) ; |
475 | m_initialized = true ; |
476 | } |
477 | |
478 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
479 | void construct ( rval_reference_type val ) |
480 | { |
481 | ::new (m_storage.address()) internal_type( types::move(val) ) ; |
482 | m_initialized = true ; |
483 | } |
484 | #endif |
485 | |
486 | |
487 | #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
488 | // Constructs in-place |
489 | // upon exception *this is always uninitialized |
490 | template<class... Args> |
491 | void emplace_assign ( Args&&... args ) |
492 | { |
493 | destroy(); |
494 | ::new (m_storage.address()) internal_type( boost::forward<Args>(args)... ); |
495 | m_initialized = true ; |
496 | } |
497 | #elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) |
498 | template<class Arg> |
499 | void emplace_assign ( Arg&& arg ) |
500 | { |
501 | destroy(); |
502 | ::new (m_storage.address()) internal_type( boost::forward<Arg>(arg) ); |
503 | m_initialized = true ; |
504 | } |
505 | |
506 | void emplace_assign () |
507 | { |
508 | destroy(); |
509 | ::new (m_storage.address()) internal_type(); |
510 | m_initialized = true ; |
511 | } |
512 | #else |
513 | template<class Arg> |
514 | void emplace_assign ( const Arg& arg ) |
515 | { |
516 | destroy(); |
517 | ::new (m_storage.address()) internal_type( arg ); |
518 | m_initialized = true ; |
519 | } |
520 | |
521 | template<class Arg> |
522 | void emplace_assign ( Arg& arg ) |
523 | { |
524 | destroy(); |
525 | ::new (m_storage.address()) internal_type( arg ); |
526 | m_initialized = true ; |
527 | } |
528 | |
529 | void emplace_assign () |
530 | { |
531 | destroy(); |
532 | ::new (m_storage.address()) internal_type(); |
533 | m_initialized = true ; |
534 | } |
535 | #endif |
536 | |
537 | #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
538 | |
539 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
540 | // Constructs in-place using the given factory |
541 | template<class Expr> |
542 | void construct ( Expr&& factory, in_place_factory_base const* ) |
543 | { |
544 | BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ; |
545 | boost_optional_detail::construct<value_type>(factory, m_storage.address()); |
546 | m_initialized = true ; |
547 | } |
548 | |
549 | // Constructs in-place using the given typed factory |
550 | template<class Expr> |
551 | void construct ( Expr&& factory, typed_in_place_factory_base const* ) |
552 | { |
553 | BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ; |
554 | factory.apply(m_storage.address()) ; |
555 | m_initialized = true ; |
556 | } |
557 | |
558 | template<class Expr> |
559 | void assign_expr_to_initialized ( Expr&& factory, in_place_factory_base const* tag ) |
560 | { |
561 | destroy(); |
562 | construct(factory,tag); |
563 | } |
564 | |
565 | // Constructs in-place using the given typed factory |
566 | template<class Expr> |
567 | void assign_expr_to_initialized ( Expr&& factory, typed_in_place_factory_base const* tag ) |
568 | { |
569 | destroy(); |
570 | construct(factory,tag); |
571 | } |
572 | |
573 | #else |
574 | // Constructs in-place using the given factory |
575 | template<class Expr> |
576 | void construct ( Expr const& factory, in_place_factory_base const* ) |
577 | { |
578 | BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ; |
579 | boost_optional_detail::construct<value_type>(factory, m_storage.address()); |
580 | m_initialized = true ; |
581 | } |
582 | |
583 | // Constructs in-place using the given typed factory |
584 | template<class Expr> |
585 | void construct ( Expr const& factory, typed_in_place_factory_base const* ) |
586 | { |
587 | BOOST_STATIC_ASSERT ( ::boost::mpl::not_<is_reference_predicate>::value ) ; |
588 | factory.apply(m_storage.address()) ; |
589 | m_initialized = true ; |
590 | } |
591 | |
592 | template<class Expr> |
593 | void assign_expr_to_initialized ( Expr const& factory, in_place_factory_base const* tag ) |
594 | { |
595 | destroy(); |
596 | construct(factory,tag); |
597 | } |
598 | |
599 | // Constructs in-place using the given typed factory |
600 | template<class Expr> |
601 | void assign_expr_to_initialized ( Expr const& factory, typed_in_place_factory_base const* tag ) |
602 | { |
603 | destroy(); |
604 | construct(factory,tag); |
605 | } |
606 | #endif |
607 | |
608 | #endif |
609 | |
610 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
611 | // Constructs using any expression implicitly convertible to the single argument |
612 | // of a one-argument T constructor. |
613 | // Converting constructions of optional<T> from optional<U> uses this function with |
614 | // 'Expr' being of type 'U' and relying on a converting constructor of T from U. |
615 | template<class Expr> |
616 | void construct ( Expr&& expr, void const* ) |
617 | { |
618 | new (m_storage.address()) internal_type(boost::forward<Expr>(expr)) ; |
619 | m_initialized = true ; |
620 | } |
621 | |
622 | // Assigns using a form any expression implicitly convertible to the single argument |
623 | // of a T's assignment operator. |
624 | // Converting assignments of optional<T> from optional<U> uses this function with |
625 | // 'Expr' being of type 'U' and relying on a converting assignment of T from U. |
626 | template<class Expr> |
627 | void assign_expr_to_initialized ( Expr&& expr, void const* ) |
628 | { |
629 | assign_value(boost::forward<Expr>(expr), is_reference_predicate()); |
630 | } |
631 | #else |
632 | // Constructs using any expression implicitly convertible to the single argument |
633 | // of a one-argument T constructor. |
634 | // Converting constructions of optional<T> from optional<U> uses this function with |
635 | // 'Expr' being of type 'U' and relying on a converting constructor of T from U. |
636 | template<class Expr> |
637 | void construct ( Expr const& expr, void const* ) |
638 | { |
639 | new (m_storage.address()) internal_type(expr) ; |
640 | m_initialized = true ; |
641 | } |
642 | |
643 | // Assigns using a form any expression implicitly convertible to the single argument |
644 | // of a T's assignment operator. |
645 | // Converting assignments of optional<T> from optional<U> uses this function with |
646 | // 'Expr' being of type 'U' and relying on a converting assignment of T from U. |
647 | template<class Expr> |
648 | void assign_expr_to_initialized ( Expr const& expr, void const* ) |
649 | { |
650 | assign_value(expr, is_reference_predicate()); |
651 | } |
652 | |
653 | #endif |
654 | |
655 | #ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION |
656 | // BCB5.64 (and probably lower versions) workaround. |
657 | // The in-place factories are supported by means of catch-all constructors |
658 | // and assignment operators (the functions are parameterized in terms of |
659 | // an arbitrary 'Expr' type) |
660 | // This compiler incorrectly resolves the overload set and sinks optional<T> and optional<U> |
661 | // to the 'Expr'-taking functions even though explicit overloads are present for them. |
662 | // Thus, the following overload is needed to properly handle the case when the 'lhs' |
663 | // is another optional. |
664 | // |
665 | // For VC<=70 compilers this workaround dosen't work becasue the comnpiler issues and error |
666 | // instead of choosing the wrong overload |
667 | // |
668 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
669 | // Notice that 'Expr' will be optional<T> or optional<U> (but not optional_base<..>) |
670 | template<class Expr> |
671 | void construct ( Expr&& expr, optional_tag const* ) |
672 | { |
673 | if ( expr.is_initialized() ) |
674 | { |
675 | // An exception can be thrown here. |
676 | // It it happens, THIS will be left uninitialized. |
677 | new (m_storage.address()) internal_type(types::move(expr.get())) ; |
678 | m_initialized = true ; |
679 | } |
680 | } |
681 | #else |
682 | // Notice that 'Expr' will be optional<T> or optional<U> (but not optional_base<..>) |
683 | template<class Expr> |
684 | void construct ( Expr const& expr, optional_tag const* ) |
685 | { |
686 | if ( expr.is_initialized() ) |
687 | { |
688 | // An exception can be thrown here. |
689 | // It it happens, THIS will be left uninitialized. |
690 | new (m_storage.address()) internal_type(expr.get()) ; |
691 | m_initialized = true ; |
692 | } |
693 | } |
694 | #endif |
695 | #endif // defined BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION |
696 | |
697 | void assign_value ( argument_type val, is_not_reference_tag ) { get_impl() = val; } |
698 | void assign_value ( argument_type val, is_reference_tag ) { construct(val); } |
699 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
700 | void assign_value ( rval_reference_type val, is_not_reference_tag ) { get_impl() = static_cast<rval_reference_type>(val); } |
701 | void assign_value ( rval_reference_type val, is_reference_tag ) { construct( static_cast<rval_reference_type>(val) ); } |
702 | #endif |
703 | |
704 | void destroy() |
705 | { |
706 | if ( m_initialized ) |
707 | destroy_impl(is_reference_predicate()) ; |
708 | } |
709 | |
710 | reference_const_type get_impl() const { return dereference(get_object(), is_reference_predicate() ) ; } |
711 | reference_type get_impl() { return dereference(get_object(), is_reference_predicate() ) ; } |
712 | |
713 | pointer_const_type get_ptr_impl() const { return cast_ptr(get_object(), is_reference_predicate() ) ; } |
714 | pointer_type get_ptr_impl() { return cast_ptr(get_object(), is_reference_predicate() ) ; } |
715 | |
716 | private : |
717 | |
718 | // internal_type can be either T or reference_content<T> |
719 | #if defined(BOOST_OPTIONAL_DETAIL_USE_ATTRIBUTE_MAY_ALIAS) |
720 | // This workaround is supposed to silence GCC warnings about broken strict aliasing rules |
721 | internal_type const* get_object() const |
722 | { |
723 | union { void const* ap_pvoid; internal_type const* as_ptype; } caster = { m_storage.address() }; |
724 | return caster.as_ptype; |
725 | } |
726 | internal_type * get_object() |
727 | { |
728 | union { void* ap_pvoid; internal_type* as_ptype; } caster = { m_storage.address() }; |
729 | return caster.as_ptype; |
730 | } |
731 | #else |
732 | internal_type const* get_object() const { return static_cast<internal_type const*>(m_storage.address()); } |
733 | internal_type * get_object() { return static_cast<internal_type *> (m_storage.address()); } |
734 | #endif |
735 | |
736 | // reference_content<T> lacks an implicit conversion to T&, so the following is needed to obtain a proper reference. |
737 | reference_const_type dereference( internal_type const* p, is_not_reference_tag ) const { return *p ; } |
738 | reference_type dereference( internal_type* p, is_not_reference_tag ) { return *p ; } |
739 | reference_const_type dereference( internal_type const* p, is_reference_tag ) const { return p->get() ; } |
740 | reference_type dereference( internal_type* p, is_reference_tag ) { return p->get() ; } |
741 | |
742 | #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581)) |
743 | void destroy_impl ( is_not_reference_tag ) { get_ptr_impl()->internal_type::~internal_type() ; m_initialized = false ; } |
744 | #else |
745 | void destroy_impl ( is_not_reference_tag ) { get_ptr_impl()->~T() ; m_initialized = false ; } |
746 | #endif |
747 | |
748 | void destroy_impl ( is_reference_tag ) { m_initialized = false ; } |
749 | |
750 | // If T is of reference type, trying to get a pointer to the held value must result in a compile-time error. |
751 | // Decent compilers should disallow conversions from reference_content<T>* to T*, but just in case, |
752 | // the following olverloads are used to filter out the case and guarantee an error in case of T being a reference. |
753 | pointer_const_type cast_ptr( internal_type const* p, is_not_reference_tag ) const { return p ; } |
754 | pointer_type cast_ptr( internal_type * p, is_not_reference_tag ) { return p ; } |
755 | pointer_const_type cast_ptr( internal_type const* p, is_reference_tag ) const { return &p->get() ; } |
756 | pointer_type cast_ptr( internal_type * p, is_reference_tag ) { return &p->get() ; } |
757 | |
758 | bool m_initialized ; |
759 | storage_type m_storage ; |
760 | } ; |
761 | |
762 | } // namespace optional_detail |
763 | |
764 | template<class T> |
765 | class optional : public optional_detail::optional_base<T> |
766 | { |
767 | typedef optional_detail::optional_base<T> base ; |
768 | |
769 | public : |
770 | |
771 | typedef optional<T> this_type ; |
772 | |
773 | typedef BOOST_DEDUCED_TYPENAME base::value_type value_type ; |
774 | typedef BOOST_DEDUCED_TYPENAME base::reference_type reference_type ; |
775 | typedef BOOST_DEDUCED_TYPENAME base::reference_const_type reference_const_type ; |
776 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
777 | typedef BOOST_DEDUCED_TYPENAME base::rval_reference_type rval_reference_type ; |
778 | typedef BOOST_DEDUCED_TYPENAME base::reference_type_of_temporary_wrapper reference_type_of_temporary_wrapper ; |
779 | #endif |
780 | typedef BOOST_DEDUCED_TYPENAME base::pointer_type pointer_type ; |
781 | typedef BOOST_DEDUCED_TYPENAME base::pointer_const_type pointer_const_type ; |
782 | typedef BOOST_DEDUCED_TYPENAME base::argument_type argument_type ; |
783 | |
784 | // Creates an optional<T> uninitialized. |
785 | // No-throw |
786 | optional() BOOST_NOEXCEPT : base() {} |
787 | |
788 | // Creates an optional<T> uninitialized. |
789 | // No-throw |
790 | optional( none_t none_ ) BOOST_NOEXCEPT : base(none_) {} |
791 | |
792 | // Creates an optional<T> initialized with 'val'. |
793 | // Can throw if T::T(T const&) does |
794 | optional ( argument_type val ) : base(val) {} |
795 | |
796 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
797 | // Creates an optional<T> initialized with 'move(val)'. |
798 | // Can throw if T::T(T &&) does |
799 | optional ( rval_reference_type val ) : base( boost::forward<T>(val) ) |
800 | {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, rval_reference_type>();} |
801 | #endif |
802 | |
803 | // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. |
804 | // Can throw if T::T(T const&) does |
805 | optional ( bool cond, argument_type val ) : base(cond,val) {} |
806 | |
807 | // NOTE: MSVC needs templated versions first |
808 | |
809 | // Creates a deep copy of another convertible optional<U> |
810 | // Requires a valid conversion from U to T. |
811 | // Can throw if T::T(U const&) does |
812 | template<class U> |
813 | explicit optional ( optional<U> const& rhs ) |
814 | : |
815 | base() |
816 | { |
817 | if ( rhs.is_initialized() ) |
818 | this->construct(rhs.get()); |
819 | } |
820 | |
821 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
822 | // Creates a deep move of another convertible optional<U> |
823 | // Requires a valid conversion from U to T. |
824 | // Can throw if T::T(U&&) does |
825 | template<class U> |
826 | explicit optional ( optional<U> && rhs ) |
827 | : |
828 | base() |
829 | { |
830 | if ( rhs.is_initialized() ) |
831 | this->construct( boost::move(rhs.get()) ); |
832 | } |
833 | #endif |
834 | |
835 | #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
836 | // Creates an optional<T> with an expression which can be either |
837 | // (a) An instance of InPlaceFactory (i.e. in_place(a,b,...,n); |
838 | // (b) An instance of TypedInPlaceFactory ( i.e. in_place<T>(a,b,...,n); |
839 | // (c) Any expression implicitly convertible to the single type |
840 | // of a one-argument T's constructor. |
841 | // (d*) Weak compilers (BCB) might also resolved Expr as optional<T> and optional<U> |
842 | // even though explicit overloads are present for these. |
843 | // Depending on the above some T ctor is called. |
844 | // Can throw if the resolved T ctor throws. |
845 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
846 | |
847 | |
848 | template<class Expr> |
849 | explicit optional ( Expr&& expr, |
850 | BOOST_DEDUCED_TYPENAME boost::disable_if_c< |
851 | (boost::is_base_of<optional_detail::optional_tag, BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type>::value) || |
852 | boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type, none_t>::value >::type* = 0 |
853 | ) |
854 | : base(boost::forward<Expr>(expr),boost::addressof(expr)) |
855 | {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, Expr&&>();} |
856 | |
857 | #else |
858 | template<class Expr> |
859 | explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {} |
860 | #endif // !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
861 | #endif // !defined BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT |
862 | |
863 | // Creates a deep copy of another optional<T> |
864 | // Can throw if T::T(T const&) does |
865 | optional ( optional const& rhs ) : base( static_cast<base const&>(rhs) ) {} |
866 | |
867 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
868 | // Creates a deep move of another optional<T> |
869 | // Can throw if T::T(T&&) does |
870 | optional ( optional && rhs ) |
871 | BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value) |
872 | : base( boost::move(rhs) ) |
873 | {} |
874 | |
875 | #endif |
876 | // No-throw (assuming T::~T() doesn't) |
877 | ~optional() {} |
878 | |
879 | #if !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) |
880 | // Assigns from an expression. See corresponding constructor. |
881 | // Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED |
882 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
883 | |
884 | template<class Expr> |
885 | BOOST_DEDUCED_TYPENAME boost::disable_if_c< |
886 | boost::is_base_of<optional_detail::optional_tag, BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type>::value || |
887 | boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<Expr>::type, none_t>::value, |
888 | optional& |
889 | >::type |
890 | operator= ( Expr&& expr ) |
891 | { |
892 | optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, Expr&&>(); |
893 | this->assign_expr(boost::forward<Expr>(expr),boost::addressof(expr)); |
894 | return *this ; |
895 | } |
896 | |
897 | #else |
898 | template<class Expr> |
899 | optional& operator= ( Expr const& expr ) |
900 | { |
901 | this->assign_expr(expr,boost::addressof(expr)); |
902 | return *this ; |
903 | } |
904 | #endif // !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
905 | #endif // !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) |
906 | |
907 | // Copy-assigns from another convertible optional<U> (converts && deep-copies the rhs value) |
908 | // Requires a valid conversion from U to T. |
909 | // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED |
910 | template<class U> |
911 | optional& operator= ( optional<U> const& rhs ) |
912 | { |
913 | this->assign(rhs); |
914 | return *this ; |
915 | } |
916 | |
917 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
918 | // Move-assigns from another convertible optional<U> (converts && deep-moves the rhs value) |
919 | // Requires a valid conversion from U to T. |
920 | // Basic Guarantee: If T::T( U && ) throws, this is left UNINITIALIZED |
921 | template<class U> |
922 | optional& operator= ( optional<U> && rhs ) |
923 | { |
924 | this->assign(boost::move(rhs)); |
925 | return *this ; |
926 | } |
927 | #endif |
928 | |
929 | // Assigns from another optional<T> (deep-copies the rhs value) |
930 | // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED |
931 | // (NOTE: On BCB, this operator is not actually called and left is left UNMODIFIED in case of a throw) |
932 | optional& operator= ( optional const& rhs ) |
933 | { |
934 | this->assign( static_cast<base const&>(rhs) ) ; |
935 | return *this ; |
936 | } |
937 | |
938 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
939 | // Assigns from another optional<T> (deep-moves the rhs value) |
940 | optional& operator= ( optional && rhs ) |
941 | BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && ::boost::is_nothrow_move_assignable<T>::value) |
942 | { |
943 | this->assign( static_cast<base &&>(rhs) ) ; |
944 | return *this ; |
945 | } |
946 | #endif |
947 | |
948 | // Assigns from a T (deep-copies the rhs value) |
949 | // Basic Guarantee: If T::( T const& ) throws, this is left UNINITIALIZED |
950 | optional& operator= ( argument_type val ) |
951 | { |
952 | this->assign( val ) ; |
953 | return *this ; |
954 | } |
955 | |
956 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
957 | // Assigns from a T (deep-moves the rhs value) |
958 | optional& operator= ( rval_reference_type val ) |
959 | { |
960 | optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref<T, rval_reference_type>(); |
961 | this->assign( boost::move(val) ) ; |
962 | return *this ; |
963 | } |
964 | #endif |
965 | |
966 | // Assigns from a "none" |
967 | // Which destroys the current value, if any, leaving this UNINITIALIZED |
968 | // No-throw (assuming T::~T() doesn't) |
969 | optional& operator= ( none_t none_ ) BOOST_NOEXCEPT |
970 | { |
971 | this->assign( none_ ) ; |
972 | return *this ; |
973 | } |
974 | |
975 | #if (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) && (!defined BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
976 | // Constructs in-place |
977 | // upon exception *this is always uninitialized |
978 | template<class... Args> |
979 | void emplace ( Args&&... args ) |
980 | { |
981 | this->emplace_assign( boost::forward<Args>(args)... ); |
982 | } |
983 | #elif (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) |
984 | template<class Arg> |
985 | void emplace ( Arg&& arg ) |
986 | { |
987 | this->emplace_assign( boost::forward<Arg>(arg) ); |
988 | } |
989 | |
990 | void emplace () |
991 | { |
992 | this->emplace_assign(); |
993 | } |
994 | #else |
995 | template<class Arg> |
996 | void emplace ( const Arg& arg ) |
997 | { |
998 | this->emplace_assign( arg ); |
999 | } |
1000 | |
1001 | template<class Arg> |
1002 | void emplace ( Arg& arg ) |
1003 | { |
1004 | this->emplace_assign( arg ); |
1005 | } |
1006 | |
1007 | void emplace () |
1008 | { |
1009 | this->emplace_assign(); |
1010 | } |
1011 | #endif |
1012 | |
1013 | void swap( optional & arg ) |
1014 | BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && ::boost::is_nothrow_move_assignable<T>::value) |
1015 | { |
1016 | // allow for Koenig lookup |
1017 | boost::swap(*this, arg); |
1018 | } |
1019 | |
1020 | |
1021 | // Returns a reference to the value if this is initialized, otherwise, |
1022 | // the behaviour is UNDEFINED |
1023 | // No-throw |
1024 | reference_const_type get() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); } |
1025 | reference_type get() { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); } |
1026 | |
1027 | // Returns a copy of the value if this is initialized, 'v' otherwise |
1028 | reference_const_type get_value_or ( reference_const_type v ) const { return this->is_initialized() ? get() : v ; } |
1029 | reference_type get_value_or ( reference_type v ) { return this->is_initialized() ? get() : v ; } |
1030 | |
1031 | // Returns a pointer to the value if this is initialized, otherwise, |
1032 | // the behaviour is UNDEFINED |
1033 | // No-throw |
1034 | pointer_const_type operator->() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_ptr_impl() ; } |
1035 | pointer_type operator->() { BOOST_ASSERT(this->is_initialized()) ; return this->get_ptr_impl() ; } |
1036 | |
1037 | // Returns a reference to the value if this is initialized, otherwise, |
1038 | // the behaviour is UNDEFINED |
1039 | // No-throw |
1040 | #if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) |
1041 | reference_const_type operator *() const& { return this->get() ; } |
1042 | reference_type operator *() & { return this->get() ; } |
1043 | reference_type_of_temporary_wrapper operator *() && { return base::types::move(this->get()) ; } |
1044 | #else |
1045 | reference_const_type operator *() const { return this->get() ; } |
1046 | reference_type operator *() { return this->get() ; } |
1047 | #endif // !defined BOOST_NO_CXX11_REF_QUALIFIERS |
1048 | |
1049 | #if (!defined BOOST_NO_CXX11_REF_QUALIFIERS) && (!defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES) |
1050 | reference_const_type value() const& |
1051 | { |
1052 | if (this->is_initialized()) |
1053 | return this->get() ; |
1054 | else |
1055 | throw_exception(e: bad_optional_access()); |
1056 | } |
1057 | |
1058 | reference_type value() & |
1059 | { |
1060 | if (this->is_initialized()) |
1061 | return this->get() ; |
1062 | else |
1063 | throw_exception(e: bad_optional_access()); |
1064 | } |
1065 | |
1066 | reference_type_of_temporary_wrapper value() && |
1067 | { |
1068 | if (this->is_initialized()) |
1069 | return base::types::move(this->get()) ; |
1070 | else |
1071 | throw_exception(e: bad_optional_access()); |
1072 | } |
1073 | |
1074 | #else |
1075 | reference_const_type value() const |
1076 | { |
1077 | if (this->is_initialized()) |
1078 | return this->get() ; |
1079 | else |
1080 | throw_exception(bad_optional_access()); |
1081 | } |
1082 | |
1083 | reference_type value() |
1084 | { |
1085 | if (this->is_initialized()) |
1086 | return this->get() ; |
1087 | else |
1088 | throw_exception(bad_optional_access()); |
1089 | } |
1090 | #endif |
1091 | |
1092 | |
1093 | #ifndef BOOST_NO_CXX11_REF_QUALIFIERS |
1094 | template <class U> |
1095 | value_type value_or ( U&& v ) const& |
1096 | { |
1097 | if (this->is_initialized()) |
1098 | return get(); |
1099 | else |
1100 | return boost::forward<U>(v); |
1101 | } |
1102 | |
1103 | template <class U> |
1104 | value_type value_or ( U&& v ) && |
1105 | { |
1106 | if (this->is_initialized()) |
1107 | return base::types::move(get()); |
1108 | else |
1109 | return boost::forward<U>(v); |
1110 | } |
1111 | #elif !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
1112 | template <class U> |
1113 | value_type value_or ( U&& v ) const |
1114 | { |
1115 | if (this->is_initialized()) |
1116 | return get(); |
1117 | else |
1118 | return boost::forward<U>(v); |
1119 | } |
1120 | #else |
1121 | template <class U> |
1122 | value_type value_or ( U const& v ) const |
1123 | { |
1124 | if (this->is_initialized()) |
1125 | return get(); |
1126 | else |
1127 | return v; |
1128 | } |
1129 | |
1130 | template <class U> |
1131 | value_type value_or ( U& v ) const |
1132 | { |
1133 | if (this->is_initialized()) |
1134 | return get(); |
1135 | else |
1136 | return v; |
1137 | } |
1138 | #endif |
1139 | |
1140 | |
1141 | #ifndef BOOST_NO_CXX11_REF_QUALIFIERS |
1142 | template <typename F> |
1143 | value_type value_or_eval ( F f ) const& |
1144 | { |
1145 | if (this->is_initialized()) |
1146 | return get(); |
1147 | else |
1148 | return f(); |
1149 | } |
1150 | |
1151 | template <typename F> |
1152 | value_type value_or_eval ( F f ) && |
1153 | { |
1154 | if (this->is_initialized()) |
1155 | return base::types::move(get()); |
1156 | else |
1157 | return f(); |
1158 | } |
1159 | #else |
1160 | template <typename F> |
1161 | value_type value_or_eval ( F f ) const |
1162 | { |
1163 | if (this->is_initialized()) |
1164 | return get(); |
1165 | else |
1166 | return f(); |
1167 | } |
1168 | #endif |
1169 | |
1170 | bool operator!() const BOOST_NOEXCEPT { return !this->is_initialized() ; } |
1171 | |
1172 | BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT() |
1173 | } ; |
1174 | |
1175 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
1176 | template<class T> |
1177 | class optional<T&&> |
1178 | { |
1179 | BOOST_STATIC_ASSERT_MSG(sizeof(T) == 0, "Optional rvalue references are illegal." ); |
1180 | } ; |
1181 | #endif |
1182 | |
1183 | // Returns optional<T>(v) |
1184 | template<class T> |
1185 | inline |
1186 | optional<T> make_optional ( T const& v ) |
1187 | { |
1188 | return optional<T>(v); |
1189 | } |
1190 | |
1191 | // Returns optional<T>(cond,v) |
1192 | template<class T> |
1193 | inline |
1194 | optional<T> make_optional ( bool cond, T const& v ) |
1195 | { |
1196 | return optional<T>(cond,v); |
1197 | } |
1198 | |
1199 | // Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED. |
1200 | // No-throw |
1201 | template<class T> |
1202 | inline |
1203 | BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type |
1204 | get ( optional<T> const& opt ) |
1205 | { |
1206 | return opt.get() ; |
1207 | } |
1208 | |
1209 | template<class T> |
1210 | inline |
1211 | BOOST_DEDUCED_TYPENAME optional<T>::reference_type |
1212 | get ( optional<T>& opt ) |
1213 | { |
1214 | return opt.get() ; |
1215 | } |
1216 | |
1217 | // Returns a pointer to the value if this is initialized, otherwise, returns NULL. |
1218 | // No-throw |
1219 | template<class T> |
1220 | inline |
1221 | BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type |
1222 | get ( optional<T> const* opt ) |
1223 | { |
1224 | return opt->get_ptr() ; |
1225 | } |
1226 | |
1227 | template<class T> |
1228 | inline |
1229 | BOOST_DEDUCED_TYPENAME optional<T>::pointer_type |
1230 | get ( optional<T>* opt ) |
1231 | { |
1232 | return opt->get_ptr() ; |
1233 | } |
1234 | |
1235 | // Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED. |
1236 | // No-throw |
1237 | template<class T> |
1238 | inline |
1239 | BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type |
1240 | get_optional_value_or ( optional<T> const& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type v ) |
1241 | { |
1242 | return opt.get_value_or(v) ; |
1243 | } |
1244 | |
1245 | template<class T> |
1246 | inline |
1247 | BOOST_DEDUCED_TYPENAME optional<T>::reference_type |
1248 | get_optional_value_or ( optional<T>& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_type v ) |
1249 | { |
1250 | return opt.get_value_or(v) ; |
1251 | } |
1252 | |
1253 | // Returns a pointer to the value if this is initialized, otherwise, returns NULL. |
1254 | // No-throw |
1255 | template<class T> |
1256 | inline |
1257 | BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type |
1258 | get_pointer ( optional<T> const& opt ) |
1259 | { |
1260 | return opt.get_ptr() ; |
1261 | } |
1262 | |
1263 | template<class T> |
1264 | inline |
1265 | BOOST_DEDUCED_TYPENAME optional<T>::pointer_type |
1266 | get_pointer ( optional<T>& opt ) |
1267 | { |
1268 | return opt.get_ptr() ; |
1269 | } |
1270 | |
1271 | // The following declaration prevents a bug where operator safe-bool is used upon streaming optional object if you forget the IO header. |
1272 | template<class CharType, class CharTrait> |
1273 | std::basic_ostream<CharType, CharTrait>& |
1274 | operator<<(std::basic_ostream<CharType, CharTrait>& os, optional_detail::optional_tag const&) |
1275 | { |
1276 | BOOST_STATIC_ASSERT_MSG(sizeof(CharType) == 0, "If you want to output boost::optional, include header <boost/optional/optional_io.hpp>" ); |
1277 | return os; |
1278 | } |
1279 | |
1280 | // optional's relational operators ( ==, !=, <, >, <=, >= ) have deep-semantics (compare values). |
1281 | // WARNING: This is UNLIKE pointers. Use equal_pointees()/less_pointess() in generic code instead. |
1282 | |
1283 | |
1284 | // |
1285 | // optional<T> vs optional<T> cases |
1286 | // |
1287 | |
1288 | template<class T> |
1289 | inline |
1290 | bool operator == ( optional<T> const& x, optional<T> const& y ) |
1291 | { return equal_pointees(x,y); } |
1292 | |
1293 | template<class T> |
1294 | inline |
1295 | bool operator < ( optional<T> const& x, optional<T> const& y ) |
1296 | { return less_pointees(x,y); } |
1297 | |
1298 | template<class T> |
1299 | inline |
1300 | bool operator != ( optional<T> const& x, optional<T> const& y ) |
1301 | { return !( x == y ) ; } |
1302 | |
1303 | template<class T> |
1304 | inline |
1305 | bool operator > ( optional<T> const& x, optional<T> const& y ) |
1306 | { return y < x ; } |
1307 | |
1308 | template<class T> |
1309 | inline |
1310 | bool operator <= ( optional<T> const& x, optional<T> const& y ) |
1311 | { return !( y < x ) ; } |
1312 | |
1313 | template<class T> |
1314 | inline |
1315 | bool operator >= ( optional<T> const& x, optional<T> const& y ) |
1316 | { return !( x < y ) ; } |
1317 | |
1318 | |
1319 | // |
1320 | // optional<T> vs T cases |
1321 | // |
1322 | template<class T> |
1323 | inline |
1324 | bool operator == ( optional<T> const& x, T const& y ) |
1325 | { return equal_pointees(x, optional<T>(y)); } |
1326 | |
1327 | template<class T> |
1328 | inline |
1329 | bool operator < ( optional<T> const& x, T const& y ) |
1330 | { return less_pointees(x, optional<T>(y)); } |
1331 | |
1332 | template<class T> |
1333 | inline |
1334 | bool operator != ( optional<T> const& x, T const& y ) |
1335 | { return !( x == y ) ; } |
1336 | |
1337 | template<class T> |
1338 | inline |
1339 | bool operator > ( optional<T> const& x, T const& y ) |
1340 | { return y < x ; } |
1341 | |
1342 | template<class T> |
1343 | inline |
1344 | bool operator <= ( optional<T> const& x, T const& y ) |
1345 | { return !( y < x ) ; } |
1346 | |
1347 | template<class T> |
1348 | inline |
1349 | bool operator >= ( optional<T> const& x, T const& y ) |
1350 | { return !( x < y ) ; } |
1351 | |
1352 | // |
1353 | // T vs optional<T> cases |
1354 | // |
1355 | |
1356 | template<class T> |
1357 | inline |
1358 | bool operator == ( T const& x, optional<T> const& y ) |
1359 | { return equal_pointees( optional<T>(x), y ); } |
1360 | |
1361 | template<class T> |
1362 | inline |
1363 | bool operator < ( T const& x, optional<T> const& y ) |
1364 | { return less_pointees( optional<T>(x), y ); } |
1365 | |
1366 | template<class T> |
1367 | inline |
1368 | bool operator != ( T const& x, optional<T> const& y ) |
1369 | { return !( x == y ) ; } |
1370 | |
1371 | template<class T> |
1372 | inline |
1373 | bool operator > ( T const& x, optional<T> const& y ) |
1374 | { return y < x ; } |
1375 | |
1376 | template<class T> |
1377 | inline |
1378 | bool operator <= ( T const& x, optional<T> const& y ) |
1379 | { return !( y < x ) ; } |
1380 | |
1381 | template<class T> |
1382 | inline |
1383 | bool operator >= ( T const& x, optional<T> const& y ) |
1384 | { return !( x < y ) ; } |
1385 | |
1386 | |
1387 | // |
1388 | // optional<T> vs none cases |
1389 | // |
1390 | |
1391 | template<class T> |
1392 | inline |
1393 | bool operator == ( optional<T> const& x, none_t ) BOOST_NOEXCEPT |
1394 | { return !x; } |
1395 | |
1396 | template<class T> |
1397 | inline |
1398 | bool operator < ( optional<T> const& x, none_t ) |
1399 | { return less_pointees(x,optional<T>() ); } |
1400 | |
1401 | template<class T> |
1402 | inline |
1403 | bool operator != ( optional<T> const& x, none_t ) BOOST_NOEXCEPT |
1404 | { return bool(x); } |
1405 | |
1406 | template<class T> |
1407 | inline |
1408 | bool operator > ( optional<T> const& x, none_t y ) |
1409 | { return y < x ; } |
1410 | |
1411 | template<class T> |
1412 | inline |
1413 | bool operator <= ( optional<T> const& x, none_t y ) |
1414 | { return !( y < x ) ; } |
1415 | |
1416 | template<class T> |
1417 | inline |
1418 | bool operator >= ( optional<T> const& x, none_t y ) |
1419 | { return !( x < y ) ; } |
1420 | |
1421 | // |
1422 | // none vs optional<T> cases |
1423 | // |
1424 | |
1425 | template<class T> |
1426 | inline |
1427 | bool operator == ( none_t , optional<T> const& y ) BOOST_NOEXCEPT |
1428 | { return !y; } |
1429 | |
1430 | template<class T> |
1431 | inline |
1432 | bool operator < ( none_t , optional<T> const& y ) |
1433 | { return less_pointees(optional<T>() ,y); } |
1434 | |
1435 | template<class T> |
1436 | inline |
1437 | bool operator != ( none_t, optional<T> const& y ) BOOST_NOEXCEPT |
1438 | { return bool(y); } |
1439 | |
1440 | template<class T> |
1441 | inline |
1442 | bool operator > ( none_t x, optional<T> const& y ) |
1443 | { return y < x ; } |
1444 | |
1445 | template<class T> |
1446 | inline |
1447 | bool operator <= ( none_t x, optional<T> const& y ) |
1448 | { return !( y < x ) ; } |
1449 | |
1450 | template<class T> |
1451 | inline |
1452 | bool operator >= ( none_t x, optional<T> const& y ) |
1453 | { return !( x < y ) ; } |
1454 | |
1455 | namespace optional_detail { |
1456 | |
1457 | template<bool use_default_constructor> struct swap_selector; |
1458 | |
1459 | template<> |
1460 | struct swap_selector<true> |
1461 | { |
1462 | template<class T> |
1463 | static void optional_swap ( optional<T>& x, optional<T>& y ) |
1464 | { |
1465 | const bool hasX = !!x; |
1466 | const bool hasY = !!y; |
1467 | |
1468 | if ( !hasX && !hasY ) |
1469 | return; |
1470 | |
1471 | if( !hasX ) |
1472 | x.emplace(); |
1473 | else if ( !hasY ) |
1474 | y.emplace(); |
1475 | |
1476 | // Boost.Utility.Swap will take care of ADL and workarounds for broken compilers |
1477 | boost::swap(x.get(),y.get()); |
1478 | |
1479 | if( !hasX ) |
1480 | y = boost::none ; |
1481 | else if( !hasY ) |
1482 | x = boost::none ; |
1483 | } |
1484 | }; |
1485 | |
1486 | #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
1487 | template<> |
1488 | struct swap_selector<false> |
1489 | { |
1490 | template<class T> |
1491 | static void optional_swap ( optional<T>& x, optional<T>& y ) |
1492 | //BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && BOOST_NOEXCEPT_EXPR(boost::swap(*x, *y))) |
1493 | { |
1494 | if(x) |
1495 | { |
1496 | if (y) |
1497 | { |
1498 | boost::swap(*x, *y); |
1499 | } |
1500 | else |
1501 | { |
1502 | y = boost::move(*x); |
1503 | x = boost::none; |
1504 | } |
1505 | } |
1506 | else |
1507 | { |
1508 | if (y) |
1509 | { |
1510 | x = boost::move(*y); |
1511 | y = boost::none; |
1512 | } |
1513 | } |
1514 | } |
1515 | }; |
1516 | #else |
1517 | template<> |
1518 | struct swap_selector<false> |
1519 | { |
1520 | template<class T> |
1521 | static void optional_swap ( optional<T>& x, optional<T>& y ) |
1522 | { |
1523 | const bool hasX = !!x; |
1524 | const bool hasY = !!y; |
1525 | |
1526 | if ( !hasX && hasY ) |
1527 | { |
1528 | x = y.get(); |
1529 | y = boost::none ; |
1530 | } |
1531 | else if ( hasX && !hasY ) |
1532 | { |
1533 | y = x.get(); |
1534 | x = boost::none ; |
1535 | } |
1536 | else if ( hasX && hasY ) |
1537 | { |
1538 | // Boost.Utility.Swap will take care of ADL and workarounds for broken compilers |
1539 | boost::swap(x.get(),y.get()); |
1540 | } |
1541 | } |
1542 | }; |
1543 | #endif // !defined BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES |
1544 | |
1545 | } // namespace optional_detail |
1546 | |
1547 | #if (!defined BOOST_NO_CXX11_RVALUE_REFERENCES) && (!defined BOOST_CONFIG_RESTORE_OBSOLETE_SWAP_IMPLEMENTATION) |
1548 | |
1549 | template<class T> |
1550 | struct optional_swap_should_use_default_constructor : boost::false_type {} ; |
1551 | |
1552 | #else |
1553 | |
1554 | template<class T> |
1555 | struct optional_swap_should_use_default_constructor : has_nothrow_default_constructor<T> {} ; |
1556 | |
1557 | #endif //BOOST_NO_CXX11_RVALUE_REFERENCES |
1558 | |
1559 | template<class T> inline void swap ( optional<T>& x, optional<T>& y ) |
1560 | //BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && BOOST_NOEXCEPT_EXPR(boost::swap(*x, *y))) |
1561 | { |
1562 | optional_detail::swap_selector<optional_swap_should_use_default_constructor<T>::value>::optional_swap(x, y); |
1563 | } |
1564 | |
1565 | } // namespace boost |
1566 | |
1567 | #endif |
1568 | |