Line data Source code
1 : // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal.
2 : // Copyright (C) 2014 - 2021 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 : #ifndef BOOST_NO_IOSTREAM
22 : #include <iosfwd>
23 : #endif // BOOST_NO_IOSTREAM
24 :
25 : #include <boost/assert.hpp>
26 : #include <boost/core/addressof.hpp>
27 : #include <boost/core/enable_if.hpp>
28 : #include <boost/core/invoke_swap.hpp>
29 : #include <boost/core/launder.hpp>
30 : #include <boost/optional/bad_optional_access.hpp>
31 : #include <boost/throw_exception.hpp>
32 : #include <boost/type_traits/alignment_of.hpp>
33 : #include <boost/type_traits/conditional.hpp>
34 : #include <boost/type_traits/conjunction.hpp>
35 : #include <boost/type_traits/disjunction.hpp>
36 : #include <boost/type_traits/has_nothrow_constructor.hpp>
37 : #include <boost/type_traits/type_with_alignment.hpp>
38 : #include <boost/type_traits/remove_const.hpp>
39 : #include <boost/type_traits/remove_reference.hpp>
40 : #include <boost/type_traits/decay.hpp>
41 : #include <boost/type_traits/is_assignable.hpp>
42 : #include <boost/type_traits/is_base_of.hpp>
43 : #include <boost/type_traits/is_const.hpp>
44 : #include <boost/type_traits/is_constructible.hpp>
45 : #include <boost/type_traits/is_convertible.hpp>
46 : #include <boost/type_traits/is_lvalue_reference.hpp>
47 : #include <boost/type_traits/is_nothrow_move_assignable.hpp>
48 : #include <boost/type_traits/is_nothrow_move_constructible.hpp>
49 : #include <boost/type_traits/is_rvalue_reference.hpp>
50 : #include <boost/type_traits/is_same.hpp>
51 : #include <boost/type_traits/is_volatile.hpp>
52 : #include <boost/type_traits/is_scalar.hpp>
53 : #include <boost/none.hpp>
54 :
55 : #include <boost/optional/optional_fwd.hpp>
56 : #include <boost/optional/detail/optional_config.hpp>
57 : #include <boost/optional/detail/optional_factory_support.hpp>
58 : #include <boost/optional/detail/optional_aligned_storage.hpp>
59 : #include <boost/optional/detail/optional_hash.hpp>
60 : #include <boost/optional/detail/optional_utility.hpp>
61 :
62 : namespace boost { namespace optional_detail {
63 :
64 : template <typename T>
65 : struct optional_value_type
66 : {
67 : };
68 :
69 : template <typename U>
70 : struct optional_value_type< ::boost::optional<U> >
71 : {
72 : typedef U type;
73 : };
74 :
75 : template <typename T>
76 : T declval();
77 :
78 :
79 : // implementing my own result_of so that it works for C++11 (std::result_of)
80 : // and in C++20 (std::invoke_result).
81 : template <typename F, typename Ref, typename Rslt = decltype(declval<F>()(declval<Ref>()))>
82 : struct result_of
83 : {
84 : typedef Rslt type;
85 : };
86 :
87 : template <typename F, typename Ref, typename Rslt = typename optional_value_type<typename result_of<F, Ref>::type>::type>
88 : struct result_value_type
89 : {
90 : typedef Rslt type;
91 : };
92 :
93 : // optional<typename optional_detail::optional_value_type<decltype(optional_detail::declval<F>()(optional_detail::declval<reference_type>()))>::type>
94 :
95 : }} // namespace boost::optional_detail
96 :
97 : namespace boost {
98 :
99 : namespace optional_ns {
100 :
101 : // a tag for in-place initialization of contained value
102 : struct in_place_init_t
103 : {
104 : struct init_tag{};
105 : BOOST_CONSTEXPR explicit in_place_init_t(init_tag){}
106 : };
107 : BOOST_INLINE_CONSTEXPR in_place_init_t in_place_init ((in_place_init_t::init_tag()));
108 :
109 : // a tag for conditional in-place initialization of contained value
110 : struct in_place_init_if_t
111 : {
112 : struct init_tag{};
113 : BOOST_CONSTEXPR explicit in_place_init_if_t(init_tag){}
114 : };
115 : BOOST_INLINE_CONSTEXPR in_place_init_if_t in_place_init_if ((in_place_init_if_t::init_tag()));
116 :
117 : } // namespace optional_ns
118 :
119 : using optional_ns::in_place_init_t;
120 : using optional_ns::in_place_init;
121 : using optional_ns::in_place_init_if_t;
122 : using optional_ns::in_place_init_if;
123 :
124 : namespace optional_detail {
125 :
126 : struct init_value_tag {};
127 :
128 : struct optional_tag {};
129 :
130 :
131 : template<class T>
132 : class optional_base : public optional_tag
133 : {
134 : private :
135 :
136 : typedef aligned_storage<T> storage_type ;
137 : typedef optional_base<T> this_type ;
138 :
139 : protected :
140 :
141 : typedef T value_type ;
142 : typedef typename boost::remove_const<T>::type unqualified_value_type;
143 :
144 : protected:
145 : typedef T & reference_type ;
146 : typedef T const& reference_const_type ;
147 : typedef T && rval_reference_type ;
148 : typedef T && reference_type_of_temporary_wrapper ;
149 : typedef T * pointer_type ;
150 : typedef T const* pointer_const_type ;
151 : typedef T const& argument_type ;
152 :
153 : // Creates an optional<T> uninitialized.
154 : // No-throw
155 164656 : optional_base()
156 : :
157 164656 : m_initialized(false) {}
158 :
159 : // Creates an optional<T> uninitialized.
160 : // No-throw
161 : optional_base ( none_t )
162 : :
163 : m_initialized(false) {}
164 :
165 : // Creates an optional<T> initialized with 'val'.
166 : // Can throw if T::T(T const&) does
167 : optional_base ( init_value_tag, argument_type val )
168 : :
169 : m_initialized(false)
170 : {
171 : construct(val);
172 : }
173 :
174 : // move-construct an optional<T> initialized from an rvalue-ref to 'val'.
175 : // Can throw if T::T(T&&) does
176 : optional_base ( init_value_tag, rval_reference_type val )
177 : :
178 : m_initialized(false)
179 : {
180 : construct( optional_detail::move(val) );
181 : }
182 :
183 : // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional<T>.
184 : // Can throw if T::T(T const&) does
185 : optional_base ( bool cond, argument_type val )
186 : :
187 : m_initialized(false)
188 : {
189 : if ( cond )
190 : construct(val);
191 : }
192 :
193 : // Creates an optional<T> initialized with 'move(val)' IFF cond is true, otherwise creates an uninitialized optional<T>.
194 : // Can throw if T::T(T &&) does
195 : optional_base ( bool cond, rval_reference_type val )
196 : :
197 : m_initialized(false)
198 : {
199 : if ( cond )
200 : construct(optional_detail::move(val));
201 : }
202 :
203 : // Creates a deep copy of another optional<T>
204 : // Can throw if T::T(T const&) does
205 : optional_base ( optional_base const& rhs )
206 : :
207 : m_initialized(false)
208 : {
209 : if ( rhs.is_initialized() )
210 : construct(rhs.get_impl());
211 : }
212 :
213 : // Creates a deep move of another optional<T>
214 : // Can throw if T::T(T&&) does
215 : optional_base ( optional_base&& rhs )
216 : BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value)
217 : :
218 : m_initialized(false)
219 : {
220 : if ( rhs.is_initialized() )
221 : construct( optional_detail::move(rhs.get_impl()) );
222 : }
223 :
224 :
225 : template<class Expr, class PtrExpr>
226 : explicit optional_base ( Expr&& expr, PtrExpr const* tag )
227 : :
228 : m_initialized(false)
229 : {
230 : construct(optional_detail::forward<Expr>(expr),tag);
231 : }
232 :
233 : optional_base& operator= ( optional_base const& rhs )
234 : {
235 : this->assign(rhs);
236 : return *this;
237 : }
238 :
239 : optional_base& operator= ( optional_base && rhs )
240 : BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && ::boost::is_nothrow_move_assignable<T>::value)
241 : {
242 : this->assign(static_cast<optional_base&&>(rhs));
243 : return *this;
244 : }
245 :
246 : // No-throw (assuming T::~T() doesn't)
247 82328 : ~optional_base() { destroy() ; }
248 :
249 : // Assigns from another optional<T> (deep-copies the rhs value)
250 : void assign ( optional_base const& rhs )
251 : {
252 : if (is_initialized())
253 : {
254 : if ( rhs.is_initialized() )
255 : assign_value(rhs.get_impl());
256 : else destroy();
257 : }
258 : else
259 : {
260 : if ( rhs.is_initialized() )
261 : construct(rhs.get_impl());
262 : }
263 : }
264 :
265 : // Assigns from another optional<T> (deep-moves the rhs value)
266 : void assign ( optional_base&& rhs )
267 : {
268 : if (is_initialized())
269 : {
270 : if ( rhs.is_initialized() )
271 : assign_value( optional_detail::move(rhs.get_impl()) );
272 : else destroy();
273 : }
274 : else
275 : {
276 : if ( rhs.is_initialized() )
277 : construct(optional_detail::move(rhs.get_impl()));
278 : }
279 : }
280 :
281 : // Assigns from another _convertible_ optional<U> (deep-copies the rhs value)
282 : template<class U>
283 : void assign ( optional<U> const& rhs )
284 : {
285 : if (is_initialized())
286 : {
287 : if ( rhs.is_initialized() )
288 : #ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES
289 : assign_value( rhs.get() );
290 : #else
291 : assign_value( static_cast<value_type>(rhs.get()) );
292 : #endif
293 :
294 : else destroy();
295 : }
296 : else
297 : {
298 : if ( rhs.is_initialized() )
299 : #ifndef BOOST_OPTIONAL_CONFIG_RESTORE_ASSIGNMENT_OF_NONCONVERTIBLE_TYPES
300 : construct(rhs.get());
301 : #else
302 : construct(static_cast<value_type>(rhs.get()));
303 : #endif
304 : }
305 : }
306 :
307 : // move-assigns from another _convertible_ optional<U> (deep-moves from the rhs value)
308 : template<class U>
309 : void assign ( optional<U>&& rhs )
310 : {
311 : typedef BOOST_DEDUCED_TYPENAME optional<U>::rval_reference_type ref_type;
312 : if (is_initialized())
313 : {
314 : if ( rhs.is_initialized() )
315 : assign_value( static_cast<ref_type>(rhs.get()) );
316 : else destroy();
317 : }
318 : else
319 : {
320 : if ( rhs.is_initialized() )
321 : construct(static_cast<ref_type>(rhs.get()));
322 : }
323 : }
324 :
325 : // Assigns from a T (deep-copies the rhs value)
326 : void assign ( argument_type val )
327 : {
328 : if (is_initialized())
329 : assign_value(val);
330 : else construct(val);
331 : }
332 :
333 : // Assigns from a T (deep-moves the rhs value)
334 231 : void assign ( rval_reference_type val )
335 : {
336 231 : if (is_initialized())
337 0 : assign_value( optional_detail::move(val) );
338 231 : else construct( optional_detail::move(val) );
339 231 : }
340 :
341 : // Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED
342 : // No-throw (assuming T::~T() doesn't)
343 : void assign ( none_t ) BOOST_NOEXCEPT { destroy(); }
344 :
345 : #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
346 :
347 : template<class Expr, class ExprPtr>
348 : void assign_expr ( Expr&& expr, ExprPtr const* tag )
349 : {
350 : if (is_initialized())
351 : assign_expr_to_initialized(optional_detail::forward<Expr>(expr),tag);
352 : else construct(optional_detail::forward<Expr>(expr),tag);
353 : }
354 :
355 : #endif
356 :
357 : public :
358 :
359 : // Destroys the current value, if any, leaving this UNINITIALIZED
360 : // No-throw (assuming T::~T() doesn't)
361 231 : void reset() BOOST_NOEXCEPT { destroy(); }
362 :
363 : // **DEPRECATED** Replaces the current value -if any- with 'val'
364 : void reset ( argument_type val ) { assign(val); }
365 :
366 : // Returns a pointer to the value if this is initialized, otherwise,
367 : // returns NULL.
368 : // No-throw
369 : pointer_const_type get_ptr() const { return m_initialized ? get_ptr_impl() : 0 ; }
370 : pointer_type get_ptr() { return m_initialized ? get_ptr_impl() : 0 ; }
371 :
372 693 : bool is_initialized() const BOOST_NOEXCEPT { return m_initialized ; }
373 :
374 : protected :
375 :
376 : void construct ( argument_type val )
377 : {
378 : ::new (m_storage.address()) unqualified_value_type(val) ;
379 : m_initialized = true ;
380 : }
381 :
382 231 : void construct ( rval_reference_type val )
383 : {
384 231 : ::new (m_storage.address()) unqualified_value_type( optional_detail::move(val) ) ;
385 231 : m_initialized = true ;
386 231 : }
387 :
388 :
389 : // Constructs in-place
390 : // upon exception *this is always uninitialized
391 : template<class... Args>
392 : void construct ( in_place_init_t, Args&&... args )
393 : {
394 : ::new (m_storage.address()) unqualified_value_type( optional_detail::forward<Args>(args)... ) ;
395 : m_initialized = true ;
396 : }
397 :
398 : template<class... Args>
399 : void emplace_assign ( Args&&... args )
400 : {
401 : destroy();
402 : construct(in_place_init, optional_detail::forward<Args>(args)...);
403 : }
404 :
405 : template<class... Args>
406 : explicit optional_base ( in_place_init_t, Args&&... args )
407 : :
408 : m_initialized(false)
409 : {
410 : construct(in_place_init, optional_detail::forward<Args>(args)...);
411 : }
412 :
413 : template<class... Args>
414 : explicit optional_base ( in_place_init_if_t, bool cond, Args&&... args )
415 : :
416 : m_initialized(false)
417 : {
418 : if ( cond )
419 : construct(in_place_init, optional_detail::forward<Args>(args)...);
420 : }
421 :
422 : #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
423 :
424 : // Constructs in-place using the given factory
425 : template<class Expr>
426 : void construct ( Expr&& factory, in_place_factory_base const* )
427 : {
428 : boost_optional_detail::construct<value_type>(factory, m_storage.address());
429 : m_initialized = true ;
430 : }
431 :
432 : // Constructs in-place using the given typed factory
433 : template<class Expr>
434 : void construct ( Expr&& factory, typed_in_place_factory_base const* )
435 : {
436 : factory.apply(m_storage.address()) ;
437 : m_initialized = true ;
438 : }
439 :
440 : template<class Expr>
441 : void assign_expr_to_initialized ( Expr&& factory, in_place_factory_base const* tag )
442 : {
443 : destroy();
444 : construct(factory,tag);
445 : }
446 :
447 : // Constructs in-place using the given typed factory
448 : template<class Expr>
449 : void assign_expr_to_initialized ( Expr&& factory, typed_in_place_factory_base const* tag )
450 : {
451 : destroy();
452 : construct(factory,tag);
453 : }
454 :
455 : #endif
456 :
457 : // Constructs using any expression implicitly convertible to the single argument
458 : // of a one-argument T constructor.
459 : // Converting constructions of optional<T> from optional<U> uses this function with
460 : // 'Expr' being of type 'U' and relying on a converting constructor of T from U.
461 : template<class Expr>
462 : void construct ( Expr&& expr, void const* )
463 : {
464 : new (m_storage.address()) unqualified_value_type(optional_detail::forward<Expr>(expr)) ;
465 : m_initialized = true ;
466 : }
467 :
468 : // Assigns using a form any expression implicitly convertible to the single argument
469 : // of a T's assignment operator.
470 : // Converting assignments of optional<T> from optional<U> uses this function with
471 : // 'Expr' being of type 'U' and relying on a converting assignment of T from U.
472 : template<class Expr>
473 : void assign_expr_to_initialized ( Expr&& expr, void const* )
474 : {
475 : assign_value( optional_detail::forward<Expr>(expr) );
476 : }
477 :
478 : #ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
479 : // BCB5.64 (and probably lower versions) workaround.
480 : // The in-place factories are supported by means of catch-all constructors
481 : // and assignment operators (the functions are parameterized in terms of
482 : // an arbitrary 'Expr' type)
483 : // This compiler incorrectly resolves the overload set and sinks optional<T> and optional<U>
484 : // to the 'Expr'-taking functions even though explicit overloads are present for them.
485 : // Thus, the following overload is needed to properly handle the case when the 'lhs'
486 : // is another optional.
487 : //
488 : // For VC<=70 compilers this workaround doesn't work because the compiler issues and error
489 : // instead of choosing the wrong overload
490 : //
491 :
492 : // Notice that 'Expr' will be optional<T> or optional<U> (but not optional_base<..>)
493 : template<class Expr>
494 : void construct ( Expr&& expr, optional_tag const* )
495 : {
496 : if ( expr.is_initialized() )
497 : {
498 : // An exception can be thrown here.
499 : // It it happens, THIS will be left uninitialized.
500 : new (m_storage.address()) unqualified_value_type(optional_detail::move(expr.get())) ;
501 : m_initialized = true ;
502 : }
503 : }
504 : #endif // defined BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION
505 :
506 : void assign_value ( argument_type val ) { get_impl() = val; }
507 0 : void assign_value ( rval_reference_type val ) { get_impl() = static_cast<rval_reference_type>(val); }
508 :
509 82559 : void destroy()
510 : {
511 82559 : if ( m_initialized )
512 231 : destroy_impl() ;
513 82559 : }
514 :
515 : reference_const_type get_impl() const { return m_storage.ref() ; }
516 231 : reference_type get_impl() { return m_storage.ref() ; }
517 :
518 : pointer_const_type get_ptr_impl() const { return m_storage.ptr_ref(); }
519 : pointer_type get_ptr_impl() { return m_storage.ptr_ref(); }
520 :
521 : private :
522 :
523 : #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1900))
524 : void destroy_impl ( ) { m_storage.ptr_ref()->~T() ; m_initialized = false ; }
525 : #else
526 231 : void destroy_impl ( ) { m_storage.ref().T::~T() ; m_initialized = false ; }
527 : #endif
528 :
529 : bool m_initialized ;
530 : storage_type m_storage ;
531 : } ;
532 :
533 : #include <boost/optional/detail/optional_trivially_copyable_base.hpp>
534 :
535 : // definition of metafunction is_optional_val_init_candidate
536 : template <typename U>
537 : struct is_optional_or_tag
538 : : boost::conditional< boost::is_base_of<optional_detail::optional_tag, BOOST_DEDUCED_TYPENAME boost::decay<U>::type>::value
539 : || boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<U>::type, none_t>::value
540 : || boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<U>::type, in_place_init_t>::value
541 : || boost::is_same<BOOST_DEDUCED_TYPENAME boost::decay<U>::type, in_place_init_if_t>::value,
542 : boost::true_type, boost::false_type>::type
543 : {};
544 :
545 : template <typename T, typename U>
546 : struct has_dedicated_constructor
547 : : boost::disjunction<is_optional_or_tag<U>, boost::is_same<T, BOOST_DEDUCED_TYPENAME boost::decay<U>::type> >
548 : {};
549 :
550 : template <typename U>
551 : struct is_in_place_factory
552 : : boost::disjunction< boost::is_base_of<boost::in_place_factory_base, BOOST_DEDUCED_TYPENAME boost::decay<U>::type>,
553 : boost::is_base_of<boost::typed_in_place_factory_base, BOOST_DEDUCED_TYPENAME boost::decay<U>::type> >
554 : {};
555 :
556 : #if !defined(BOOST_OPTIONAL_DETAIL_NO_IS_CONSTRUCTIBLE_TRAIT)
557 :
558 : template <typename T, typename U>
559 : struct is_factory_or_constructible_to_T
560 : : boost::disjunction< is_in_place_factory<U>, boost::is_constructible<T, U&&> >
561 : {};
562 :
563 : template <typename T, typename U>
564 : struct is_optional_constructible : boost::is_constructible<T, U>
565 : {};
566 :
567 : #else
568 :
569 : template <typename, typename>
570 : struct is_factory_or_constructible_to_T : boost::true_type
571 : {};
572 :
573 : template <typename T, typename U>
574 : struct is_optional_constructible : boost::true_type
575 : {};
576 :
577 : #endif // is_convertible condition
578 :
579 : #if !defined(BOOST_NO_CXX11_DECLTYPE) && !BOOST_WORKAROUND(BOOST_MSVC, < 1800)
580 : // for is_assignable
581 :
582 : // On some initial rvalue reference implementations GCC does it in a strange way,
583 : // preferring perfect-forwarding constructor to implicit copy constructor.
584 :
585 : template <typename T, typename U>
586 : struct is_opt_assignable
587 : : boost::conjunction<boost::is_convertible<U&&, T>, boost::is_assignable<T&, U&&> >
588 : {};
589 :
590 : #else
591 :
592 : template <typename T, typename U>
593 : struct is_opt_assignable : boost::is_convertible<U, T>
594 : {};
595 :
596 : #endif
597 :
598 : template <typename T, typename U>
599 : struct is_factory_or_opt_assignable_to_T
600 : : boost::disjunction< is_in_place_factory<U>, is_opt_assignable<T, U> >
601 : {};
602 :
603 : template <typename T, typename U, bool = has_dedicated_constructor<T, U>::value>
604 : struct is_optional_val_init_candidate
605 : : boost::false_type
606 : {};
607 :
608 : template <typename T, typename U>
609 : struct is_optional_val_init_candidate<T, U, false>
610 : : is_factory_or_constructible_to_T<T, U>
611 : {};
612 :
613 : template <typename T, typename U, bool = has_dedicated_constructor<T, U>::value>
614 : struct is_optional_val_assign_candidate
615 : : boost::false_type
616 : {};
617 :
618 : template <typename T, typename U>
619 : struct is_optional_val_assign_candidate<T, U, false>
620 : : is_factory_or_opt_assignable_to_T<T, U>
621 : {};
622 :
623 : } // namespace optional_detail
624 :
625 : namespace optional_config {
626 :
627 : template <typename T>
628 : struct optional_uses_direct_storage_for
629 : : boost::conditional<(boost::is_scalar<T>::value && !boost::is_const<T>::value && !boost::is_volatile<T>::value)
630 : , boost::true_type, boost::false_type>::type
631 : {};
632 :
633 : } // namespace optional_config
634 :
635 :
636 : #ifndef BOOST_OPTIONAL_DETAIL_NO_DIRECT_STORAGE_SPEC
637 : # define BOOST_OPTIONAL_BASE_TYPE(T) boost::conditional< optional_config::optional_uses_direct_storage_for<T>::value, \
638 : optional_detail::tc_optional_base<T>, \
639 : optional_detail::optional_base<T> \
640 : >::type
641 : #else
642 : # define BOOST_OPTIONAL_BASE_TYPE(T) optional_detail::optional_base<T>
643 : #endif
644 :
645 : template<class T>
646 : class optional
647 : : public BOOST_OPTIONAL_BASE_TYPE(T)
648 : {
649 : typedef typename BOOST_OPTIONAL_BASE_TYPE(T) base ;
650 :
651 : public :
652 :
653 : typedef optional<T> this_type ;
654 :
655 : typedef BOOST_DEDUCED_TYPENAME base::value_type value_type ;
656 : typedef BOOST_DEDUCED_TYPENAME base::reference_type reference_type ;
657 : typedef BOOST_DEDUCED_TYPENAME base::reference_const_type reference_const_type ;
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 : typedef BOOST_DEDUCED_TYPENAME base::pointer_type pointer_type ;
661 : typedef BOOST_DEDUCED_TYPENAME base::pointer_const_type pointer_const_type ;
662 : typedef BOOST_DEDUCED_TYPENAME base::argument_type argument_type ;
663 :
664 : // Creates an optional<T> uninitialized.
665 : // No-throw
666 167520 : optional() BOOST_NOEXCEPT : base() {}
667 :
668 : // Creates an optional<T> uninitialized.
669 : // No-throw
670 : optional( none_t none_ ) BOOST_NOEXCEPT : base(none_) {}
671 :
672 : // Creates an optional<T> initialized with 'val'.
673 : // Can throw if T::T(T const&) does
674 : optional ( argument_type val ) : base(optional_detail::init_value_tag(), val) {}
675 :
676 : // Creates an optional<T> initialized with 'move(val)'.
677 : // Can throw if T::T(T &&) does
678 : optional ( rval_reference_type val ) : base(optional_detail::init_value_tag(), optional_detail::forward<T>(val))
679 : {}
680 :
681 : // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional.
682 : // Can throw if T::T(T const&) does
683 : optional ( bool cond, argument_type val ) : base(cond,val) {}
684 :
685 : /// Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional.
686 : // Can throw if T::T(T &&) does
687 : optional ( bool cond, rval_reference_type val ) : base( cond, optional_detail::forward<T>(val) )
688 : {}
689 :
690 : // NOTE: MSVC needs templated versions first
691 :
692 : // Creates a deep copy of another convertible optional<U>
693 : // Requires a valid conversion from U to T.
694 : // Can throw if T::T(U const&) does
695 : template<class U>
696 : explicit optional ( optional<U> const& rhs
697 : #ifndef BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS
698 : ,BOOST_DEDUCED_TYPENAME boost::enable_if< optional_detail::is_optional_constructible<T, U const&>, bool>::type = true
699 : #endif
700 : )
701 : :
702 : base()
703 : {
704 : if ( rhs.is_initialized() )
705 : this->construct(rhs.get());
706 : }
707 :
708 : // Creates a deep move of another convertible optional<U>
709 : // Requires a valid conversion from U to T.
710 : // Can throw if T::T(U&&) does
711 : template<class U>
712 : explicit optional ( optional<U> && rhs
713 : #ifndef BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS
714 : ,BOOST_DEDUCED_TYPENAME boost::enable_if< optional_detail::is_optional_constructible<T, U>, bool>::type = true
715 : #endif
716 : )
717 : :
718 : base()
719 : {
720 : if ( rhs.is_initialized() )
721 : this->construct( optional_detail::move(rhs.get()) );
722 : }
723 :
724 : #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
725 : // Creates an optional<T> with an expression which can be either
726 : // (a) An instance of InPlaceFactory (i.e. in_place(a,b,...,n);
727 : // (b) An instance of TypedInPlaceFactory ( i.e. in_place<T>(a,b,...,n);
728 : // (c) Any expression implicitly convertible to the single type
729 : // of a one-argument T's constructor.
730 : // (d*) Weak compilers (BCB) might also resolved Expr as optional<T> and optional<U>
731 : // even though explicit overloads are present for these.
732 : // Depending on the above some T ctor is called.
733 : // Can throw if the resolved T ctor throws.
734 :
735 :
736 : template<class Expr>
737 : explicit optional ( Expr&& expr,
738 : BOOST_DEDUCED_TYPENAME boost::enable_if< optional_detail::is_optional_val_init_candidate<T, Expr>, bool>::type = true
739 : )
740 : : base(optional_detail::forward<Expr>(expr),boost::addressof(expr))
741 : {}
742 :
743 : #endif // !defined BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT
744 :
745 : // Creates a deep copy of another optional<T>
746 : // Can throw if T::T(T const&) does
747 : #ifndef BOOST_OPTIONAL_DETAIL_NO_DEFAULTED_MOVE_FUNCTIONS
748 : optional ( optional const& ) = default;
749 : #else
750 : optional ( optional const& rhs ) : base( static_cast<base const&>(rhs) ) {}
751 : #endif
752 :
753 : // Creates a deep move of another optional<T>
754 : // Can throw if T::T(T&&) does
755 : #ifndef BOOST_OPTIONAL_DETAIL_NO_DEFAULTED_MOVE_FUNCTIONS
756 : optional ( optional && ) = default;
757 : #else
758 : optional ( optional && rhs )
759 : BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value)
760 : : base( optional_detail::move(rhs) )
761 : {}
762 : #endif
763 :
764 :
765 : #if BOOST_WORKAROUND(_MSC_VER, <= 1600)
766 : // On old MSVC compilers the implicitly declared dtor is not called
767 : ~optional() {}
768 : #endif
769 :
770 :
771 : #if !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION)
772 : // Assigns from an expression. See corresponding constructor.
773 : // Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED
774 :
775 : template<class Expr>
776 : BOOST_DEDUCED_TYPENAME boost::enable_if<optional_detail::is_optional_val_assign_candidate<T, Expr>, optional&>::type
777 : operator= ( Expr&& expr )
778 : {
779 : this->assign_expr(optional_detail::forward<Expr>(expr),boost::addressof(expr));
780 : return *this ;
781 : }
782 :
783 : #endif // !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION)
784 :
785 : // Copy-assigns from another convertible optional<U> (converts && deep-copies the rhs value)
786 : // Requires a valid conversion from U to T.
787 : // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED
788 : template<class U>
789 : optional& operator= ( optional<U> const& rhs )
790 : {
791 : this->assign(rhs);
792 : return *this ;
793 : }
794 :
795 : // Move-assigns from another convertible optional<U> (converts && deep-moves the rhs value)
796 : // Requires a valid conversion from U to T.
797 : // Basic Guarantee: If T::T( U && ) throws, this is left UNINITIALIZED
798 : template<class U>
799 : optional& operator= ( optional<U> && rhs )
800 : {
801 : this->assign(optional_detail::move(rhs));
802 : return *this ;
803 : }
804 :
805 : // Assigns from another optional<T> (deep-copies the rhs value)
806 : // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED
807 : // (NOTE: On BCB, this operator is not actually called and left is left UNMODIFIED in case of a throw)
808 : #ifndef BOOST_OPTIONAL_DETAIL_NO_DEFAULTED_MOVE_FUNCTIONS
809 : optional& operator= ( optional const& rhs ) = default;
810 : #else
811 : optional& operator= ( optional const& rhs )
812 : {
813 : this->assign( static_cast<base const&>(rhs) ) ;
814 : return *this ;
815 : }
816 : #endif
817 :
818 : // Assigns from another optional<T> (deep-moves the rhs value)
819 : #ifndef BOOST_OPTIONAL_DETAIL_NO_DEFAULTED_MOVE_FUNCTIONS
820 : optional& operator= ( optional && ) = default;
821 : #else
822 : optional& operator= ( optional && rhs )
823 : BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && ::boost::is_nothrow_move_assignable<T>::value)
824 : {
825 : this->assign( static_cast<base &&>(rhs) ) ;
826 : return *this ;
827 : }
828 : #endif
829 :
830 : #ifndef BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX
831 :
832 : // Assigns from a T (deep-moves/copies the rhs value)
833 : template <typename T_>
834 : BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_same<T, BOOST_DEDUCED_TYPENAME boost::decay<T_>::type>, optional&>::type
835 239 : operator= ( T_&& val )
836 : {
837 239 : this->assign( optional_detail::forward<T_>(val) ) ;
838 239 : return *this ;
839 : }
840 :
841 : #else
842 :
843 : // Assigns from a T (deep-copies the rhs value)
844 : // Basic Guarantee: If T::( T const& ) throws, this is left UNINITIALIZED
845 : optional& operator= ( argument_type val )
846 : {
847 : this->assign( val ) ;
848 : return *this ;
849 : }
850 :
851 : // Assigns from a T (deep-moves the rhs value)
852 : optional& operator= ( rval_reference_type val )
853 : {
854 : this->assign( optional_detail::move(val) ) ;
855 : return *this ;
856 : }
857 :
858 : #endif // BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX
859 :
860 : // Assigns from a "none"
861 : // Which destroys the current value, if any, leaving this UNINITIALIZED
862 : // No-throw (assuming T::~T() doesn't)
863 : optional& operator= ( none_t none_ ) BOOST_NOEXCEPT
864 : {
865 : this->assign( none_ ) ;
866 : return *this ;
867 : }
868 :
869 : // Constructs in-place
870 : // upon exception *this is always uninitialized
871 : template<class... Args>
872 : void emplace ( Args&&... args )
873 : {
874 : this->emplace_assign( optional_detail::forward<Args>(args)... );
875 : }
876 :
877 : template<class... Args>
878 : explicit optional ( in_place_init_t, Args&&... args )
879 : : base( in_place_init, optional_detail::forward<Args>(args)... )
880 : {}
881 :
882 : template<class... Args>
883 : explicit optional ( in_place_init_if_t, bool cond, Args&&... args )
884 : : base( in_place_init_if, cond, optional_detail::forward<Args>(args)... )
885 : {}
886 :
887 : void swap( optional & arg )
888 : BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible<T>::value && ::boost::is_nothrow_move_assignable<T>::value)
889 : {
890 : // allow for Koenig lookup
891 : boost::core::invoke_swap(*this, arg);
892 : }
893 :
894 :
895 : // Returns a reference to the value if this is initialized, otherwise,
896 : // the behaviour is UNDEFINED
897 : // No-throw
898 0 : reference_const_type get() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); }
899 239 : reference_type get() { BOOST_ASSERT(this->is_initialized()) ; return this->get_impl(); }
900 :
901 : // Returns a copy of the value if this is initialized, 'v' otherwise
902 : reference_const_type get_value_or ( reference_const_type v ) const { return this->is_initialized() ? get() : v ; }
903 : reference_type get_value_or ( reference_type v ) { return this->is_initialized() ? get() : v ; }
904 :
905 : // Returns a pointer to the value if this is initialized, otherwise,
906 : // the behaviour is UNDEFINED
907 : // No-throw
908 : pointer_const_type operator->() const { BOOST_ASSERT(this->is_initialized()) ; return this->get_ptr_impl() ; }
909 : pointer_type operator->() { BOOST_ASSERT(this->is_initialized()) ; return this->get_ptr_impl() ; }
910 :
911 : // Returns a reference to the value if this is initialized, otherwise,
912 : // the behaviour is UNDEFINED
913 : // No-throw
914 : reference_const_type operator *() BOOST_OPTIONAL_CONST_REF_QUAL { return this->get() ; }
915 : reference_type operator *() BOOST_OPTIONAL_REF_QUAL { return this->get() ; }
916 :
917 : #ifndef BOOST_NO_CXX11_REF_QUALIFIERS
918 : reference_type_of_temporary_wrapper operator *() && { return optional_detail::move(this->get()) ; }
919 : #endif
920 :
921 : reference_const_type value() BOOST_OPTIONAL_CONST_REF_QUAL
922 : {
923 : if (this->is_initialized())
924 : return this->get() ;
925 : else
926 : throw_exception(bad_optional_access());
927 : }
928 :
929 : reference_type value() BOOST_OPTIONAL_REF_QUAL
930 : {
931 : if (this->is_initialized())
932 : return this->get() ;
933 : else
934 : throw_exception(bad_optional_access());
935 : }
936 :
937 : template <class U>
938 : value_type value_or ( U&& v ) BOOST_OPTIONAL_CONST_REF_QUAL
939 : {
940 : if (this->is_initialized())
941 : return get();
942 : else
943 : return optional_detail::forward<U>(v);
944 : }
945 :
946 : template <typename F>
947 : value_type value_or_eval ( F f ) BOOST_OPTIONAL_CONST_REF_QUAL
948 : {
949 : if (this->is_initialized())
950 : return get();
951 : else
952 : return f();
953 : }
954 :
955 : #ifndef BOOST_NO_CXX11_REF_QUALIFIERS
956 : reference_type_of_temporary_wrapper value() &&
957 : {
958 : if (this->is_initialized())
959 : return optional_detail::move(this->get()) ;
960 : else
961 : throw_exception(bad_optional_access());
962 : }
963 :
964 : template <class U>
965 4 : value_type value_or ( U&& v ) &&
966 : {
967 4 : if (this->is_initialized())
968 4 : return optional_detail::move(get());
969 : else
970 0 : return optional_detail::forward<U>(v);
971 4 : }
972 :
973 : template <typename F>
974 : value_type value_or_eval ( F f ) &&
975 : {
976 : if (this->is_initialized())
977 : return optional_detail::move(get());
978 : else
979 : return f();
980 : }
981 : #endif
982 :
983 : // Monadic interface
984 :
985 : template <typename F>
986 : optional<typename optional_detail::result_of<F, reference_type>::type> map(F f) BOOST_OPTIONAL_REF_QUAL
987 : {
988 : if (this->has_value())
989 : return f(get());
990 : else
991 : return none;
992 : }
993 :
994 : template <typename F>
995 : optional<typename optional_detail::result_of<F, reference_const_type>::type> map(F f) BOOST_OPTIONAL_CONST_REF_QUAL
996 : {
997 : if (this->has_value())
998 : return f(get());
999 : else
1000 : return none;
1001 : }
1002 :
1003 : #ifndef BOOST_NO_CXX11_REF_QUALIFIERS
1004 : template <typename F>
1005 : optional<typename optional_detail::result_of<F, reference_type_of_temporary_wrapper>::type> map(F f) &&
1006 : {
1007 : if (this->has_value())
1008 : return f(optional_detail::move(this->get()));
1009 : else
1010 : return none;
1011 : }
1012 : #endif
1013 :
1014 : template <typename F>
1015 : optional<typename optional_detail::result_value_type<F, reference_type>::type>
1016 : flat_map(F f) BOOST_OPTIONAL_REF_QUAL
1017 : {
1018 : if (this->has_value())
1019 : return f(get());
1020 : else
1021 : return none;
1022 : }
1023 :
1024 : template <typename F>
1025 : optional<typename optional_detail::result_value_type<F, reference_const_type>::type>
1026 : flat_map(F f) BOOST_OPTIONAL_CONST_REF_QUAL
1027 : {
1028 : if (this->has_value())
1029 : return f(get());
1030 : else
1031 : return none;
1032 : }
1033 :
1034 : #ifndef BOOST_NO_CXX11_REF_QUALIFIERS
1035 : template <typename F>
1036 : optional<typename optional_detail::result_value_type<F, reference_type_of_temporary_wrapper>::type>
1037 : flat_map(F f) &&
1038 : {
1039 : if (this->has_value())
1040 : return f(optional_detail::move(get()));
1041 : else
1042 : return none;
1043 : }
1044 : #endif
1045 :
1046 235 : bool has_value() const BOOST_NOEXCEPT { return this->is_initialized() ; }
1047 :
1048 235 : explicit operator bool() const BOOST_NOEXCEPT { return this->has_value() ; }
1049 : } ;
1050 :
1051 :
1052 : template<class T>
1053 : class optional<T&&>
1054 : {
1055 : static_assert(sizeof(T) == 0, "Optional rvalue references are illegal.");
1056 : } ;
1057 :
1058 : } // namespace boost
1059 :
1060 : #ifndef BOOST_OPTIONAL_CONFIG_DONT_SPECIALIZE_OPTIONAL_REFS
1061 : # include <boost/optional/detail/optional_reference_spec.hpp>
1062 : #endif
1063 :
1064 : namespace boost {
1065 :
1066 :
1067 : template<class T>
1068 : inline
1069 : optional<BOOST_DEDUCED_TYPENAME boost::decay<T>::type> make_optional ( T && v )
1070 : {
1071 : return optional<BOOST_DEDUCED_TYPENAME boost::decay<T>::type>(optional_detail::forward<T>(v));
1072 : }
1073 :
1074 : // Returns optional<T>(cond,v)
1075 : template<class T>
1076 : inline
1077 : optional<BOOST_DEDUCED_TYPENAME boost::decay<T>::type> make_optional ( bool cond, T && v )
1078 : {
1079 : return optional<BOOST_DEDUCED_TYPENAME boost::decay<T>::type>(cond,optional_detail::forward<T>(v));
1080 : }
1081 :
1082 :
1083 : // Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED.
1084 : // No-throw
1085 : template<class T>
1086 : inline
1087 : BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type
1088 : get ( optional<T> const& opt )
1089 : {
1090 : return opt.get() ;
1091 : }
1092 :
1093 : template<class T>
1094 : inline
1095 : BOOST_DEDUCED_TYPENAME optional<T>::reference_type
1096 : get ( optional<T>& opt )
1097 : {
1098 : return opt.get() ;
1099 : }
1100 :
1101 : // Returns a pointer to the value if this is initialized, otherwise, returns NULL.
1102 : // No-throw
1103 : template<class T>
1104 : inline
1105 : BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type
1106 : get ( optional<T> const* opt )
1107 : {
1108 : return opt->get_ptr() ;
1109 : }
1110 :
1111 : template<class T>
1112 : inline
1113 : BOOST_DEDUCED_TYPENAME optional<T>::pointer_type
1114 : get ( optional<T>* opt )
1115 : {
1116 : return opt->get_ptr() ;
1117 : }
1118 :
1119 : // Returns a reference to the value if this is initialized, otherwise, the behaviour is UNDEFINED.
1120 : // No-throw
1121 : template<class T>
1122 : inline
1123 : BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type
1124 : get_optional_value_or ( optional<T> const& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_const_type v )
1125 : {
1126 : return opt.get_value_or(v) ;
1127 : }
1128 :
1129 : template<class T>
1130 : inline
1131 : BOOST_DEDUCED_TYPENAME optional<T>::reference_type
1132 : get_optional_value_or ( optional<T>& opt, BOOST_DEDUCED_TYPENAME optional<T>::reference_type v )
1133 : {
1134 : return opt.get_value_or(v) ;
1135 : }
1136 :
1137 : // Returns a pointer to the value if this is initialized, otherwise, returns NULL.
1138 : // No-throw
1139 : template<class T>
1140 : inline
1141 : BOOST_DEDUCED_TYPENAME optional<T>::pointer_const_type
1142 : get_pointer ( optional<T> const& opt )
1143 : {
1144 : return opt.get_ptr() ;
1145 : }
1146 :
1147 : template<class T>
1148 : inline
1149 : BOOST_DEDUCED_TYPENAME optional<T>::pointer_type
1150 : get_pointer ( optional<T>& opt )
1151 : {
1152 : return opt.get_ptr() ;
1153 : }
1154 :
1155 : } // namespace boost
1156 :
1157 : #ifndef BOOST_NO_IOSTREAM
1158 : namespace boost {
1159 :
1160 : // The following declaration prevents a bug where operator safe-bool is used upon streaming optional object if you forget the IO header.
1161 : template<class CharType, class CharTrait>
1162 : std::basic_ostream<CharType, CharTrait>&
1163 : operator<<(std::basic_ostream<CharType, CharTrait>& os, optional_detail::optional_tag const&)
1164 : {
1165 : static_assert(sizeof(CharType) == 0, "If you want to output boost::optional, include header <boost/optional/optional_io.hpp>");
1166 : return os;
1167 : }
1168 :
1169 : } // namespace boost
1170 : #endif // BOOST_NO_IOSTREAM
1171 :
1172 : #include <boost/optional/detail/optional_relops.hpp>
1173 : #include <boost/optional/detail/optional_swap.hpp>
1174 :
1175 : #endif // header guard
|