blob: 8a4a31a52ee3e87c7cd4a3503ee5b4763364c735 [file] [log] [blame]
Davide Pesavento1fd00242018-05-20 00:11:01 -04001//
2// Copyright (c) 2014-2017 Martin Moene
3//
4// https://github.com/martinmoene/optional-lite
5//
6// This code is licensed under the MIT License (MIT).
7//
8// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
11// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
13// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
14// THE SOFTWARE.
15
16#pragma once
17
18#ifndef NONSTD_OPTIONAL_LITE_HPP
19#define NONSTD_OPTIONAL_LITE_HPP
20
21#define optional_lite_VERSION "2.3.2"
22
23// Compiler detection (C++20 is speculative):
24// Note: MSVC supports C++14 since it supports C++17.
25
26#ifdef _MSVC_LANG
27# define optional_MSVC_LANG _MSVC_LANG
28#else
29# define optional_MSVC_LANG 0
30#endif
31
32#define optional_CPP11 (__cplusplus == 201103L )
33#define optional_CPP11_OR_GREATER (__cplusplus >= 201103L || optional_MSVC_LANG >= 201103L )
34#define optional_CPP14_OR_GREATER (__cplusplus >= 201402L || optional_MSVC_LANG >= 201703L )
35#define optional_CPP17_OR_GREATER (__cplusplus >= 201703L || optional_MSVC_LANG >= 201703L )
36#define optional_CPP20_OR_GREATER (__cplusplus >= 202000L || optional_MSVC_LANG >= 202000L )
37
38// use C++17 std::optional if available:
39
40#if defined( __has_include )
41# define optional_HAS_INCLUDE( arg ) __has_include( arg )
42#else
43# define optional_HAS_INCLUDE( arg ) 0
44#endif
45
46#define optional_HAVE_STD_OPTIONAL ( optional_CPP17_OR_GREATER && optional_HAS_INCLUDE( <optional> ) )
47
48#if optional_HAVE_STD_OPTIONAL
49
50#include <optional>
51
52namespace nonstd {
53
54 using std::optional;
55 using std::bad_optional_access;
56 using std::hash;
57
58 using std::nullopt;
59 using std::nullopt_t;
60 using std::in_place;
61 using std::in_place_type;
62 using std::in_place_index;
63 using std::in_place_t;
64 using std::in_place_type_t;
65 using std::in_place_index_t;
66
67 using std::operator==;
68 using std::operator!=;
69 using std::operator<;
70 using std::operator<=;
71 using std::operator>;
72 using std::operator>=;
73 using std::make_optional;
74 using std::swap;
75}
76
77#else // C++17 std::optional
78
79#include <cassert>
80#include <stdexcept>
81#include <utility>
82
83// optional-lite alignment configuration:
84
85#ifndef optional_CONFIG_MAX_ALIGN_HACK
86# define optional_CONFIG_MAX_ALIGN_HACK 0
87#endif
88
89#ifndef optional_CONFIG_ALIGN_AS
90// no default, used in #if defined()
91#endif
92
93#ifndef optional_CONFIG_ALIGN_AS_FALLBACK
94# define optional_CONFIG_ALIGN_AS_FALLBACK double
95#endif
96
97// Compiler warning suppression:
98
99#ifdef __clang__
100# pragma clang diagnostic push
101# pragma clang diagnostic ignored "-Wundef"
102#elif defined __GNUC__
103# pragma GCC diagnostic push
104# pragma GCC diagnostic ignored "-Wundef"
105#endif
106
107// half-open range [lo..hi):
108#define optional_BETWEEN( v, lo, hi ) ( lo <= v && v < hi )
109
110#if defined(_MSC_VER) && !defined(__clang__)
111# define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900)) )
112#else
113# define optional_COMPILER_MSVC_VERSION 0
114#endif
115
116#define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * major + minor ) + patch )
117
118#if defined __GNUC__
119# define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
120#else
121# define optional_COMPILER_GNUC_VERSION 0
122#endif
123
124#if defined __clang__
125# define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
126#else
127# define optional_COMPILER_CLANG_VERSION 0
128#endif
129
130#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 )
131# pragma warning( push )
132# pragma warning( disable: 4345 ) // initialization behavior changed
133#endif
134
135#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 )
136# pragma warning( push )
137# pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const'
138#endif
139
140// Presence of language and library features:
141
142#define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE )
143
144// Presence of C++11 language features:
145
146#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 100
147# define optional_HAVE_AUTO 1
148# define optional_HAVE_NULLPTR 1
149# define optional_HAVE_STATIC_ASSERT 1
150#endif
151
152#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 120
153# define optional_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 1
154# define optional_HAVE_INITIALIZER_LIST 1
155#endif
156
157#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 140
158# define optional_HAVE_ALIAS_TEMPLATE 1
159# define optional_HAVE_CONSTEXPR_11 1
160# define optional_HAVE_ENUM_CLASS 1
161# define optional_HAVE_EXPLICIT_CONVERSION 1
162# define optional_HAVE_IS_DEFAULT 1
163# define optional_HAVE_IS_DELETE 1
164# define optional_HAVE_NOEXCEPT 1
165# define optional_HAVE_REF_QUALIFIER 1
166#endif
167
168// Presence of C++14 language features:
169
170#if optional_CPP14_OR_GREATER
171# define optional_HAVE_CONSTEXPR_14 1
172#endif
173
174// Presence of C++17 language features:
175
176#if optional_CPP17_OR_GREATER
177# define optional_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1
178#endif
179
180// Presence of C++ library features:
181
182#if optional_COMPILER_GNUC_VERSION
183# define optional_HAVE_TR1_TYPE_TRAITS 1
184# define optional_HAVE_TR1_ADD_POINTER 1
185#endif
186
187#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 90
188# define optional_HAVE_TYPE_TRAITS 1
189# define optional_HAVE_STD_ADD_POINTER 1
190#endif
191
192#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 110
193# define optional_HAVE_ARRAY 1
194#endif
195
196#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 120
197# define optional_HAVE_CONDITIONAL 1
198#endif
199
200#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 140 || (optional_COMPILER_MSVC_VERSION >= 90 && _HAS_CPP0X)
201# define optional_HAVE_CONTAINER_DATA_METHOD 1
202#endif
203
204#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 120
205# define optional_HAVE_REMOVE_CV 1
206#endif
207
208#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 140
209# define optional_HAVE_SIZED_TYPES 1
210#endif
211
212// For the rest, consider VC14 as C++11 for optional-lite:
213
214#if optional_COMPILER_MSVC_VERSION >= 140
215# undef optional_CPP11_OR_GREATER
216# define optional_CPP11_OR_GREATER 1
217#endif
218
219// C++ feature usage:
220
221#if optional_HAVE( CONSTEXPR_11 )
222# define optional_constexpr constexpr
223#else
224# define optional_constexpr /*constexpr*/
225#endif
226
227#if optional_HAVE( CONSTEXPR_14 )
228# define optional_constexpr14 constexpr
229#else
230# define optional_constexpr14 /*constexpr*/
231#endif
232
233#if optional_HAVE( NOEXCEPT )
234# define optional_noexcept noexcept
235#else
236# define optional_noexcept /*noexcept*/
237#endif
238
239#if optional_HAVE( NULLPTR )
240# define optional_nullptr nullptr
241#else
242# define optional_nullptr NULL
243#endif
244
245#if optional_HAVE( REF_QUALIFIER )
246# define optional_ref_qual &
247# define optional_refref_qual &&
248#else
249# define optional_ref_qual /*&*/
250# define optional_refref_qual /*&&*/
251#endif
252
253// additional includes:
254
255#if optional_CPP11_OR_GREATER
256# include <functional>
257#endif
258
259#if optional_HAVE( INITIALIZER_LIST )
260# include <initializer_list>
261#endif
262
263#if optional_HAVE( TYPE_TRAITS )
264# include <type_traits>
265#elif optional_HAVE( TR1_TYPE_TRAITS )
266# include <tr1/type_traits>
267#endif
268
269// type traits needed:
270
271namespace nonstd { namespace optional_lite { namespace detail {
272
273#if optional_HAVE( CONDITIONAL )
274 using std::conditional;
275#else
276 template< bool B, typename T, typename F > struct conditional { typedef T type; };
277 template< typename T, typename F > struct conditional<false, T, F> { typedef F type; };
278#endif // optional_HAVE_CONDITIONAL
279
280}}}
281
282//
283// in_place: code duplicated in any-lite, optional-lite, variant-lite:
284//
285
286#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
287
288namespace nonstd {
289
290namespace detail {
291
292template< class T >
293struct in_place_type_tag {};
294
295template< std::size_t I >
296struct in_place_index_tag {};
297
298} // namespace detail
299
300struct in_place_t {};
301
302template< class T >
303inline in_place_t in_place( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
304{
305 return in_place_t();
306}
307
308template< std::size_t I >
309inline in_place_t in_place( detail::in_place_index_tag<I> = detail::in_place_index_tag<I>() )
310{
311 return in_place_t();
312}
313
314template< class T >
315inline in_place_t in_place_type( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
316{
317 return in_place_t();
318}
319
320template< std::size_t I >
321inline in_place_t in_place_index( detail::in_place_index_tag<I> = detail::in_place_index_tag<I>() )
322{
323 return in_place_t();
324}
325
326// mimic templated typedef:
327
328#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
329#define nonstd_lite_in_place_index_t(T) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<I> )
330
331#define nonstd_lite_HAVE_IN_PLACE_TYPES 1
332
333} // namespace nonstd
334
335#endif // nonstd_lite_HAVE_IN_PLACE_TYPES
336
337//
338// optional:
339//
340
341namespace nonstd { namespace optional_lite {
342
343/// class optional
344
345template< typename T >
346class optional;
347
348namespace detail {
349
350// C++11 emulation:
351
352struct nulltype{};
353
354template< typename Head, typename Tail >
355struct typelist
356{
357 typedef Head head;
358 typedef Tail tail;
359};
360
361#if optional_CONFIG_MAX_ALIGN_HACK
362
363// Max align, use most restricted type for alignment:
364
365#define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ )
366#define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line )
367#define optional_UNIQUE3( name, line ) name ## line
368
369#define optional_ALIGN_TYPE( type ) \
370 type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st )
371
372template< typename T >
373struct struct_t { T _; };
374
375union max_align_t
376{
377 optional_ALIGN_TYPE( char );
378 optional_ALIGN_TYPE( short int );
379 optional_ALIGN_TYPE( int );
380 optional_ALIGN_TYPE( long int );
381 optional_ALIGN_TYPE( float );
382 optional_ALIGN_TYPE( double );
383 optional_ALIGN_TYPE( long double );
384 optional_ALIGN_TYPE( char * );
385 optional_ALIGN_TYPE( short int * );
386 optional_ALIGN_TYPE( int * );
387 optional_ALIGN_TYPE( long int * );
388 optional_ALIGN_TYPE( float * );
389 optional_ALIGN_TYPE( double * );
390 optional_ALIGN_TYPE( long double * );
391 optional_ALIGN_TYPE( void * );
392
393#ifdef HAVE_LONG_LONG
394 optional_ALIGN_TYPE( long long );
395#endif
396
397 struct Unknown;
398
399 Unknown ( * optional_UNIQUE(_) )( Unknown );
400 Unknown * Unknown::* optional_UNIQUE(_);
401 Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown );
402
403 struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_);
404 struct_t< Unknown * Unknown::* > optional_UNIQUE(_);
405 struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_);
406};
407
408#undef optional_UNIQUE
409#undef optional_UNIQUE2
410#undef optional_UNIQUE3
411
412#undef optional_ALIGN_TYPE
413
414#elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK
415
416// Use user-specified type for alignment:
417
418#define optional_ALIGN_AS( unused ) \
419 optional_CONFIG_ALIGN_AS
420
421#else // optional_CONFIG_MAX_ALIGN_HACK
422
423// Determine POD type to use for alignment:
424
425#define optional_ALIGN_AS( to_align ) \
426 typename type_of_size< alignment_types, alignment_of< to_align >::value >::type
427
428template <typename T>
429struct alignment_of;
430
431template <typename T>
432struct alignment_of_hack
433{
434 char c;
435 T t;
436 alignment_of_hack();
437};
438
439template <unsigned A, unsigned S>
440struct alignment_logic
441{
442 enum { value = A < S ? A : S };
443};
444
445template< typename T >
446struct alignment_of
447{
448 enum { value = alignment_logic<
449 sizeof( alignment_of_hack<T> ) - sizeof(T), sizeof(T) >::value, };
450};
451
452template< typename List, size_t N >
453struct type_of_size
454{
455 typedef typename conditional<
456 N == sizeof( typename List::head ),
457 typename List::head,
458 typename type_of_size<typename List::tail, N >::type >::type type;
459};
460
461template< size_t N >
462struct type_of_size< nulltype, N >
463{
464 typedef optional_CONFIG_ALIGN_AS_FALLBACK type;
465};
466
467template< typename T>
468struct struct_t { T _; };
469
470#define optional_ALIGN_TYPE( type ) \
471 typelist< type , typelist< struct_t< type >
472
473struct Unknown;
474
475typedef
476 optional_ALIGN_TYPE( char ),
477 optional_ALIGN_TYPE( short ),
478 optional_ALIGN_TYPE( int ),
479 optional_ALIGN_TYPE( long ),
480 optional_ALIGN_TYPE( float ),
481 optional_ALIGN_TYPE( double ),
482 optional_ALIGN_TYPE( long double ),
483
484 optional_ALIGN_TYPE( char *),
485 optional_ALIGN_TYPE( short * ),
486 optional_ALIGN_TYPE( int * ),
487 optional_ALIGN_TYPE( long * ),
488 optional_ALIGN_TYPE( float * ),
489 optional_ALIGN_TYPE( double * ),
490 optional_ALIGN_TYPE( long double * ),
491
492 optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ),
493 optional_ALIGN_TYPE( Unknown * Unknown::* ),
494 optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ),
495
496 nulltype
497 > > > > > > > > > > > > > >
498 > > > > > > > > > > > > > >
499 > > > > > >
500 alignment_types;
501
502#undef optional_ALIGN_TYPE
503
504#endif // optional_CONFIG_MAX_ALIGN_HACK
505
506/// C++03 constructed union to hold value.
507
508template< typename T >
509union storage_t
510{
511private:
512 friend class optional<T>;
513
514 typedef T value_type;
515
516 storage_t() {}
517
518 storage_t( value_type const & v )
519 {
520 construct_value( v );
521 }
522
523 void construct_value( value_type const & v )
524 {
525 ::new( value_ptr() ) value_type( v );
526 }
527
528#if optional_CPP11_OR_GREATER
529
530 storage_t( value_type && v )
531 {
532 construct_value( std::move( v ) );
533 }
534
535 void construct_value( value_type && v )
536 {
537 ::new( value_ptr() ) value_type( std::move( v ) );
538 }
539
540#endif
541
542 void destruct_value()
543 {
544 value_ptr()->~T();
545 }
546
547 value_type const * value_ptr() const
548 {
549 return as<value_type>();
550 }
551
552 value_type * value_ptr()
553 {
554 return as<value_type>();
555 }
556
557 value_type const & value() const optional_ref_qual
558 {
559 return * value_ptr();
560 }
561
562 value_type & value() optional_ref_qual
563 {
564 return * value_ptr();
565 }
566
567#if optional_CPP11_OR_GREATER
568
569 value_type const && value() const optional_refref_qual
570 {
571 return * value_ptr();
572 }
573
574 value_type && value() optional_refref_qual
575 {
576 return * value_ptr();
577 }
578
579#endif
580
581#if optional_CPP11_OR_GREATER
582
583 using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type;
584 aligned_storage_t data;
585
586#elif optional_CONFIG_MAX_ALIGN_HACK
587
588 typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t;
589
590 max_align_t hack;
591 aligned_storage_t data;
592
593#else
594 typedef optional_ALIGN_AS(value_type) align_as_type;
595
596 typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t;
597 aligned_storage_t data;
598
599# undef optional_ALIGN_AS
600
601#endif // optional_CONFIG_MAX_ALIGN_HACK
602
603 void * ptr() optional_noexcept
604 {
605 return &data;
606 }
607
608 void const * ptr() const optional_noexcept
609 {
610 return &data;
611 }
612
613 template <typename U>
614 U * as()
615 {
616 return reinterpret_cast<U*>( ptr() );
617 }
618
619 template <typename U>
620 U const * as() const
621 {
622 return reinterpret_cast<U const *>( ptr() );
623 }
624};
625
626} // namespace detail
627
628/// disengaged state tag
629
630struct nullopt_t
631{
632 struct init{};
633 optional_constexpr nullopt_t( init ) {}
634};
635
636#if optional_HAVE( CONSTEXPR_11 )
637constexpr nullopt_t nullopt{ nullopt_t::init{} };
638#else
639// extra parenthesis to prevent the most vexing parse:
640const nullopt_t nullopt(( nullopt_t::init() ));
641#endif
642
643/// optional access error
644
645class bad_optional_access : public std::logic_error
646{
647public:
648 explicit bad_optional_access()
649 : logic_error( "bad optional access" ) {}
650};
651
652/// optional
653
654template< typename T>
655class optional
656{
657private:
658 typedef void (optional::*safe_bool)() const;
659
660public:
661 typedef T value_type;
662
663 optional_constexpr optional() optional_noexcept
664 : has_value_( false )
665 , contained()
666 {}
667
668 optional_constexpr optional( nullopt_t ) optional_noexcept
669 : has_value_( false )
670 , contained()
671 {}
672
673 optional( optional const & rhs )
674 : has_value_( rhs.has_value() )
675 {
676 if ( rhs.has_value() )
677 contained.construct_value( rhs.contained.value() );
678 }
679
680#if optional_CPP11_OR_GREATER
681 optional_constexpr14 optional( optional && rhs ) noexcept( std::is_nothrow_move_constructible<T>::value )
682 : has_value_( rhs.has_value() )
683 {
684 if ( rhs.has_value() )
685 contained.construct_value( std::move( rhs.contained.value() ) );
686 }
687#endif
688
689 optional_constexpr optional( value_type const & value )
690 : has_value_( true )
691 , contained( value )
692 {}
693
694#if optional_CPP11_OR_GREATER
695
696 optional_constexpr optional( value_type && value )
697 : has_value_( true )
698 , contained( std::move( value ) )
699 {}
700
701 template< class... Args >
702 optional_constexpr explicit optional( nonstd_lite_in_place_type_t(T), Args&&... args )
703 : has_value_( true )
704 , contained( T( std::forward<Args>(args)...) )
705 {}
706
707 template< class U, class... Args >
708 optional_constexpr explicit optional( nonstd_lite_in_place_type_t(T), std::initializer_list<U> il, Args&&... args )
709 : has_value_( true )
710 , contained( T( il, std::forward<Args>(args)...) )
711 {}
712
713#endif // optional_CPP11_OR_GREATER
714
715 ~optional()
716 {
717 if ( has_value() )
718 contained.destruct_value();
719 }
720
721 // assignment
722
723 optional & operator=( nullopt_t ) optional_noexcept
724 {
725 reset();
726 return *this;
727 }
728
729 optional & operator=( optional const & rhs )
730#if optional_CPP11_OR_GREATER
731 noexcept( std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value )
732#endif
733 {
734 if ( has_value() == true && rhs.has_value() == false ) reset();
735 else if ( has_value() == false && rhs.has_value() == true ) initialize( *rhs );
736 else if ( has_value() == true && rhs.has_value() == true ) contained.value() = *rhs;
737 return *this;
738 }
739
740#if optional_CPP11_OR_GREATER
741
742 optional & operator=( optional && rhs ) noexcept
743 {
744 if ( has_value() == true && rhs.has_value() == false ) reset();
745 else if ( has_value() == false && rhs.has_value() == true ) initialize( std::move( *rhs ) );
746 else if ( has_value() == true && rhs.has_value() == true ) contained.value() = std::move( *rhs );
747 return *this;
748 }
749
750 template< class U,
751 typename = typename std::enable_if< std::is_same< typename std::decay<U>::type, T>::value >::type >
752 optional & operator=( U && v )
753 {
754 if ( has_value() ) contained.value() = std::forward<U>( v );
755 else initialize( T( std::forward<U>( v ) ) );
756 return *this;
757 }
758
759 template< class... Args >
760 void emplace( Args&&... args )
761 {
762 *this = nullopt;
763 initialize( T( std::forward<Args>(args)...) );
764 }
765
766 template< class U, class... Args >
767 void emplace( std::initializer_list<U> il, Args&&... args )
768 {
769 *this = nullopt;
770 initialize( T( il, std::forward<Args>(args)...) );
771 }
772
773#endif // optional_CPP11_OR_GREATER
774
775 // swap
776
777 void swap( optional & rhs )
778#if optional_CPP11_OR_GREATER
779 noexcept( std::is_nothrow_move_constructible<T>::value && noexcept( std::swap( std::declval<T&>(), std::declval<T&>() ) ) )
780#endif
781 {
782 using std::swap;
783 if ( has_value() == true && rhs.has_value() == true ) { swap( **this, *rhs ); }
784 else if ( has_value() == false && rhs.has_value() == true ) { initialize( *rhs ); rhs.reset(); }
785 else if ( has_value() == true && rhs.has_value() == false ) { rhs.initialize( **this ); reset(); }
786 }
787
788 // observers
789
790 optional_constexpr value_type const * operator ->() const
791 {
792 return assert( has_value() ),
793 contained.value_ptr();
794 }
795
796 optional_constexpr14 value_type * operator ->()
797 {
798 return assert( has_value() ),
799 contained.value_ptr();
800 }
801
802 optional_constexpr value_type const & operator *() const optional_ref_qual
803 {
804 return assert( has_value() ),
805 contained.value();
806 }
807
808 optional_constexpr14 value_type & operator *() optional_ref_qual
809 {
810 return assert( has_value() ),
811 contained.value();
812 }
813
814#if optional_CPP11_OR_GREATER
815
816 optional_constexpr value_type const && operator *() const optional_refref_qual
817 {
818 return assert( has_value() ),
819 std::move( contained.value() );
820 }
821
822 optional_constexpr14 value_type && operator *() optional_refref_qual
823 {
824 return assert( has_value() ),
825 std::move( contained.value() );
826 }
827
828#endif
829
830#if optional_CPP11_OR_GREATER
831 optional_constexpr explicit operator bool() const optional_noexcept
832 {
833 return has_value();
834 }
835#else
836 optional_constexpr operator safe_bool() const optional_noexcept
837 {
838 return has_value() ? &optional::this_type_does_not_support_comparisons : 0;
839 }
840#endif
841
842 optional_constexpr bool has_value() const optional_noexcept
843 {
844 return has_value_;
845 }
846
847 optional_constexpr14 value_type const & value() const optional_ref_qual
848 {
849 if ( ! has_value() )
850 throw bad_optional_access();
851
852 return contained.value();
853 }
854
855 optional_constexpr14 value_type & value() optional_ref_qual
856 {
857 if ( ! has_value() )
858 throw bad_optional_access();
859
860 return contained.value();
861 }
862
863#if optional_HAVE( REF_QUALIFIER )
864
865 optional_constexpr14 value_type const && value() const optional_refref_qual
866 {
867 if ( ! has_value() )
868 throw bad_optional_access();
869
870 return std::move( contained.value() );
871 }
872
873 optional_constexpr14 value_type && value() optional_refref_qual
874 {
875 if ( ! has_value() )
876 throw bad_optional_access();
877
878 return std::move( contained.value() );
879 }
880
881#endif
882
883#if optional_CPP11_OR_GREATER
884
885 template< class U >
886 optional_constexpr value_type value_or( U && v ) const optional_ref_qual
887 {
888 return has_value() ? contained.value() : static_cast<T>(std::forward<U>( v ) );
889 }
890
891 template< class U >
892 optional_constexpr value_type value_or( U && v ) const optional_refref_qual
893 {
894 return has_value() ? std::move( contained.value() ) : static_cast<T>(std::forward<U>( v ) );
895 }
896
897#else
898
899 template< class U >
900 optional_constexpr value_type value_or( U const & v ) const
901 {
902 return has_value() ? contained.value() : static_cast<value_type>( v );
903 }
904
905#endif // optional_CPP11_OR_GREATER
906
907 // modifiers
908
909 void reset() optional_noexcept
910 {
911 if ( has_value() )
912 contained.destruct_value();
913
914 has_value_ = false;
915 }
916
917private:
918 void this_type_does_not_support_comparisons() const {}
919
920 template< typename V >
921 void initialize( V const & value )
922 {
923 assert( ! has_value() );
924 contained.construct_value( value );
925 has_value_ = true;
926 }
927
928#if optional_CPP11_OR_GREATER
929 template< typename V >
930 void initialize( V && value )
931 {
932 assert( ! has_value() );
933 contained.construct_value( std::move( value ) );
934 has_value_ = true;
935 }
936#endif
937
938private:
939 bool has_value_;
940 detail::storage_t< value_type > contained;
941
942};
943
944// Relational operators
945
946template< typename T, typename U >
947inline optional_constexpr bool operator==( optional<T> const & x, optional<U> const & y )
948{
949 return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y;
950}
951
952template< typename T, typename U >
953inline optional_constexpr bool operator!=( optional<T> const & x, optional<U> const & y )
954{
955 return !(x == y);
956}
957
958template< typename T, typename U >
959inline optional_constexpr bool operator<( optional<T> const & x, optional<U> const & y )
960{
961 return (!y) ? false : (!x) ? true : *x < *y;
962}
963
964template< typename T, typename U >
965inline optional_constexpr bool operator>( optional<T> const & x, optional<U> const & y )
966{
967 return (y < x);
968}
969
970template< typename T, typename U >
971inline optional_constexpr bool operator<=( optional<T> const & x, optional<U> const & y )
972{
973 return !(y < x);
974}
975
976template< typename T, typename U >
977inline optional_constexpr bool operator>=( optional<T> const & x, optional<U> const & y )
978{
979 return !(x < y);
980}
981
982// Comparison with nullopt
983
984template< typename T >
985inline optional_constexpr bool operator==( optional<T> const & x, nullopt_t ) optional_noexcept
986{
987 return (!x);
988}
989
990template< typename T >
991inline optional_constexpr bool operator==( nullopt_t, optional<T> const & x ) optional_noexcept
992{
993 return (!x);
994}
995
996template< typename T >
997inline optional_constexpr bool operator!=( optional<T> const & x, nullopt_t ) optional_noexcept
998{
999 return bool(x);
1000}
1001
1002template< typename T >
1003inline optional_constexpr bool operator!=( nullopt_t, optional<T> const & x ) optional_noexcept
1004{
1005 return bool(x);
1006}
1007
1008template< typename T >
1009inline optional_constexpr bool operator<( optional<T> const &, nullopt_t ) optional_noexcept
1010{
1011 return false;
1012}
1013
1014template< typename T >
1015inline optional_constexpr bool operator<( nullopt_t, optional<T> const & x ) optional_noexcept
1016{
1017 return bool(x);
1018}
1019
1020template< typename T >
1021inline optional_constexpr bool operator<=( optional<T> const & x, nullopt_t ) optional_noexcept
1022{
1023 return (!x);
1024}
1025
1026template< typename T >
1027inline optional_constexpr bool operator<=( nullopt_t, optional<T> const & ) optional_noexcept
1028{
1029 return true;
1030}
1031
1032template< typename T >
1033inline optional_constexpr bool operator>( optional<T> const & x, nullopt_t ) optional_noexcept
1034{
1035 return bool(x);
1036}
1037
1038template< typename T >
1039inline optional_constexpr bool operator>( nullopt_t, optional<T> const & ) optional_noexcept
1040{
1041 return false;
1042}
1043
1044template< typename T >
1045inline optional_constexpr bool operator>=( optional<T> const &, nullopt_t ) optional_noexcept
1046{
1047 return true;
1048}
1049
1050template< typename T >
1051inline optional_constexpr bool operator>=( nullopt_t, optional<T> const & x ) optional_noexcept
1052{
1053 return (!x);
1054}
1055
1056// Comparison with T
1057
1058template< typename T, typename U >
1059inline optional_constexpr bool operator==( optional<T> const & x, U const & v )
1060{
1061 return bool(x) ? *x == v : false;
1062}
1063
1064template< typename T, typename U >
1065inline optional_constexpr bool operator==( U const & v, optional<T> const & x )
1066{
1067 return bool(x) ? v == *x : false;
1068}
1069
1070template< typename T, typename U >
1071inline optional_constexpr bool operator!=( optional<T> const & x, U const & v )
1072{
1073 return bool(x) ? *x != v : true;
1074}
1075
1076template< typename T, typename U >
1077inline optional_constexpr bool operator!=( U const & v, optional<T> const & x )
1078{
1079 return bool(x) ? v != *x : true;
1080}
1081
1082template< typename T, typename U >
1083inline optional_constexpr bool operator<( optional<T> const & x, U const & v )
1084{
1085 return bool(x) ? *x < v : true;
1086}
1087
1088template< typename T, typename U >
1089inline optional_constexpr bool operator<( U const & v, optional<T> const & x )
1090{
1091 return bool(x) ? v < *x : false;
1092}
1093
1094template< typename T, typename U >
1095inline optional_constexpr bool operator<=( optional<T> const & x, U const & v )
1096{
1097 return bool(x) ? *x <= v : true;
1098}
1099
1100template< typename T, typename U >
1101inline optional_constexpr bool operator<=( U const & v, optional<T> const & x )
1102{
1103 return bool(x) ? v <= *x : false;
1104}
1105
1106template< typename T, typename U >
1107inline optional_constexpr bool operator>( optional<T> const & x, U const & v )
1108{
1109 return bool(x) ? *x > v : false;
1110}
1111
1112template< typename T, typename U >
1113inline optional_constexpr bool operator>( U const & v, optional<T> const & x )
1114{
1115 return bool(x) ? v > *x : true;
1116}
1117
1118template< typename T, typename U >
1119inline optional_constexpr bool operator>=( optional<T> const & x, U const & v )
1120{
1121 return bool(x) ? *x >= v : false;
1122}
1123
1124template< typename T, typename U >
1125inline optional_constexpr bool operator>=( U const & v, optional<T> const & x )
1126{
1127 return bool(x) ? v >= *x : true;
1128}
1129
1130// Specialized algorithms
1131
1132template< typename T >
1133void swap( optional<T> & x, optional<T> & y )
1134#if optional_CPP11_OR_GREATER
1135 noexcept( noexcept( x.swap(y) ) )
1136#endif
1137{
1138 x.swap( y );
1139}
1140
1141#if optional_CPP11_OR_GREATER
1142
1143template< class T >
1144optional_constexpr optional< typename std::decay<T>::type > make_optional( T && v )
1145{
1146 return optional< typename std::decay<T>::type >( std::forward<T>( v ) );
1147}
1148
1149template< class T, class...Args >
1150optional_constexpr optional<T> make_optional( Args&&... args )
1151{
1152 return optional<T>( in_place, std::forward<Args>(args)...);
1153}
1154
1155template< class T, class U, class... Args >
1156optional_constexpr optional<T> make_optional( std::initializer_list<U> il, Args&&... args )
1157{
1158 return optional<T>( in_place, il, std::forward<Args>(args)...);
1159}
1160
1161#else
1162
1163template< typename T >
1164optional<T> make_optional( T const & v )
1165{
1166 return optional<T>( v );
1167}
1168
1169#endif // optional_CPP11_OR_GREATER
1170
1171} // namespace optional
1172
1173using namespace optional_lite;
1174
1175} // namespace nonstd
1176
1177#if optional_CPP11_OR_GREATER
1178
1179// specialize the std::hash algorithm:
1180
1181namespace std {
1182
1183template< class T >
1184struct hash< nonstd::optional<T> >
1185{
1186public:
1187 std::size_t operator()( nonstd::optional<T> const & v ) const optional_noexcept
1188 {
1189 return bool( v ) ? hash<T>()( *v ) : 0;
1190 }
1191};
1192
1193} //namespace std
1194
1195#endif // optional_CPP11_OR_GREATER
1196
1197#ifdef __clang__
1198# pragma clang diagnostic pop
1199#elif defined __GNUC__
1200# pragma GCC diagnostic pop
1201#endif
1202
1203#endif // have C++17 std::optional
1204
1205#endif // NONSTD_OPTIONAL_LITE_HPP