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