blob: 764598ac979db68e6be23825f79b654511a9b49b [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 Pesaventod2c750b2018-09-16 12:48:01 -04006// Distributed under the Boost Software License, Version 1.0.
Davide Pesaventobc76da12018-07-17 15:20:24 -04007// (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 Pesaventod2c750b2018-09-16 12:48:01 -040014#define optional_lite_MAJOR 3
15#define optional_lite_MINOR 1
16#define optional_lite_PATCH 0
Davide Pesavento1fd00242018-05-20 00:11:01 -040017
Davide Pesaventod2c750b2018-09-16 12:48:01 -040018#define optional_lite_VERSION optional_STRINGIFY(optional_lite_MAJOR) "." optional_STRINGIFY(optional_lite_MINOR) "." optional_STRINGIFY(optional_lite_PATCH)
Davide Pesavento1fd00242018-05-20 00:11:01 -040019
Davide Pesaventod2c750b2018-09-16 12:48:01 -040020#define optional_STRINGIFY( x ) optional_STRINGIFY_( x )
21#define optional_STRINGIFY_( x ) #x
22
23// optional-lite configuration:
24
25#define optional_OPTIONAL_DEFAULT 0
26#define optional_OPTIONAL_NONSTD 1
27#define optional_OPTIONAL_STD 2
28
29#if !defined( optional_CONFIG_SELECT_OPTIONAL )
30# define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD )
Davide Pesavento1fd00242018-05-20 00:11:01 -040031#endif
32
Davide Pesaventod2c750b2018-09-16 12:48:01 -040033// C++ language version detection (C++20 is speculative):
34// Note: VC14.0/1900 (VS2015) lacks too much from C++14.
Davide Pesavento1fd00242018-05-20 00:11:01 -040035
Davide Pesaventod2c750b2018-09-16 12:48:01 -040036#ifndef optional_CPLUSPLUS
37# ifdef _MSVC_LANG
38# define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
39# else
40# define optional_CPLUSPLUS __cplusplus
41# endif
Davide Pesavento1fd00242018-05-20 00:11:01 -040042#endif
43
Davide Pesaventod2c750b2018-09-16 12:48:01 -040044#define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L )
45#define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L )
46#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L )
47#define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L )
48#define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L )
Davide Pesavento1fd00242018-05-20 00:11:01 -040049
Davide Pesaventod2c750b2018-09-16 12:48:01 -040050// C++ language version (represent 98 as 3):
51
52#define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) )
53
54// Use C++17 std::optional if available and requested:
55
56#if optional_CPP17_OR_GREATER && defined(__has_include )
57# if __has_include( <optional> )
58# define optional_HAVE_STD_OPTIONAL 1
59# else
60# define optional_HAVE_STD_OPTIONAL 0
61# endif
62#else
63# define optional_HAVE_STD_OPTIONAL 0
64#endif
65
66#define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) )
67
68// Using std::optional:
69
70#if optional_USES_STD_OPTIONAL
Davide Pesavento1fd00242018-05-20 00:11:01 -040071
72#include <optional>
73
74namespace nonstd {
75
76 using std::optional;
77 using std::bad_optional_access;
78 using std::hash;
79
80 using std::nullopt;
81 using std::nullopt_t;
82 using std::in_place;
83 using std::in_place_type;
84 using std::in_place_index;
85 using std::in_place_t;
86 using std::in_place_type_t;
87 using std::in_place_index_t;
88
89 using std::operator==;
90 using std::operator!=;
91 using std::operator<;
92 using std::operator<=;
93 using std::operator>;
94 using std::operator>=;
95 using std::make_optional;
96 using std::swap;
97}
98
Davide Pesaventod2c750b2018-09-16 12:48:01 -040099#else // optional_USES_STD_OPTIONAL
Davide Pesavento1fd00242018-05-20 00:11:01 -0400100
101#include <cassert>
102#include <stdexcept>
103#include <utility>
104
105// optional-lite alignment configuration:
106
107#ifndef optional_CONFIG_MAX_ALIGN_HACK
108# define optional_CONFIG_MAX_ALIGN_HACK 0
109#endif
110
111#ifndef optional_CONFIG_ALIGN_AS
112// no default, used in #if defined()
113#endif
114
115#ifndef optional_CONFIG_ALIGN_AS_FALLBACK
116# define optional_CONFIG_ALIGN_AS_FALLBACK double
117#endif
118
119// Compiler warning suppression:
120
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400121#if defined (__clang__)
Davide Pesavento1fd00242018-05-20 00:11:01 -0400122# pragma clang diagnostic push
123# pragma clang diagnostic ignored "-Wundef"
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400124#elif defined (__GNUC__)
Davide Pesavento1fd00242018-05-20 00:11:01 -0400125# pragma GCC diagnostic push
126# pragma GCC diagnostic ignored "-Wundef"
127#endif
128
129// half-open range [lo..hi):
130#define optional_BETWEEN( v, lo, hi ) ( lo <= v && v < hi )
131
132#if defined(_MSC_VER) && !defined(__clang__)
133# define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900)) )
134#else
135# define optional_COMPILER_MSVC_VERSION 0
136#endif
137
138#define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * major + minor ) + patch )
139
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400140#if defined (__GNUC__) && !defined(__clang__)
Davide Pesavento1fd00242018-05-20 00:11:01 -0400141# define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
142#else
143# define optional_COMPILER_GNUC_VERSION 0
144#endif
145
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400146#if defined (__clang__)
Davide Pesavento1fd00242018-05-20 00:11:01 -0400147# define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
148#else
149# define optional_COMPILER_CLANG_VERSION 0
150#endif
151
152#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 )
153# pragma warning( push )
154# pragma warning( disable: 4345 ) // initialization behavior changed
155#endif
156
157#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 )
158# pragma warning( push )
159# pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const'
160#endif
161
162// Presence of language and library features:
163
164#define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE )
165
166// Presence of C++11 language features:
167
168#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 100
169# define optional_HAVE_AUTO 1
170# define optional_HAVE_NULLPTR 1
171# define optional_HAVE_STATIC_ASSERT 1
172#endif
173
174#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 120
175# define optional_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 1
176# define optional_HAVE_INITIALIZER_LIST 1
177#endif
178
179#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 140
180# define optional_HAVE_ALIAS_TEMPLATE 1
181# define optional_HAVE_CONSTEXPR_11 1
182# define optional_HAVE_ENUM_CLASS 1
183# define optional_HAVE_EXPLICIT_CONVERSION 1
184# define optional_HAVE_IS_DEFAULT 1
185# define optional_HAVE_IS_DELETE 1
186# define optional_HAVE_NOEXCEPT 1
187# define optional_HAVE_REF_QUALIFIER 1
188#endif
189
190// Presence of C++14 language features:
191
192#if optional_CPP14_OR_GREATER
193# define optional_HAVE_CONSTEXPR_14 1
194#endif
195
196// Presence of C++17 language features:
197
198#if optional_CPP17_OR_GREATER
199# define optional_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1
200#endif
201
202// Presence of C++ library features:
203
204#if optional_COMPILER_GNUC_VERSION
205# define optional_HAVE_TR1_TYPE_TRAITS 1
206# define optional_HAVE_TR1_ADD_POINTER 1
207#endif
208
209#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 90
210# define optional_HAVE_TYPE_TRAITS 1
211# define optional_HAVE_STD_ADD_POINTER 1
212#endif
213
214#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 110
215# define optional_HAVE_ARRAY 1
216#endif
217
218#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 120
219# define optional_HAVE_CONDITIONAL 1
220#endif
221
222#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 140 || (optional_COMPILER_MSVC_VERSION >= 90 && _HAS_CPP0X)
223# define optional_HAVE_CONTAINER_DATA_METHOD 1
224#endif
225
226#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 120
227# define optional_HAVE_REMOVE_CV 1
228#endif
229
230#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 140
231# define optional_HAVE_SIZED_TYPES 1
232#endif
233
234// For the rest, consider VC14 as C++11 for optional-lite:
235
236#if optional_COMPILER_MSVC_VERSION >= 140
237# undef optional_CPP11_OR_GREATER
238# define optional_CPP11_OR_GREATER 1
239#endif
240
241// C++ feature usage:
242
243#if optional_HAVE( CONSTEXPR_11 )
244# define optional_constexpr constexpr
245#else
246# define optional_constexpr /*constexpr*/
247#endif
248
249#if optional_HAVE( CONSTEXPR_14 )
250# define optional_constexpr14 constexpr
251#else
252# define optional_constexpr14 /*constexpr*/
253#endif
254
255#if optional_HAVE( NOEXCEPT )
256# define optional_noexcept noexcept
257#else
258# define optional_noexcept /*noexcept*/
259#endif
260
261#if optional_HAVE( NULLPTR )
262# define optional_nullptr nullptr
263#else
264# define optional_nullptr NULL
265#endif
266
267#if optional_HAVE( REF_QUALIFIER )
268# define optional_ref_qual &
269# define optional_refref_qual &&
270#else
271# define optional_ref_qual /*&*/
272# define optional_refref_qual /*&&*/
273#endif
274
275// additional includes:
276
277#if optional_CPP11_OR_GREATER
278# include <functional>
279#endif
280
281#if optional_HAVE( INITIALIZER_LIST )
282# include <initializer_list>
283#endif
284
285#if optional_HAVE( TYPE_TRAITS )
286# include <type_traits>
287#elif optional_HAVE( TR1_TYPE_TRAITS )
288# include <tr1/type_traits>
289#endif
290
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400291// Method enabling
Davide Pesavento1fd00242018-05-20 00:11:01 -0400292
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400293#if optional_CPP11_OR_GREATER
Davide Pesavento1fd00242018-05-20 00:11:01 -0400294
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400295# define optional_REQUIRES_T(...) \
296 , typename = typename std::enable_if<__VA_ARGS__>::type
Davide Pesavento1fd00242018-05-20 00:11:01 -0400297
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400298# define optional_REQUIRES_R(R, ...) \
299 typename std::enable_if<__VA_ARGS__, R>::type
300
301# define optional_REQUIRES_A(...) \
302 , typename std::enable_if<__VA_ARGS__, void*>::type = optional_nullptr
303
304#endif
Davide Pesavento1fd00242018-05-20 00:11:01 -0400305
306//
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400307// in_place: code duplicated in any-lite, expected-lite, optional-lite, variant-lite:
Davide Pesavento1fd00242018-05-20 00:11:01 -0400308//
309
310#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400311#define nonstd_lite_HAVE_IN_PLACE_TYPES 1
312
313// C++17 std::in_place in <utility>:
314
315#if optional_CPP17_OR_GREATER
Davide Pesavento1fd00242018-05-20 00:11:01 -0400316
317namespace nonstd {
318
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400319using std::in_place;
320using std::in_place_type;
321using std::in_place_index;
322using std::in_place_t;
323using std::in_place_type_t;
324using std::in_place_index_t;
325
326#define nonstd_lite_in_place_t( T) std::in_place_t
327#define nonstd_lite_in_place_type_t( T) std::in_place_type_t<T>
328#define nonstd_lite_in_place_index_t(T) std::in_place_index_t<I>
329
330#define nonstd_lite_in_place( T) std::in_place_t{}
331#define nonstd_lite_in_place_type( T) std::in_place_type_t<T>{}
332#define nonstd_lite_in_place_index(T) std::in_place_index_t<I>{}
333
334} // namespace nonstd
335
336#else // optional_CPP17_OR_GREATER
337
338namespace nonstd {
Davide Pesavento1fd00242018-05-20 00:11:01 -0400339namespace detail {
340
341template< class T >
342struct in_place_type_tag {};
343
344template< std::size_t I >
345struct in_place_index_tag {};
346
347} // namespace detail
348
349struct in_place_t {};
350
351template< class T >
352inline in_place_t in_place( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
353{
354 return in_place_t();
355}
356
357template< std::size_t I >
358inline in_place_t in_place( detail::in_place_index_tag<I> = detail::in_place_index_tag<I>() )
359{
360 return in_place_t();
361}
362
363template< class T >
364inline in_place_t in_place_type( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
365{
366 return in_place_t();
367}
368
369template< std::size_t I >
370inline in_place_t in_place_index( detail::in_place_index_tag<I> = detail::in_place_index_tag<I>() )
371{
372 return in_place_t();
373}
374
375// mimic templated typedef:
376
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400377#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400378#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
379#define nonstd_lite_in_place_index_t(T) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<I> )
380
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400381#define nonstd_lite_in_place( T) nonstd::in_place_type<T>
382#define nonstd_lite_in_place_type( T) nonstd::in_place_type<T>
383#define nonstd_lite_in_place_index(T) nonstd::in_place_index<I>
Davide Pesavento1fd00242018-05-20 00:11:01 -0400384
385} // namespace nonstd
386
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400387#endif // optional_CPP17_OR_GREATER
Davide Pesavento1fd00242018-05-20 00:11:01 -0400388#endif // nonstd_lite_HAVE_IN_PLACE_TYPES
389
390//
391// optional:
392//
393
394namespace nonstd { namespace optional_lite {
395
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400396namespace detail {
397
398#if optional_HAVE( CONDITIONAL )
399 using std::conditional;
400#else
401 template< bool B, typename T, typename F > struct conditional { typedef T type; };
402 template< typename T, typename F > struct conditional<false, T, F> { typedef F type; };
403#endif // optional_HAVE_CONDITIONAL
404
405} // namespace detail
406
407#if optional_CPP11_OR_GREATER
408
409namespace std20 {
410
411// type traits C++20:
412
413template< typename T >
414struct remove_cvref
415{
416 typedef typename std::remove_cv< typename std::remove_reference<T>::type >::type type;
417};
418
419} // namespace std20
420
421#endif // optional_CPP11_OR_GREATER
422
Davide Pesavento1fd00242018-05-20 00:11:01 -0400423/// class optional
424
425template< typename T >
426class optional;
427
428namespace detail {
429
430// C++11 emulation:
431
432struct nulltype{};
433
434template< typename Head, typename Tail >
435struct typelist
436{
437 typedef Head head;
438 typedef Tail tail;
439};
440
441#if optional_CONFIG_MAX_ALIGN_HACK
442
443// Max align, use most restricted type for alignment:
444
445#define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ )
446#define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line )
447#define optional_UNIQUE3( name, line ) name ## line
448
449#define optional_ALIGN_TYPE( type ) \
450 type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st )
451
452template< typename T >
453struct struct_t { T _; };
454
455union max_align_t
456{
457 optional_ALIGN_TYPE( char );
458 optional_ALIGN_TYPE( short int );
459 optional_ALIGN_TYPE( int );
460 optional_ALIGN_TYPE( long int );
461 optional_ALIGN_TYPE( float );
462 optional_ALIGN_TYPE( double );
463 optional_ALIGN_TYPE( long double );
464 optional_ALIGN_TYPE( char * );
465 optional_ALIGN_TYPE( short int * );
466 optional_ALIGN_TYPE( int * );
467 optional_ALIGN_TYPE( long int * );
468 optional_ALIGN_TYPE( float * );
469 optional_ALIGN_TYPE( double * );
470 optional_ALIGN_TYPE( long double * );
471 optional_ALIGN_TYPE( void * );
472
473#ifdef HAVE_LONG_LONG
474 optional_ALIGN_TYPE( long long );
475#endif
476
477 struct Unknown;
478
479 Unknown ( * optional_UNIQUE(_) )( Unknown );
480 Unknown * Unknown::* optional_UNIQUE(_);
481 Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown );
482
483 struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_);
484 struct_t< Unknown * Unknown::* > optional_UNIQUE(_);
485 struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_);
486};
487
488#undef optional_UNIQUE
489#undef optional_UNIQUE2
490#undef optional_UNIQUE3
491
492#undef optional_ALIGN_TYPE
493
494#elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK
495
496// Use user-specified type for alignment:
497
498#define optional_ALIGN_AS( unused ) \
499 optional_CONFIG_ALIGN_AS
500
501#else // optional_CONFIG_MAX_ALIGN_HACK
502
503// Determine POD type to use for alignment:
504
505#define optional_ALIGN_AS( to_align ) \
506 typename type_of_size< alignment_types, alignment_of< to_align >::value >::type
507
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400508template< typename T >
Davide Pesavento1fd00242018-05-20 00:11:01 -0400509struct alignment_of;
510
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400511template< typename T >
Davide Pesavento1fd00242018-05-20 00:11:01 -0400512struct alignment_of_hack
513{
514 char c;
515 T t;
516 alignment_of_hack();
517};
518
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400519template< size_t A, size_t S >
Davide Pesavento1fd00242018-05-20 00:11:01 -0400520struct alignment_logic
521{
522 enum { value = A < S ? A : S };
523};
524
525template< typename T >
526struct alignment_of
527{
528 enum { value = alignment_logic<
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400529 sizeof( alignment_of_hack<T> ) - sizeof(T), sizeof(T) >::value };
Davide Pesavento1fd00242018-05-20 00:11:01 -0400530};
531
532template< typename List, size_t N >
533struct type_of_size
534{
535 typedef typename conditional<
536 N == sizeof( typename List::head ),
537 typename List::head,
538 typename type_of_size<typename List::tail, N >::type >::type type;
539};
540
541template< size_t N >
542struct type_of_size< nulltype, N >
543{
544 typedef optional_CONFIG_ALIGN_AS_FALLBACK type;
545};
546
547template< typename T>
548struct struct_t { T _; };
549
550#define optional_ALIGN_TYPE( type ) \
551 typelist< type , typelist< struct_t< type >
552
553struct Unknown;
554
555typedef
556 optional_ALIGN_TYPE( char ),
557 optional_ALIGN_TYPE( short ),
558 optional_ALIGN_TYPE( int ),
559 optional_ALIGN_TYPE( long ),
560 optional_ALIGN_TYPE( float ),
561 optional_ALIGN_TYPE( double ),
562 optional_ALIGN_TYPE( long double ),
563
564 optional_ALIGN_TYPE( char *),
565 optional_ALIGN_TYPE( short * ),
566 optional_ALIGN_TYPE( int * ),
567 optional_ALIGN_TYPE( long * ),
568 optional_ALIGN_TYPE( float * ),
569 optional_ALIGN_TYPE( double * ),
570 optional_ALIGN_TYPE( long double * ),
571
572 optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ),
573 optional_ALIGN_TYPE( Unknown * Unknown::* ),
574 optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ),
575
576 nulltype
577 > > > > > > > > > > > > > >
578 > > > > > > > > > > > > > >
579 > > > > > >
580 alignment_types;
581
582#undef optional_ALIGN_TYPE
583
584#endif // optional_CONFIG_MAX_ALIGN_HACK
585
586/// C++03 constructed union to hold value.
587
588template< typename T >
589union storage_t
590{
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400591//private:
592// template< typename > friend class optional;
Davide Pesavento1fd00242018-05-20 00:11:01 -0400593
594 typedef T value_type;
595
596 storage_t() {}
597
598 storage_t( value_type const & v )
599 {
600 construct_value( v );
601 }
602
603 void construct_value( value_type const & v )
604 {
605 ::new( value_ptr() ) value_type( v );
606 }
607
608#if optional_CPP11_OR_GREATER
609
610 storage_t( value_type && v )
611 {
612 construct_value( std::move( v ) );
613 }
614
615 void construct_value( value_type && v )
616 {
617 ::new( value_ptr() ) value_type( std::move( v ) );
618 }
619
Davide Pesaventobc76da12018-07-17 15:20:24 -0400620 template< class... Args >
621 void emplace( Args&&... args )
622 {
623 ::new( value_ptr() ) value_type( std::forward<Args>(args)... );
624 }
625
626 template< class U, class... Args >
627 void emplace( std::initializer_list<U> il, Args&&... args )
628 {
629 ::new( value_ptr() ) value_type( il, std::forward<Args>(args)... );
630 }
631
Davide Pesavento1fd00242018-05-20 00:11:01 -0400632#endif
633
634 void destruct_value()
635 {
636 value_ptr()->~T();
637 }
638
639 value_type const * value_ptr() const
640 {
641 return as<value_type>();
642 }
643
644 value_type * value_ptr()
645 {
646 return as<value_type>();
647 }
648
649 value_type const & value() const optional_ref_qual
650 {
651 return * value_ptr();
652 }
653
654 value_type & value() optional_ref_qual
655 {
656 return * value_ptr();
657 }
658
659#if optional_CPP11_OR_GREATER
660
661 value_type const && value() const optional_refref_qual
662 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400663 return std::move( value() );
Davide Pesavento1fd00242018-05-20 00:11:01 -0400664 }
665
666 value_type && value() optional_refref_qual
667 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400668 return std::move( value() );
Davide Pesavento1fd00242018-05-20 00:11:01 -0400669 }
670
671#endif
672
673#if optional_CPP11_OR_GREATER
674
675 using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type;
676 aligned_storage_t data;
677
678#elif optional_CONFIG_MAX_ALIGN_HACK
679
680 typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t;
681
682 max_align_t hack;
683 aligned_storage_t data;
684
685#else
686 typedef optional_ALIGN_AS(value_type) align_as_type;
687
688 typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t;
689 aligned_storage_t data;
690
691# undef optional_ALIGN_AS
692
693#endif // optional_CONFIG_MAX_ALIGN_HACK
694
695 void * ptr() optional_noexcept
696 {
697 return &data;
698 }
699
700 void const * ptr() const optional_noexcept
701 {
702 return &data;
703 }
704
705 template <typename U>
706 U * as()
707 {
708 return reinterpret_cast<U*>( ptr() );
709 }
710
711 template <typename U>
712 U const * as() const
713 {
714 return reinterpret_cast<U const *>( ptr() );
715 }
716};
717
718} // namespace detail
719
720/// disengaged state tag
721
722struct nullopt_t
723{
724 struct init{};
725 optional_constexpr nullopt_t( init ) {}
726};
727
728#if optional_HAVE( CONSTEXPR_11 )
729constexpr nullopt_t nullopt{ nullopt_t::init{} };
730#else
731// extra parenthesis to prevent the most vexing parse:
732const nullopt_t nullopt(( nullopt_t::init() ));
733#endif
734
735/// optional access error
736
737class bad_optional_access : public std::logic_error
738{
739public:
740 explicit bad_optional_access()
741 : logic_error( "bad optional access" ) {}
742};
743
744/// optional
745
746template< typename T>
747class optional
748{
749private:
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400750 template< typename > friend class optional;
751
Davide Pesavento1fd00242018-05-20 00:11:01 -0400752 typedef void (optional::*safe_bool)() const;
753
754public:
755 typedef T value_type;
756
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400757 // x.x.3.1, constructors
758
759 // 1a - default construct
Davide Pesavento1fd00242018-05-20 00:11:01 -0400760 optional_constexpr optional() optional_noexcept
761 : has_value_( false )
762 , contained()
763 {}
764
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400765 // 1b - construct explicitly empty
Davide Pesavento1fd00242018-05-20 00:11:01 -0400766 optional_constexpr optional( nullopt_t ) optional_noexcept
767 : has_value_( false )
768 , contained()
769 {}
770
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400771 // 2 - copy-construct
772 optional_constexpr14 optional( optional const & other
Davide Pesavento1fd00242018-05-20 00:11:01 -0400773#if optional_CPP11_OR_GREATER
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400774 optional_REQUIRES_A(
775 true || std::is_copy_constructible<T>::value
776 )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400777#endif
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400778 )
779 : has_value_( other.has_value() )
780 {
781 if ( other.has_value() )
782 contained.construct_value( other.contained.value() );
783 }
Davide Pesavento1fd00242018-05-20 00:11:01 -0400784
785#if optional_CPP11_OR_GREATER
786
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400787 // 3 (C++11) - move-construct from optional
788 optional_constexpr14 optional( optional && other
789 optional_REQUIRES_A(
790 true || std::is_move_constructible<T>::value
791 )
792 ) noexcept( std::is_nothrow_move_constructible<T>::value )
793 : has_value_( other.has_value() )
794 {
795 if ( other.has_value() )
796 contained.construct_value( std::move( other.contained.value() ) );
797 }
Davide Pesavento1fd00242018-05-20 00:11:01 -0400798
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400799 // 4 (C++11) - explicit converting copy-construct from optional
800 template< typename U >
801 explicit optional( optional<U> const & other
802 optional_REQUIRES_A(
803 std::is_constructible<T, U const &>::value
804 && !std::is_constructible<T, optional<U> & >::value
805 && !std::is_constructible<T, optional<U> && >::value
806 && !std::is_constructible<T, optional<U> const & >::value
807 && !std::is_constructible<T, optional<U> const && >::value
808 && !std::is_convertible< optional<U> & , T>::value
809 && !std::is_convertible< optional<U> && , T>::value
810 && !std::is_convertible< optional<U> const & , T>::value
811 && !std::is_convertible< optional<U> const &&, T>::value
812 && !std::is_convertible< U const & , T>::value /*=> explicit */
813 )
814 )
815 : has_value_( other.has_value() )
816 {
817 if ( other.has_value() )
818 contained.construct_value( other.contained.value() );
819 }
820#endif // optional_CPP11_OR_GREATER
821
822 // 4 (C++98 and later) - non-explicit converting copy-construct from optional
823 template< typename U >
824 optional( optional<U> const & other
825#if optional_CPP11_OR_GREATER
826 optional_REQUIRES_A(
827 std::is_constructible<T, U const &>::value
828 && !std::is_constructible<T, optional<U> & >::value
829 && !std::is_constructible<T, optional<U> && >::value
830 && !std::is_constructible<T, optional<U> const & >::value
831 && !std::is_constructible<T, optional<U> const && >::value
832 && !std::is_convertible< optional<U> & , T>::value
833 && !std::is_convertible< optional<U> && , T>::value
834 && !std::is_convertible< optional<U> const & , T>::value
835 && !std::is_convertible< optional<U> const &&, T>::value
836 && std::is_convertible< U const & , T>::value /*=> non-explicit */
837 )
838#endif // optional_CPP11_OR_GREATER
839 )
840 : has_value_( other.has_value() )
841 {
842 if ( other.has_value() )
843 contained.construct_value( other.contained.value() );
844 }
845
846#if optional_CPP11_OR_GREATER
847
848 // 5a (C++11) - explicit converting move-construct from optional
849 template< typename U >
850 optional( optional<U> && other
851 optional_REQUIRES_A(
852 std::is_constructible<T, U const &>::value
853 && !std::is_constructible<T, optional<U> & >::value
854 && !std::is_constructible<T, optional<U> && >::value
855 && !std::is_constructible<T, optional<U> const & >::value
856 && !std::is_constructible<T, optional<U> const && >::value
857 && !std::is_convertible< optional<U> & , T>::value
858 && !std::is_convertible< optional<U> && , T>::value
859 && !std::is_convertible< optional<U> const & , T>::value
860 && !std::is_convertible< optional<U> const &&, T>::value
861 && !std::is_convertible< U &&, T>::value /*=> explicit */
862 )
863 )
864 : has_value_( other.has_value() )
865 {
866 if ( other.has_value() )
867 contained.construct_value( std::move( other.contained.value() ) );
868 }
869
870 // 5a (C++11) - non-explicit converting move-construct from optional
871 template< typename U >
872 optional( optional<U> && other
873 optional_REQUIRES_A(
874 std::is_constructible<T, U const &>::value
875 && !std::is_constructible<T, optional<U> & >::value
876 && !std::is_constructible<T, optional<U> && >::value
877 && !std::is_constructible<T, optional<U> const & >::value
878 && !std::is_constructible<T, optional<U> const && >::value
879 && !std::is_convertible< optional<U> & , T>::value
880 && !std::is_convertible< optional<U> && , T>::value
881 && !std::is_convertible< optional<U> const & , T>::value
882 && !std::is_convertible< optional<U> const &&, T>::value
883 && std::is_convertible< U &&, T>::value /*=> non-explicit */
884 )
885 )
886 : has_value_( other.has_value() )
887 {
888 if ( other.has_value() )
889 contained.construct_value( std::move( other.contained.value() ) );
890 }
891
892 // 6 (C++11) - in-place construct
893 template< typename... Args
894 optional_REQUIRES_T(
895 std::is_constructible<T, Args&&...>::value
896 )
897 >
898 optional_constexpr explicit optional( nonstd_lite_in_place_t(T), Args&&... args )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400899 : has_value_( true )
900 , contained( T( std::forward<Args>(args)...) )
901 {}
902
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400903 // 7 (C++11) - in-place construct, initializer-list
904 template< typename U, typename... Args
905 optional_REQUIRES_T(
906 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value
907 )
908 >
909 optional_constexpr explicit optional( nonstd_lite_in_place_t(T), std::initializer_list<U> il, Args&&... args )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400910 : has_value_( true )
911 , contained( T( il, std::forward<Args>(args)...) )
912 {}
913
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400914 // 8a (C++11) - explicit move construct from value
915 template< typename U = value_type >
916 optional_constexpr explicit optional( U && value
917 optional_REQUIRES_A(
918 std::is_constructible<T, U&&>::value
919 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
920 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
921 && !std::is_convertible<U&&, T>::value /*=> explicit */
922 )
923 )
924 : has_value_( true )
925 , contained( std::forward<U>( value ) )
926 {}
927
928 // 8a (C++11) - non-explicit move construct from value
929 template< typename U = value_type >
930 optional_constexpr optional( U && value
931 optional_REQUIRES_A(
932 std::is_constructible<T, U&&>::value
933 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
934 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
935 && std::is_convertible<U&&, T>::value /*=> non-explicit */
936 )
937 )
938 : has_value_( true )
939 , contained( std::forward<U>( value ) )
940 {}
941
942#else // optional_CPP11_OR_GREATER
943
944 // 8 (C++98)
945 optional( value_type const & value )
946 : has_value_( true )
947 , contained( value )
948 {}
949
Davide Pesavento1fd00242018-05-20 00:11:01 -0400950#endif // optional_CPP11_OR_GREATER
951
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400952 // x.x.3.2, destructor
953
Davide Pesavento1fd00242018-05-20 00:11:01 -0400954 ~optional()
955 {
956 if ( has_value() )
957 contained.destruct_value();
958 }
959
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400960 // x.x.3.3, assignment
Davide Pesavento1fd00242018-05-20 00:11:01 -0400961
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400962 // 1 (C++98and later) - assign explicitly empty
Davide Pesavento1fd00242018-05-20 00:11:01 -0400963 optional & operator=( nullopt_t ) optional_noexcept
964 {
965 reset();
966 return *this;
967 }
968
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400969 // 2 (C++98and later) - copy-assign from optional
Davide Pesavento1fd00242018-05-20 00:11:01 -0400970#if optional_CPP11_OR_GREATER
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400971 optional_REQUIRES_R(
972 optional &,
973 true
974// std::is_copy_constructible<T>::value
975// && std::is_copy_assignable<T>::value
976 )
977 operator=( optional const & other )
978 noexcept(
979 std::is_nothrow_move_assignable<T>::value
980 && std::is_nothrow_move_constructible<T>::value
981 )
982#else
983 optional & operator=( optional const & other )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400984#endif
985 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400986 if ( has_value() == true && other.has_value() == false ) reset();
987 else if ( has_value() == false && other.has_value() == true ) initialize( *other );
988 else if ( has_value() == true && other.has_value() == true ) contained.value() = *other;
Davide Pesavento1fd00242018-05-20 00:11:01 -0400989 return *this;
990 }
991
992#if optional_CPP11_OR_GREATER
993
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400994 // 3 (C++11) - move-assign from optional
995 optional_REQUIRES_R(
996 optional &,
997 true
998// std::is_move_constructible<T>::value
999// && std::is_move_assignable<T>::value
1000 )
1001 operator=( optional && other ) noexcept
Davide Pesavento1fd00242018-05-20 00:11:01 -04001002 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001003 if ( has_value() == true && other.has_value() == false ) reset();
1004 else if ( has_value() == false && other.has_value() == true ) initialize( std::move( *other ) );
1005 else if ( has_value() == true && other.has_value() == true ) contained.value() = std::move( *other );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001006 return *this;
1007 }
1008
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001009 // 4 (C++11) - move-assign from value
1010 template< typename U = T >
1011 optional_REQUIRES_R(
1012 optional &,
1013 std::is_constructible<T , U>::value
1014 && std::is_assignable<T&, U>::value
1015 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
1016 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
1017// && !(std::is_scalar<T>::value && std::is_same<T, typename std::decay<U>::type>::value)
1018 )
1019 operator=( U && value )
Davide Pesavento1fd00242018-05-20 00:11:01 -04001020 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001021 if ( has_value() ) contained.value() = std::forward<U>( value );
1022 else initialize( T( std::forward<U>( value ) ) );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001023 return *this;
1024 }
1025
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001026#else // optional_CPP11_OR_GREATER
Davide Pesavento1fd00242018-05-20 00:11:01 -04001027
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001028 // 4 (C++98) - copy-assign from value
1029 template< typename U /*= T*/ >
1030 optional & operator=( U const & value )
Davide Pesavento1fd00242018-05-20 00:11:01 -04001031 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001032 if ( has_value() ) contained.value() = value;
1033 else initialize( T( value ) );
1034 return *this;
Davide Pesavento1fd00242018-05-20 00:11:01 -04001035 }
1036
1037#endif // optional_CPP11_OR_GREATER
1038
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001039 // 5 (C++98 and later) - converting copy-assign from optional
1040 template< typename U >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001041#if optional_CPP11_OR_GREATER
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001042 optional_REQUIRES_R(
1043 optional&,
1044 std::is_constructible< T , U const &>::value
1045 && std::is_assignable< T&, U const &>::value
1046 && !std::is_constructible<T, optional<U> & >::value
1047 && !std::is_constructible<T, optional<U> && >::value
1048 && !std::is_constructible<T, optional<U> const & >::value
1049 && !std::is_constructible<T, optional<U> const && >::value
1050 && !std::is_convertible< optional<U> & , T>::value
1051 && !std::is_convertible< optional<U> && , T>::value
1052 && !std::is_convertible< optional<U> const & , T>::value
1053 && !std::is_convertible< optional<U> const &&, T>::value
1054 && !std::is_assignable< T&, optional<U> & >::value
1055 && !std::is_assignable< T&, optional<U> && >::value
1056 && !std::is_assignable< T&, optional<U> const & >::value
1057 && !std::is_assignable< T&, optional<U> const && >::value
1058 )
1059#else
1060 optional&
1061#endif // optional_CPP11_OR_GREATER
1062 operator=( optional<U> const & other )
1063 {
1064 return *this = optional( other );
1065 }
1066
1067#if optional_CPP11_OR_GREATER
1068
1069 // 6 (C++11) - converting move-assign from optional
1070 template< typename U >
1071 optional_REQUIRES_R(
1072 optional&,
1073 std::is_constructible< T , U>::value
1074 && std::is_assignable< T&, U>::value
1075 && !std::is_constructible<T, optional<U> & >::value
1076 && !std::is_constructible<T, optional<U> && >::value
1077 && !std::is_constructible<T, optional<U> const & >::value
1078 && !std::is_constructible<T, optional<U> const && >::value
1079 && !std::is_convertible< optional<U> & , T>::value
1080 && !std::is_convertible< optional<U> && , T>::value
1081 && !std::is_convertible< optional<U> const & , T>::value
1082 && !std::is_convertible< optional<U> const &&, T>::value
1083 && !std::is_assignable< T&, optional<U> & >::value
1084 && !std::is_assignable< T&, optional<U> && >::value
1085 && !std::is_assignable< T&, optional<U> const & >::value
1086 && !std::is_assignable< T&, optional<U> const && >::value
1087 )
1088 operator=( optional<U> && other )
1089 {
1090 return *this = optional( std::move( other ) );
1091 }
1092
1093 // 7 (C++11) - emplace
1094 template< typename... Args
1095 optional_REQUIRES_T(
1096 std::is_constructible<T, Args&&...>::value
1097 )
1098 >
1099 T& emplace( Args&&... args )
1100 {
1101 *this = nullopt;
1102 contained.emplace( std::forward<Args>(args)... );
1103 has_value_ = true;
1104 return contained.value();
1105 }
1106
1107 // 8 (C++11) - emplace, initializer-list
1108 template< typename U, typename... Args
1109 optional_REQUIRES_T(
1110 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value
1111 )
1112 >
1113 T& emplace( std::initializer_list<U> il, Args&&... args )
1114 {
1115 *this = nullopt;
1116 contained.emplace( il, std::forward<Args>(args)... );
1117 has_value_ = true;
1118 return contained.value();
1119 }
1120
1121#endif // optional_CPP11_OR_GREATER
1122
1123 // x.x.3.4, swap
1124
1125 void swap( optional & other )
1126#if optional_CPP11_OR_GREATER
1127 noexcept(
1128 std::is_nothrow_move_constructible<T>::value
1129 && noexcept( std::swap( std::declval<T&>(), std::declval<T&>() ) )
1130 )
Davide Pesavento1fd00242018-05-20 00:11:01 -04001131#endif
1132 {
1133 using std::swap;
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001134 if ( has_value() == true && other.has_value() == true ) { swap( **this, *other ); }
1135 else if ( has_value() == false && other.has_value() == true ) { initialize( *other ); other.reset(); }
1136 else if ( has_value() == true && other.has_value() == false ) { other.initialize( **this ); reset(); }
Davide Pesavento1fd00242018-05-20 00:11:01 -04001137 }
1138
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001139 // x.x.3.5, observers
Davide Pesavento1fd00242018-05-20 00:11:01 -04001140
1141 optional_constexpr value_type const * operator ->() const
1142 {
1143 return assert( has_value() ),
1144 contained.value_ptr();
1145 }
1146
1147 optional_constexpr14 value_type * operator ->()
1148 {
1149 return assert( has_value() ),
1150 contained.value_ptr();
1151 }
1152
1153 optional_constexpr value_type const & operator *() const optional_ref_qual
1154 {
1155 return assert( has_value() ),
1156 contained.value();
1157 }
1158
1159 optional_constexpr14 value_type & operator *() optional_ref_qual
1160 {
1161 return assert( has_value() ),
1162 contained.value();
1163 }
1164
1165#if optional_CPP11_OR_GREATER
1166
1167 optional_constexpr value_type const && operator *() const optional_refref_qual
1168 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001169 return std::move( **this );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001170 }
1171
1172 optional_constexpr14 value_type && operator *() optional_refref_qual
1173 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001174 return std::move( **this );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001175 }
1176
1177#endif
1178
1179#if optional_CPP11_OR_GREATER
1180 optional_constexpr explicit operator bool() const optional_noexcept
1181 {
1182 return has_value();
1183 }
1184#else
1185 optional_constexpr operator safe_bool() const optional_noexcept
1186 {
1187 return has_value() ? &optional::this_type_does_not_support_comparisons : 0;
1188 }
1189#endif
1190
1191 optional_constexpr bool has_value() const optional_noexcept
1192 {
1193 return has_value_;
1194 }
1195
1196 optional_constexpr14 value_type const & value() const optional_ref_qual
1197 {
1198 if ( ! has_value() )
1199 throw bad_optional_access();
1200
1201 return contained.value();
1202 }
1203
1204 optional_constexpr14 value_type & value() optional_ref_qual
1205 {
1206 if ( ! has_value() )
1207 throw bad_optional_access();
1208
1209 return contained.value();
1210 }
1211
1212#if optional_HAVE( REF_QUALIFIER )
1213
1214 optional_constexpr14 value_type const && value() const optional_refref_qual
1215 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001216 return std::move( value() );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001217 }
1218
1219 optional_constexpr14 value_type && value() optional_refref_qual
1220 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001221 return std::move( value() );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001222 }
1223
1224#endif
1225
1226#if optional_CPP11_OR_GREATER
1227
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001228 template< typename U >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001229 optional_constexpr value_type value_or( U && v ) const optional_ref_qual
1230 {
1231 return has_value() ? contained.value() : static_cast<T>(std::forward<U>( v ) );
1232 }
1233
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001234 template< typename U >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001235 optional_constexpr value_type value_or( U && v ) const optional_refref_qual
1236 {
1237 return has_value() ? std::move( contained.value() ) : static_cast<T>(std::forward<U>( v ) );
1238 }
1239
1240#else
1241
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001242 template< typename U >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001243 optional_constexpr value_type value_or( U const & v ) const
1244 {
1245 return has_value() ? contained.value() : static_cast<value_type>( v );
1246 }
1247
1248#endif // optional_CPP11_OR_GREATER
1249
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001250 // x.x.3.6, modifiers
Davide Pesavento1fd00242018-05-20 00:11:01 -04001251
1252 void reset() optional_noexcept
1253 {
1254 if ( has_value() )
1255 contained.destruct_value();
1256
1257 has_value_ = false;
1258 }
1259
1260private:
1261 void this_type_does_not_support_comparisons() const {}
1262
1263 template< typename V >
1264 void initialize( V const & value )
1265 {
1266 assert( ! has_value() );
1267 contained.construct_value( value );
1268 has_value_ = true;
1269 }
1270
1271#if optional_CPP11_OR_GREATER
1272 template< typename V >
1273 void initialize( V && value )
1274 {
1275 assert( ! has_value() );
1276 contained.construct_value( std::move( value ) );
1277 has_value_ = true;
1278 }
Davide Pesaventobc76da12018-07-17 15:20:24 -04001279
Davide Pesavento1fd00242018-05-20 00:11:01 -04001280#endif
1281
1282private:
1283 bool has_value_;
1284 detail::storage_t< value_type > contained;
1285
1286};
1287
1288// Relational operators
1289
1290template< typename T, typename U >
1291inline optional_constexpr bool operator==( optional<T> const & x, optional<U> const & y )
1292{
1293 return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y;
1294}
1295
1296template< typename T, typename U >
1297inline optional_constexpr bool operator!=( optional<T> const & x, optional<U> const & y )
1298{
1299 return !(x == y);
1300}
1301
1302template< typename T, typename U >
1303inline optional_constexpr bool operator<( optional<T> const & x, optional<U> const & y )
1304{
1305 return (!y) ? false : (!x) ? true : *x < *y;
1306}
1307
1308template< typename T, typename U >
1309inline optional_constexpr bool operator>( optional<T> const & x, optional<U> const & y )
1310{
1311 return (y < x);
1312}
1313
1314template< typename T, typename U >
1315inline optional_constexpr bool operator<=( optional<T> const & x, optional<U> const & y )
1316{
1317 return !(y < x);
1318}
1319
1320template< typename T, typename U >
1321inline optional_constexpr bool operator>=( optional<T> const & x, optional<U> const & y )
1322{
1323 return !(x < y);
1324}
1325
1326// Comparison with nullopt
1327
1328template< typename T >
1329inline optional_constexpr bool operator==( optional<T> const & x, nullopt_t ) optional_noexcept
1330{
1331 return (!x);
1332}
1333
1334template< typename T >
1335inline optional_constexpr bool operator==( nullopt_t, optional<T> const & x ) optional_noexcept
1336{
1337 return (!x);
1338}
1339
1340template< typename T >
1341inline optional_constexpr bool operator!=( optional<T> const & x, nullopt_t ) optional_noexcept
1342{
1343 return bool(x);
1344}
1345
1346template< typename T >
1347inline optional_constexpr bool operator!=( nullopt_t, optional<T> const & x ) optional_noexcept
1348{
1349 return bool(x);
1350}
1351
1352template< typename T >
1353inline optional_constexpr bool operator<( optional<T> const &, nullopt_t ) optional_noexcept
1354{
1355 return false;
1356}
1357
1358template< typename T >
1359inline optional_constexpr bool operator<( nullopt_t, optional<T> const & x ) optional_noexcept
1360{
1361 return bool(x);
1362}
1363
1364template< typename T >
1365inline optional_constexpr bool operator<=( optional<T> const & x, nullopt_t ) optional_noexcept
1366{
1367 return (!x);
1368}
1369
1370template< typename T >
1371inline optional_constexpr bool operator<=( nullopt_t, optional<T> const & ) optional_noexcept
1372{
1373 return true;
1374}
1375
1376template< typename T >
1377inline optional_constexpr bool operator>( optional<T> const & x, nullopt_t ) optional_noexcept
1378{
1379 return bool(x);
1380}
1381
1382template< typename T >
1383inline optional_constexpr bool operator>( nullopt_t, optional<T> const & ) optional_noexcept
1384{
1385 return false;
1386}
1387
1388template< typename T >
1389inline optional_constexpr bool operator>=( optional<T> const &, nullopt_t ) optional_noexcept
1390{
1391 return true;
1392}
1393
1394template< typename T >
1395inline optional_constexpr bool operator>=( nullopt_t, optional<T> const & x ) optional_noexcept
1396{
1397 return (!x);
1398}
1399
1400// Comparison with T
1401
1402template< typename T, typename U >
1403inline optional_constexpr bool operator==( optional<T> const & x, U const & v )
1404{
1405 return bool(x) ? *x == v : false;
1406}
1407
1408template< typename T, typename U >
1409inline optional_constexpr bool operator==( U const & v, optional<T> const & x )
1410{
1411 return bool(x) ? v == *x : false;
1412}
1413
1414template< typename T, typename U >
1415inline optional_constexpr bool operator!=( optional<T> const & x, U const & v )
1416{
1417 return bool(x) ? *x != v : true;
1418}
1419
1420template< typename T, typename U >
1421inline optional_constexpr bool operator!=( U const & v, optional<T> const & x )
1422{
1423 return bool(x) ? v != *x : true;
1424}
1425
1426template< typename T, typename U >
1427inline optional_constexpr bool operator<( optional<T> const & x, U const & v )
1428{
1429 return bool(x) ? *x < v : true;
1430}
1431
1432template< typename T, typename U >
1433inline optional_constexpr bool operator<( U const & v, optional<T> const & x )
1434{
1435 return bool(x) ? v < *x : false;
1436}
1437
1438template< typename T, typename U >
1439inline optional_constexpr bool operator<=( optional<T> const & x, U const & v )
1440{
1441 return bool(x) ? *x <= v : true;
1442}
1443
1444template< typename T, typename U >
1445inline optional_constexpr bool operator<=( U const & v, optional<T> const & x )
1446{
1447 return bool(x) ? v <= *x : false;
1448}
1449
1450template< typename T, typename U >
1451inline optional_constexpr bool operator>( optional<T> const & x, U const & v )
1452{
1453 return bool(x) ? *x > v : false;
1454}
1455
1456template< typename T, typename U >
1457inline optional_constexpr bool operator>( U const & v, optional<T> const & x )
1458{
1459 return bool(x) ? v > *x : true;
1460}
1461
1462template< typename T, typename U >
1463inline optional_constexpr bool operator>=( optional<T> const & x, U const & v )
1464{
1465 return bool(x) ? *x >= v : false;
1466}
1467
1468template< typename T, typename U >
1469inline optional_constexpr bool operator>=( U const & v, optional<T> const & x )
1470{
1471 return bool(x) ? v >= *x : true;
1472}
1473
1474// Specialized algorithms
1475
1476template< typename T >
1477void swap( optional<T> & x, optional<T> & y )
1478#if optional_CPP11_OR_GREATER
1479 noexcept( noexcept( x.swap(y) ) )
1480#endif
1481{
1482 x.swap( y );
1483}
1484
1485#if optional_CPP11_OR_GREATER
1486
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001487template< typename T >
1488optional_constexpr optional< typename std::decay<T>::type > make_optional( T && value )
Davide Pesavento1fd00242018-05-20 00:11:01 -04001489{
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001490 return optional< typename std::decay<T>::type >( std::forward<T>( value ) );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001491}
1492
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001493template< typename T, typename...Args >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001494optional_constexpr optional<T> make_optional( Args&&... args )
1495{
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001496 return optional<T>( nonstd_lite_in_place(T), std::forward<Args>(args)...);
Davide Pesavento1fd00242018-05-20 00:11:01 -04001497}
1498
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001499template< typename T, typename U, typename... Args >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001500optional_constexpr optional<T> make_optional( std::initializer_list<U> il, Args&&... args )
1501{
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001502 return optional<T>( nonstd_lite_in_place(T), il, std::forward<Args>(args)...);
Davide Pesavento1fd00242018-05-20 00:11:01 -04001503}
1504
1505#else
1506
1507template< typename T >
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001508optional<T> make_optional( T const & value )
Davide Pesavento1fd00242018-05-20 00:11:01 -04001509{
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001510 return optional<T>( value );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001511}
1512
1513#endif // optional_CPP11_OR_GREATER
1514
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001515} // namespace optional_lite
Davide Pesavento1fd00242018-05-20 00:11:01 -04001516
1517using namespace optional_lite;
1518
1519} // namespace nonstd
1520
1521#if optional_CPP11_OR_GREATER
1522
1523// specialize the std::hash algorithm:
1524
1525namespace std {
1526
1527template< class T >
1528struct hash< nonstd::optional<T> >
1529{
1530public:
1531 std::size_t operator()( nonstd::optional<T> const & v ) const optional_noexcept
1532 {
1533 return bool( v ) ? hash<T>()( *v ) : 0;
1534 }
1535};
1536
1537} //namespace std
1538
1539#endif // optional_CPP11_OR_GREATER
1540
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001541#if defined (__clang__)
Davide Pesavento1fd00242018-05-20 00:11:01 -04001542# pragma clang diagnostic pop
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001543#elif defined (__GNUC__)
Davide Pesavento1fd00242018-05-20 00:11:01 -04001544# pragma GCC diagnostic pop
1545#endif
1546
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001547#endif // optional_USES_STD_OPTIONAL
Davide Pesavento1fd00242018-05-20 00:11:01 -04001548
1549#endif // NONSTD_OPTIONAL_LITE_HPP