blob: c7a6554972beaac55e4d9d9c785c10ec76bdb85a [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
Davide Pesavento17b61b42018-11-21 23:10:48 -050016#define optional_lite_PATCH 1
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
Davide Pesavento17b61b42018-11-21 23:10:48 -050037# if defined(_MSVC_LANG ) && !defined(__clang__)
Davide Pesaventod2c750b2018-09-16 12:48:01 -040038# 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 )
Davide Pesavento17b61b42018-11-21 23:10:48 -050046#define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L )
Davide Pesaventod2c750b2018-09-16 12:48:01 -040047#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L )
48#define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L )
49#define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L )
Davide Pesavento1fd00242018-05-20 00:11:01 -040050
Davide Pesaventod2c750b2018-09-16 12:48:01 -040051// C++ language version (represent 98 as 3):
52
53#define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) )
54
55// Use C++17 std::optional if available and requested:
56
57#if optional_CPP17_OR_GREATER && defined(__has_include )
58# if __has_include( <optional> )
59# define optional_HAVE_STD_OPTIONAL 1
60# else
61# define optional_HAVE_STD_OPTIONAL 0
62# endif
63#else
64# define optional_HAVE_STD_OPTIONAL 0
65#endif
66
67#define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) )
68
Davide Pesavento17b61b42018-11-21 23:10:48 -050069//
70// in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite:
71//
72
73#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
74#define nonstd_lite_HAVE_IN_PLACE_TYPES 1
75
76// C++17 std::in_place in <utility>:
77
78#if optional_CPP17_OR_GREATER
79
80#include <utility>
81
82namespace nonstd {
83
84using std::in_place;
85using std::in_place_type;
86using std::in_place_index;
87using std::in_place_t;
88using std::in_place_type_t;
89using std::in_place_index_t;
90
91#define nonstd_lite_in_place_t( T) std::in_place_t
92#define nonstd_lite_in_place_type_t( T) std::in_place_type_t<T>
93#define nonstd_lite_in_place_index_t(K) std::in_place_index_t<K>
94
95#define nonstd_lite_in_place( T) std::in_place_t{}
96#define nonstd_lite_in_place_type( T) std::in_place_type_t<T>{}
97#define nonstd_lite_in_place_index(K) std::in_place_index_t<K>{}
98
99} // namespace nonstd
100
101#else // optional_CPP17_OR_GREATER
102
103#include <cstddef>
104
105namespace nonstd {
106namespace detail {
107
108template< class T >
109struct in_place_type_tag {};
110
111template< std::size_t K >
112struct in_place_index_tag {};
113
114} // namespace detail
115
116struct in_place_t {};
117
118template< class T >
119inline in_place_t in_place( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
120{
121 return in_place_t();
122}
123
124template< std::size_t K >
125inline in_place_t in_place( detail::in_place_index_tag<K> = detail::in_place_index_tag<K>() )
126{
127 return in_place_t();
128}
129
130template< class T >
131inline in_place_t in_place_type( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
132{
133 return in_place_t();
134}
135
136template< std::size_t K >
137inline in_place_t in_place_index( detail::in_place_index_tag<K> = detail::in_place_index_tag<K>() )
138{
139 return in_place_t();
140}
141
142// mimic templated typedef:
143
144#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
145#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
146#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<K> )
147
148#define nonstd_lite_in_place( T) nonstd::in_place_type<T>
149#define nonstd_lite_in_place_type( T) nonstd::in_place_type<T>
150#define nonstd_lite_in_place_index(K) nonstd::in_place_index<K>
151
152} // namespace nonstd
153
154#endif // optional_CPP17_OR_GREATER
155#endif // nonstd_lite_HAVE_IN_PLACE_TYPES
156
157//
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400158// Using std::optional:
Davide Pesavento17b61b42018-11-21 23:10:48 -0500159//
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400160
161#if optional_USES_STD_OPTIONAL
Davide Pesavento1fd00242018-05-20 00:11:01 -0400162
163#include <optional>
164
165namespace nonstd {
166
167 using std::optional;
168 using std::bad_optional_access;
169 using std::hash;
170
171 using std::nullopt;
172 using std::nullopt_t;
Davide Pesavento1fd00242018-05-20 00:11:01 -0400173
174 using std::operator==;
175 using std::operator!=;
176 using std::operator<;
177 using std::operator<=;
178 using std::operator>;
179 using std::operator>=;
180 using std::make_optional;
181 using std::swap;
182}
183
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400184#else // optional_USES_STD_OPTIONAL
Davide Pesavento1fd00242018-05-20 00:11:01 -0400185
186#include <cassert>
187#include <stdexcept>
188#include <utility>
189
190// optional-lite alignment configuration:
191
192#ifndef optional_CONFIG_MAX_ALIGN_HACK
193# define optional_CONFIG_MAX_ALIGN_HACK 0
194#endif
195
196#ifndef optional_CONFIG_ALIGN_AS
197// no default, used in #if defined()
198#endif
199
200#ifndef optional_CONFIG_ALIGN_AS_FALLBACK
201# define optional_CONFIG_ALIGN_AS_FALLBACK double
202#endif
203
204// Compiler warning suppression:
205
Davide Pesavento17b61b42018-11-21 23:10:48 -0500206#if defined(__clang__)
Davide Pesavento1fd00242018-05-20 00:11:01 -0400207# pragma clang diagnostic push
208# pragma clang diagnostic ignored "-Wundef"
Davide Pesavento17b61b42018-11-21 23:10:48 -0500209#elif defined(__GNUC__)
Davide Pesavento1fd00242018-05-20 00:11:01 -0400210# pragma GCC diagnostic push
211# pragma GCC diagnostic ignored "-Wundef"
212#endif
213
214// half-open range [lo..hi):
Davide Pesavento17b61b42018-11-21 23:10:48 -0500215#define optional_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400216
Davide Pesavento17b61b42018-11-21 23:10:48 -0500217// Compiler versions:
218//
219// MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0)
220// MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002)
221// MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003)
222// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005)
223// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008)
224// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
225// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
226// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
227// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
228// MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017)
229
230#if defined(_MSC_VER ) && !defined(__clang__)
231# define optional_COMPILER_MSVC_VER (_MSC_VER )
232# define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400233#else
Davide Pesavento17b61b42018-11-21 23:10:48 -0500234# define optional_COMPILER_MSVC_VER 0
235# define optional_COMPILER_MSVC_VERSION 0
Davide Pesavento1fd00242018-05-20 00:11:01 -0400236#endif
237
238#define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * major + minor ) + patch )
239
Davide Pesavento17b61b42018-11-21 23:10:48 -0500240#if defined(__GNUC__) && !defined(__clang__)
Davide Pesavento1fd00242018-05-20 00:11:01 -0400241# define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
242#else
243# define optional_COMPILER_GNUC_VERSION 0
244#endif
245
Davide Pesavento17b61b42018-11-21 23:10:48 -0500246#if defined(__clang__)
Davide Pesavento1fd00242018-05-20 00:11:01 -0400247# define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
248#else
249# define optional_COMPILER_CLANG_VERSION 0
250#endif
251
252#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 )
253# pragma warning( push )
254# pragma warning( disable: 4345 ) // initialization behavior changed
255#endif
256
257#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 )
258# pragma warning( push )
259# pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const'
260#endif
261
262// Presence of language and library features:
263
264#define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE )
265
Davide Pesavento17b61b42018-11-21 23:10:48 -0500266#ifdef _HAS_CPP0X
267# define optional_HAS_CPP0X _HAS_CPP0X
268#else
269# define optional_HAS_CPP0X 0
Davide Pesavento1fd00242018-05-20 00:11:01 -0400270#endif
271
Davide Pesavento17b61b42018-11-21 23:10:48 -0500272// Unless defined otherwise below, consider VC14 as C++11 for optional-lite:
Davide Pesavento1fd00242018-05-20 00:11:01 -0400273
Davide Pesavento17b61b42018-11-21 23:10:48 -0500274#if optional_COMPILER_MSVC_VER >= 1900
Davide Pesavento1fd00242018-05-20 00:11:01 -0400275# undef optional_CPP11_OR_GREATER
276# define optional_CPP11_OR_GREATER 1
277#endif
278
Davide Pesavento17b61b42018-11-21 23:10:48 -0500279#define optional_CPP11_90 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1500)
280#define optional_CPP11_100 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1600)
281#define optional_CPP11_110 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1700)
282#define optional_CPP11_120 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1800)
283#define optional_CPP11_140 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1900)
284#define optional_CPP11_141 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1910)
285
286#define optional_CPP14_000 (optional_CPP14_OR_GREATER)
287#define optional_CPP17_000 (optional_CPP17_OR_GREATER)
288
289// Presence of C++11 language features:
290
291#define optional_HAVE_CONSTEXPR_11 optional_CPP11_140
292#define optional_HAVE_NOEXCEPT optional_CPP11_140
293#define optional_HAVE_NULLPTR optional_CPP11_100
294#define optional_HAVE_REF_QUALIFIER optional_CPP11_140
295
296// Presence of C++14 language features:
297
298#define optional_HAVE_CONSTEXPR_14 optional_CPP14_000
299
300// Presence of C++17 language features:
301
302// no flag
303
304// Presence of C++ library features:
305
306#define optional_HAVE_CONDITIONAL optional_CPP11_120
307#define optional_HAVE_REMOVE_CV optional_CPP11_120
308#define optional_HAVE_TYPE_TRAITS optional_CPP11_90
309
310#define optional_HAVE_TR1_TYPE_TRAITS (!! optional_COMPILER_GNUC_VERSION )
311#define optional_HAVE_TR1_ADD_POINTER (!! optional_COMPILER_GNUC_VERSION )
312
Davide Pesavento1fd00242018-05-20 00:11:01 -0400313// C++ feature usage:
314
315#if optional_HAVE( CONSTEXPR_11 )
316# define optional_constexpr constexpr
317#else
318# define optional_constexpr /*constexpr*/
319#endif
320
321#if optional_HAVE( CONSTEXPR_14 )
322# define optional_constexpr14 constexpr
323#else
324# define optional_constexpr14 /*constexpr*/
325#endif
326
327#if optional_HAVE( NOEXCEPT )
328# define optional_noexcept noexcept
329#else
330# define optional_noexcept /*noexcept*/
331#endif
332
333#if optional_HAVE( NULLPTR )
334# define optional_nullptr nullptr
335#else
336# define optional_nullptr NULL
337#endif
338
339#if optional_HAVE( REF_QUALIFIER )
340# define optional_ref_qual &
341# define optional_refref_qual &&
342#else
343# define optional_ref_qual /*&*/
344# define optional_refref_qual /*&&*/
345#endif
346
347// additional includes:
348
349#if optional_CPP11_OR_GREATER
350# include <functional>
351#endif
352
353#if optional_HAVE( INITIALIZER_LIST )
354# include <initializer_list>
355#endif
356
357#if optional_HAVE( TYPE_TRAITS )
358# include <type_traits>
359#elif optional_HAVE( TR1_TYPE_TRAITS )
360# include <tr1/type_traits>
361#endif
362
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400363// Method enabling
Davide Pesavento1fd00242018-05-20 00:11:01 -0400364
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400365#if optional_CPP11_OR_GREATER
Davide Pesavento1fd00242018-05-20 00:11:01 -0400366
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400367# define optional_REQUIRES_T(...) \
368 , typename = typename std::enable_if<__VA_ARGS__>::type
Davide Pesavento1fd00242018-05-20 00:11:01 -0400369
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400370# define optional_REQUIRES_R(R, ...) \
371 typename std::enable_if<__VA_ARGS__, R>::type
372
373# define optional_REQUIRES_A(...) \
374 , typename std::enable_if<__VA_ARGS__, void*>::type = optional_nullptr
375
376#endif
Davide Pesavento1fd00242018-05-20 00:11:01 -0400377
378//
Davide Pesavento1fd00242018-05-20 00:11:01 -0400379// optional:
380//
381
382namespace nonstd { namespace optional_lite {
383
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400384namespace detail {
385
386#if optional_HAVE( CONDITIONAL )
387 using std::conditional;
388#else
389 template< bool B, typename T, typename F > struct conditional { typedef T type; };
390 template< typename T, typename F > struct conditional<false, T, F> { typedef F type; };
391#endif // optional_HAVE_CONDITIONAL
392
393} // namespace detail
394
395#if optional_CPP11_OR_GREATER
396
397namespace std20 {
398
399// type traits C++20:
400
401template< typename T >
402struct remove_cvref
403{
404 typedef typename std::remove_cv< typename std::remove_reference<T>::type >::type type;
405};
406
407} // namespace std20
408
409#endif // optional_CPP11_OR_GREATER
410
Davide Pesavento1fd00242018-05-20 00:11:01 -0400411/// class optional
412
413template< typename T >
414class optional;
415
416namespace detail {
417
418// C++11 emulation:
419
420struct nulltype{};
421
422template< typename Head, typename Tail >
423struct typelist
424{
425 typedef Head head;
426 typedef Tail tail;
427};
428
429#if optional_CONFIG_MAX_ALIGN_HACK
430
431// Max align, use most restricted type for alignment:
432
433#define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ )
434#define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line )
435#define optional_UNIQUE3( name, line ) name ## line
436
437#define optional_ALIGN_TYPE( type ) \
438 type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st )
439
440template< typename T >
441struct struct_t { T _; };
442
443union max_align_t
444{
445 optional_ALIGN_TYPE( char );
446 optional_ALIGN_TYPE( short int );
447 optional_ALIGN_TYPE( int );
448 optional_ALIGN_TYPE( long int );
449 optional_ALIGN_TYPE( float );
450 optional_ALIGN_TYPE( double );
451 optional_ALIGN_TYPE( long double );
452 optional_ALIGN_TYPE( char * );
453 optional_ALIGN_TYPE( short int * );
454 optional_ALIGN_TYPE( int * );
455 optional_ALIGN_TYPE( long int * );
456 optional_ALIGN_TYPE( float * );
457 optional_ALIGN_TYPE( double * );
458 optional_ALIGN_TYPE( long double * );
459 optional_ALIGN_TYPE( void * );
460
461#ifdef HAVE_LONG_LONG
462 optional_ALIGN_TYPE( long long );
463#endif
464
465 struct Unknown;
466
467 Unknown ( * optional_UNIQUE(_) )( Unknown );
468 Unknown * Unknown::* optional_UNIQUE(_);
469 Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown );
470
471 struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_);
472 struct_t< Unknown * Unknown::* > optional_UNIQUE(_);
473 struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_);
474};
475
476#undef optional_UNIQUE
477#undef optional_UNIQUE2
478#undef optional_UNIQUE3
479
480#undef optional_ALIGN_TYPE
481
482#elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK
483
484// Use user-specified type for alignment:
485
486#define optional_ALIGN_AS( unused ) \
487 optional_CONFIG_ALIGN_AS
488
489#else // optional_CONFIG_MAX_ALIGN_HACK
490
491// Determine POD type to use for alignment:
492
493#define optional_ALIGN_AS( to_align ) \
494 typename type_of_size< alignment_types, alignment_of< to_align >::value >::type
495
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400496template< typename T >
Davide Pesavento1fd00242018-05-20 00:11:01 -0400497struct alignment_of;
498
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400499template< typename T >
Davide Pesavento1fd00242018-05-20 00:11:01 -0400500struct alignment_of_hack
501{
502 char c;
503 T t;
504 alignment_of_hack();
505};
506
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400507template< size_t A, size_t S >
Davide Pesavento1fd00242018-05-20 00:11:01 -0400508struct alignment_logic
509{
510 enum { value = A < S ? A : S };
511};
512
513template< typename T >
514struct alignment_of
515{
516 enum { value = alignment_logic<
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400517 sizeof( alignment_of_hack<T> ) - sizeof(T), sizeof(T) >::value };
Davide Pesavento1fd00242018-05-20 00:11:01 -0400518};
519
520template< typename List, size_t N >
521struct type_of_size
522{
523 typedef typename conditional<
524 N == sizeof( typename List::head ),
525 typename List::head,
526 typename type_of_size<typename List::tail, N >::type >::type type;
527};
528
529template< size_t N >
530struct type_of_size< nulltype, N >
531{
532 typedef optional_CONFIG_ALIGN_AS_FALLBACK type;
533};
534
535template< typename T>
536struct struct_t { T _; };
537
538#define optional_ALIGN_TYPE( type ) \
539 typelist< type , typelist< struct_t< type >
540
541struct Unknown;
542
543typedef
544 optional_ALIGN_TYPE( char ),
545 optional_ALIGN_TYPE( short ),
546 optional_ALIGN_TYPE( int ),
547 optional_ALIGN_TYPE( long ),
548 optional_ALIGN_TYPE( float ),
549 optional_ALIGN_TYPE( double ),
550 optional_ALIGN_TYPE( long double ),
551
552 optional_ALIGN_TYPE( char *),
553 optional_ALIGN_TYPE( short * ),
554 optional_ALIGN_TYPE( int * ),
555 optional_ALIGN_TYPE( long * ),
556 optional_ALIGN_TYPE( float * ),
557 optional_ALIGN_TYPE( double * ),
558 optional_ALIGN_TYPE( long double * ),
559
560 optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ),
561 optional_ALIGN_TYPE( Unknown * Unknown::* ),
562 optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ),
563
564 nulltype
565 > > > > > > > > > > > > > >
566 > > > > > > > > > > > > > >
567 > > > > > >
568 alignment_types;
569
570#undef optional_ALIGN_TYPE
571
572#endif // optional_CONFIG_MAX_ALIGN_HACK
573
574/// C++03 constructed union to hold value.
575
576template< typename T >
577union storage_t
578{
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400579//private:
580// template< typename > friend class optional;
Davide Pesavento1fd00242018-05-20 00:11:01 -0400581
582 typedef T value_type;
583
584 storage_t() {}
585
586 storage_t( value_type const & v )
587 {
588 construct_value( v );
589 }
590
591 void construct_value( value_type const & v )
592 {
593 ::new( value_ptr() ) value_type( v );
594 }
595
596#if optional_CPP11_OR_GREATER
597
598 storage_t( value_type && v )
599 {
600 construct_value( std::move( v ) );
601 }
602
603 void construct_value( value_type && v )
604 {
605 ::new( value_ptr() ) value_type( std::move( v ) );
606 }
607
Davide Pesaventobc76da12018-07-17 15:20:24 -0400608 template< class... Args >
609 void emplace( Args&&... args )
610 {
611 ::new( value_ptr() ) value_type( std::forward<Args>(args)... );
612 }
613
614 template< class U, class... Args >
615 void emplace( std::initializer_list<U> il, Args&&... args )
616 {
617 ::new( value_ptr() ) value_type( il, std::forward<Args>(args)... );
618 }
619
Davide Pesavento1fd00242018-05-20 00:11:01 -0400620#endif
621
622 void destruct_value()
623 {
624 value_ptr()->~T();
625 }
626
627 value_type const * value_ptr() const
628 {
629 return as<value_type>();
630 }
631
632 value_type * value_ptr()
633 {
634 return as<value_type>();
635 }
636
637 value_type const & value() const optional_ref_qual
638 {
639 return * value_ptr();
640 }
641
642 value_type & value() optional_ref_qual
643 {
644 return * value_ptr();
645 }
646
647#if optional_CPP11_OR_GREATER
648
649 value_type const && value() const optional_refref_qual
650 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400651 return std::move( value() );
Davide Pesavento1fd00242018-05-20 00:11:01 -0400652 }
653
654 value_type && value() optional_refref_qual
655 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400656 return std::move( value() );
Davide Pesavento1fd00242018-05-20 00:11:01 -0400657 }
658
659#endif
660
661#if optional_CPP11_OR_GREATER
662
663 using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type;
664 aligned_storage_t data;
665
666#elif optional_CONFIG_MAX_ALIGN_HACK
667
668 typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t;
669
670 max_align_t hack;
671 aligned_storage_t data;
672
673#else
674 typedef optional_ALIGN_AS(value_type) align_as_type;
675
676 typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t;
677 aligned_storage_t data;
678
679# undef optional_ALIGN_AS
680
681#endif // optional_CONFIG_MAX_ALIGN_HACK
682
683 void * ptr() optional_noexcept
684 {
685 return &data;
686 }
687
688 void const * ptr() const optional_noexcept
689 {
690 return &data;
691 }
692
693 template <typename U>
694 U * as()
695 {
696 return reinterpret_cast<U*>( ptr() );
697 }
698
699 template <typename U>
700 U const * as() const
701 {
702 return reinterpret_cast<U const *>( ptr() );
703 }
704};
705
706} // namespace detail
707
708/// disengaged state tag
709
710struct nullopt_t
711{
712 struct init{};
713 optional_constexpr nullopt_t( init ) {}
714};
715
716#if optional_HAVE( CONSTEXPR_11 )
717constexpr nullopt_t nullopt{ nullopt_t::init{} };
718#else
719// extra parenthesis to prevent the most vexing parse:
720const nullopt_t nullopt(( nullopt_t::init() ));
721#endif
722
723/// optional access error
724
725class bad_optional_access : public std::logic_error
726{
727public:
728 explicit bad_optional_access()
729 : logic_error( "bad optional access" ) {}
730};
731
732/// optional
733
734template< typename T>
735class optional
736{
737private:
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400738 template< typename > friend class optional;
739
Davide Pesavento1fd00242018-05-20 00:11:01 -0400740 typedef void (optional::*safe_bool)() const;
741
742public:
743 typedef T value_type;
744
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400745 // x.x.3.1, constructors
746
747 // 1a - default construct
Davide Pesavento1fd00242018-05-20 00:11:01 -0400748 optional_constexpr optional() optional_noexcept
749 : has_value_( false )
750 , contained()
751 {}
752
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400753 // 1b - construct explicitly empty
Davide Pesavento1fd00242018-05-20 00:11:01 -0400754 optional_constexpr optional( nullopt_t ) optional_noexcept
755 : has_value_( false )
756 , contained()
757 {}
758
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400759 // 2 - copy-construct
760 optional_constexpr14 optional( optional const & other
Davide Pesavento1fd00242018-05-20 00:11:01 -0400761#if optional_CPP11_OR_GREATER
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400762 optional_REQUIRES_A(
763 true || std::is_copy_constructible<T>::value
764 )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400765#endif
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400766 )
767 : has_value_( other.has_value() )
768 {
769 if ( other.has_value() )
770 contained.construct_value( other.contained.value() );
771 }
Davide Pesavento1fd00242018-05-20 00:11:01 -0400772
773#if optional_CPP11_OR_GREATER
774
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400775 // 3 (C++11) - move-construct from optional
776 optional_constexpr14 optional( optional && other
777 optional_REQUIRES_A(
778 true || std::is_move_constructible<T>::value
779 )
780 ) noexcept( std::is_nothrow_move_constructible<T>::value )
781 : has_value_( other.has_value() )
782 {
783 if ( other.has_value() )
784 contained.construct_value( std::move( other.contained.value() ) );
785 }
Davide Pesavento1fd00242018-05-20 00:11:01 -0400786
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400787 // 4 (C++11) - explicit converting copy-construct from optional
788 template< typename U >
789 explicit optional( optional<U> const & other
790 optional_REQUIRES_A(
791 std::is_constructible<T, U const &>::value
792 && !std::is_constructible<T, optional<U> & >::value
793 && !std::is_constructible<T, optional<U> && >::value
794 && !std::is_constructible<T, optional<U> const & >::value
795 && !std::is_constructible<T, optional<U> const && >::value
796 && !std::is_convertible< optional<U> & , T>::value
797 && !std::is_convertible< optional<U> && , T>::value
798 && !std::is_convertible< optional<U> const & , T>::value
799 && !std::is_convertible< optional<U> const &&, T>::value
800 && !std::is_convertible< U const & , T>::value /*=> explicit */
801 )
802 )
803 : has_value_( other.has_value() )
804 {
805 if ( other.has_value() )
806 contained.construct_value( other.contained.value() );
807 }
808#endif // optional_CPP11_OR_GREATER
809
810 // 4 (C++98 and later) - non-explicit converting copy-construct from optional
811 template< typename U >
812 optional( optional<U> const & other
813#if optional_CPP11_OR_GREATER
814 optional_REQUIRES_A(
815 std::is_constructible<T, U const &>::value
816 && !std::is_constructible<T, optional<U> & >::value
817 && !std::is_constructible<T, optional<U> && >::value
818 && !std::is_constructible<T, optional<U> const & >::value
819 && !std::is_constructible<T, optional<U> const && >::value
820 && !std::is_convertible< optional<U> & , T>::value
821 && !std::is_convertible< optional<U> && , T>::value
822 && !std::is_convertible< optional<U> const & , T>::value
823 && !std::is_convertible< optional<U> const &&, T>::value
824 && std::is_convertible< U const & , T>::value /*=> non-explicit */
825 )
826#endif // optional_CPP11_OR_GREATER
827 )
828 : has_value_( other.has_value() )
829 {
830 if ( other.has_value() )
831 contained.construct_value( other.contained.value() );
832 }
833
834#if optional_CPP11_OR_GREATER
835
836 // 5a (C++11) - explicit converting move-construct from optional
837 template< typename U >
838 optional( optional<U> && other
839 optional_REQUIRES_A(
840 std::is_constructible<T, U const &>::value
841 && !std::is_constructible<T, optional<U> & >::value
842 && !std::is_constructible<T, optional<U> && >::value
843 && !std::is_constructible<T, optional<U> const & >::value
844 && !std::is_constructible<T, optional<U> const && >::value
845 && !std::is_convertible< optional<U> & , T>::value
846 && !std::is_convertible< optional<U> && , T>::value
847 && !std::is_convertible< optional<U> const & , T>::value
848 && !std::is_convertible< optional<U> const &&, T>::value
849 && !std::is_convertible< U &&, T>::value /*=> explicit */
850 )
851 )
852 : has_value_( other.has_value() )
853 {
854 if ( other.has_value() )
855 contained.construct_value( std::move( other.contained.value() ) );
856 }
857
858 // 5a (C++11) - non-explicit converting move-construct from optional
859 template< typename U >
860 optional( optional<U> && other
861 optional_REQUIRES_A(
862 std::is_constructible<T, U const &>::value
863 && !std::is_constructible<T, optional<U> & >::value
864 && !std::is_constructible<T, optional<U> && >::value
865 && !std::is_constructible<T, optional<U> const & >::value
866 && !std::is_constructible<T, optional<U> const && >::value
867 && !std::is_convertible< optional<U> & , T>::value
868 && !std::is_convertible< optional<U> && , T>::value
869 && !std::is_convertible< optional<U> const & , T>::value
870 && !std::is_convertible< optional<U> const &&, T>::value
871 && std::is_convertible< U &&, T>::value /*=> non-explicit */
872 )
873 )
874 : has_value_( other.has_value() )
875 {
876 if ( other.has_value() )
877 contained.construct_value( std::move( other.contained.value() ) );
878 }
879
880 // 6 (C++11) - in-place construct
881 template< typename... Args
882 optional_REQUIRES_T(
883 std::is_constructible<T, Args&&...>::value
884 )
885 >
886 optional_constexpr explicit optional( nonstd_lite_in_place_t(T), Args&&... args )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400887 : has_value_( true )
888 , contained( T( std::forward<Args>(args)...) )
889 {}
890
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400891 // 7 (C++11) - in-place construct, initializer-list
892 template< typename U, typename... Args
893 optional_REQUIRES_T(
894 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value
895 )
896 >
897 optional_constexpr explicit optional( nonstd_lite_in_place_t(T), std::initializer_list<U> il, Args&&... args )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400898 : has_value_( true )
899 , contained( T( il, std::forward<Args>(args)...) )
900 {}
901
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400902 // 8a (C++11) - explicit move construct from value
903 template< typename U = value_type >
904 optional_constexpr explicit optional( U && value
905 optional_REQUIRES_A(
906 std::is_constructible<T, U&&>::value
907 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
908 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
909 && !std::is_convertible<U&&, T>::value /*=> explicit */
910 )
911 )
912 : has_value_( true )
913 , contained( std::forward<U>( value ) )
914 {}
915
916 // 8a (C++11) - non-explicit move construct from value
917 template< typename U = value_type >
918 optional_constexpr optional( U && value
919 optional_REQUIRES_A(
920 std::is_constructible<T, U&&>::value
921 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
922 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
923 && std::is_convertible<U&&, T>::value /*=> non-explicit */
924 )
925 )
926 : has_value_( true )
927 , contained( std::forward<U>( value ) )
928 {}
929
930#else // optional_CPP11_OR_GREATER
931
932 // 8 (C++98)
933 optional( value_type const & value )
934 : has_value_( true )
935 , contained( value )
936 {}
937
Davide Pesavento1fd00242018-05-20 00:11:01 -0400938#endif // optional_CPP11_OR_GREATER
939
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400940 // x.x.3.2, destructor
941
Davide Pesavento1fd00242018-05-20 00:11:01 -0400942 ~optional()
943 {
944 if ( has_value() )
945 contained.destruct_value();
946 }
947
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400948 // x.x.3.3, assignment
Davide Pesavento1fd00242018-05-20 00:11:01 -0400949
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400950 // 1 (C++98and later) - assign explicitly empty
Davide Pesavento1fd00242018-05-20 00:11:01 -0400951 optional & operator=( nullopt_t ) optional_noexcept
952 {
953 reset();
954 return *this;
955 }
956
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400957 // 2 (C++98and later) - copy-assign from optional
Davide Pesavento1fd00242018-05-20 00:11:01 -0400958#if optional_CPP11_OR_GREATER
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400959 optional_REQUIRES_R(
960 optional &,
961 true
962// std::is_copy_constructible<T>::value
963// && std::is_copy_assignable<T>::value
964 )
965 operator=( optional const & other )
966 noexcept(
967 std::is_nothrow_move_assignable<T>::value
968 && std::is_nothrow_move_constructible<T>::value
969 )
970#else
971 optional & operator=( optional const & other )
Davide Pesavento1fd00242018-05-20 00:11:01 -0400972#endif
973 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400974 if ( has_value() == true && other.has_value() == false ) reset();
975 else if ( has_value() == false && other.has_value() == true ) initialize( *other );
976 else if ( has_value() == true && other.has_value() == true ) contained.value() = *other;
Davide Pesavento1fd00242018-05-20 00:11:01 -0400977 return *this;
978 }
979
980#if optional_CPP11_OR_GREATER
981
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400982 // 3 (C++11) - move-assign from optional
983 optional_REQUIRES_R(
984 optional &,
985 true
986// std::is_move_constructible<T>::value
987// && std::is_move_assignable<T>::value
988 )
989 operator=( optional && other ) noexcept
Davide Pesavento1fd00242018-05-20 00:11:01 -0400990 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400991 if ( has_value() == true && other.has_value() == false ) reset();
992 else if ( has_value() == false && other.has_value() == true ) initialize( std::move( *other ) );
993 else if ( has_value() == true && other.has_value() == true ) contained.value() = std::move( *other );
Davide Pesavento1fd00242018-05-20 00:11:01 -0400994 return *this;
995 }
996
Davide Pesaventod2c750b2018-09-16 12:48:01 -0400997 // 4 (C++11) - move-assign from value
998 template< typename U = T >
999 optional_REQUIRES_R(
1000 optional &,
1001 std::is_constructible<T , U>::value
1002 && std::is_assignable<T&, U>::value
1003 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
1004 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
1005// && !(std::is_scalar<T>::value && std::is_same<T, typename std::decay<U>::type>::value)
1006 )
1007 operator=( U && value )
Davide Pesavento1fd00242018-05-20 00:11:01 -04001008 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001009 if ( has_value() ) contained.value() = std::forward<U>( value );
1010 else initialize( T( std::forward<U>( value ) ) );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001011 return *this;
1012 }
1013
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001014#else // optional_CPP11_OR_GREATER
Davide Pesavento1fd00242018-05-20 00:11:01 -04001015
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001016 // 4 (C++98) - copy-assign from value
1017 template< typename U /*= T*/ >
1018 optional & operator=( U const & value )
Davide Pesavento1fd00242018-05-20 00:11:01 -04001019 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001020 if ( has_value() ) contained.value() = value;
1021 else initialize( T( value ) );
1022 return *this;
Davide Pesavento1fd00242018-05-20 00:11:01 -04001023 }
1024
1025#endif // optional_CPP11_OR_GREATER
1026
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001027 // 5 (C++98 and later) - converting copy-assign from optional
1028 template< typename U >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001029#if optional_CPP11_OR_GREATER
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001030 optional_REQUIRES_R(
1031 optional&,
1032 std::is_constructible< T , U const &>::value
1033 && std::is_assignable< T&, U const &>::value
1034 && !std::is_constructible<T, optional<U> & >::value
1035 && !std::is_constructible<T, optional<U> && >::value
1036 && !std::is_constructible<T, optional<U> const & >::value
1037 && !std::is_constructible<T, optional<U> const && >::value
1038 && !std::is_convertible< optional<U> & , T>::value
1039 && !std::is_convertible< optional<U> && , T>::value
1040 && !std::is_convertible< optional<U> const & , T>::value
1041 && !std::is_convertible< optional<U> const &&, T>::value
1042 && !std::is_assignable< T&, optional<U> & >::value
1043 && !std::is_assignable< T&, optional<U> && >::value
1044 && !std::is_assignable< T&, optional<U> const & >::value
1045 && !std::is_assignable< T&, optional<U> const && >::value
1046 )
1047#else
1048 optional&
1049#endif // optional_CPP11_OR_GREATER
1050 operator=( optional<U> const & other )
1051 {
1052 return *this = optional( other );
1053 }
1054
1055#if optional_CPP11_OR_GREATER
1056
1057 // 6 (C++11) - converting move-assign from optional
1058 template< typename U >
1059 optional_REQUIRES_R(
1060 optional&,
1061 std::is_constructible< T , U>::value
1062 && std::is_assignable< T&, U>::value
1063 && !std::is_constructible<T, optional<U> & >::value
1064 && !std::is_constructible<T, optional<U> && >::value
1065 && !std::is_constructible<T, optional<U> const & >::value
1066 && !std::is_constructible<T, optional<U> const && >::value
1067 && !std::is_convertible< optional<U> & , T>::value
1068 && !std::is_convertible< optional<U> && , T>::value
1069 && !std::is_convertible< optional<U> const & , T>::value
1070 && !std::is_convertible< optional<U> const &&, T>::value
1071 && !std::is_assignable< T&, optional<U> & >::value
1072 && !std::is_assignable< T&, optional<U> && >::value
1073 && !std::is_assignable< T&, optional<U> const & >::value
1074 && !std::is_assignable< T&, optional<U> const && >::value
1075 )
1076 operator=( optional<U> && other )
1077 {
1078 return *this = optional( std::move( other ) );
1079 }
1080
1081 // 7 (C++11) - emplace
1082 template< typename... Args
1083 optional_REQUIRES_T(
1084 std::is_constructible<T, Args&&...>::value
1085 )
1086 >
1087 T& emplace( Args&&... args )
1088 {
1089 *this = nullopt;
1090 contained.emplace( std::forward<Args>(args)... );
1091 has_value_ = true;
1092 return contained.value();
1093 }
1094
1095 // 8 (C++11) - emplace, initializer-list
1096 template< typename U, typename... Args
1097 optional_REQUIRES_T(
1098 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value
1099 )
1100 >
1101 T& emplace( std::initializer_list<U> il, Args&&... args )
1102 {
1103 *this = nullopt;
1104 contained.emplace( il, std::forward<Args>(args)... );
1105 has_value_ = true;
1106 return contained.value();
1107 }
1108
1109#endif // optional_CPP11_OR_GREATER
1110
1111 // x.x.3.4, swap
1112
1113 void swap( optional & other )
1114#if optional_CPP11_OR_GREATER
1115 noexcept(
1116 std::is_nothrow_move_constructible<T>::value
1117 && noexcept( std::swap( std::declval<T&>(), std::declval<T&>() ) )
1118 )
Davide Pesavento1fd00242018-05-20 00:11:01 -04001119#endif
1120 {
1121 using std::swap;
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001122 if ( has_value() == true && other.has_value() == true ) { swap( **this, *other ); }
1123 else if ( has_value() == false && other.has_value() == true ) { initialize( *other ); other.reset(); }
1124 else if ( has_value() == true && other.has_value() == false ) { other.initialize( **this ); reset(); }
Davide Pesavento1fd00242018-05-20 00:11:01 -04001125 }
1126
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001127 // x.x.3.5, observers
Davide Pesavento1fd00242018-05-20 00:11:01 -04001128
1129 optional_constexpr value_type const * operator ->() const
1130 {
1131 return assert( has_value() ),
1132 contained.value_ptr();
1133 }
1134
1135 optional_constexpr14 value_type * operator ->()
1136 {
1137 return assert( has_value() ),
1138 contained.value_ptr();
1139 }
1140
1141 optional_constexpr value_type const & operator *() const optional_ref_qual
1142 {
1143 return assert( has_value() ),
1144 contained.value();
1145 }
1146
1147 optional_constexpr14 value_type & operator *() optional_ref_qual
1148 {
1149 return assert( has_value() ),
1150 contained.value();
1151 }
1152
1153#if optional_CPP11_OR_GREATER
1154
1155 optional_constexpr value_type const && operator *() const optional_refref_qual
1156 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001157 return std::move( **this );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001158 }
1159
1160 optional_constexpr14 value_type && operator *() optional_refref_qual
1161 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001162 return std::move( **this );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001163 }
1164
1165#endif
1166
1167#if optional_CPP11_OR_GREATER
1168 optional_constexpr explicit operator bool() const optional_noexcept
1169 {
1170 return has_value();
1171 }
1172#else
1173 optional_constexpr operator safe_bool() const optional_noexcept
1174 {
1175 return has_value() ? &optional::this_type_does_not_support_comparisons : 0;
1176 }
1177#endif
1178
1179 optional_constexpr bool has_value() const optional_noexcept
1180 {
1181 return has_value_;
1182 }
1183
1184 optional_constexpr14 value_type const & value() const optional_ref_qual
1185 {
1186 if ( ! has_value() )
1187 throw bad_optional_access();
1188
1189 return contained.value();
1190 }
1191
1192 optional_constexpr14 value_type & value() optional_ref_qual
1193 {
1194 if ( ! has_value() )
1195 throw bad_optional_access();
1196
1197 return contained.value();
1198 }
1199
1200#if optional_HAVE( REF_QUALIFIER )
1201
Davide Pesavento17b61b42018-11-21 23:10:48 -05001202 optional_constexpr value_type const && value() const optional_refref_qual
Davide Pesavento1fd00242018-05-20 00:11:01 -04001203 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001204 return std::move( value() );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001205 }
1206
1207 optional_constexpr14 value_type && value() optional_refref_qual
1208 {
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001209 return std::move( value() );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001210 }
1211
1212#endif
1213
1214#if optional_CPP11_OR_GREATER
1215
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001216 template< typename U >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001217 optional_constexpr value_type value_or( U && v ) const optional_ref_qual
1218 {
1219 return has_value() ? contained.value() : static_cast<T>(std::forward<U>( v ) );
1220 }
1221
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001222 template< typename U >
Davide Pesavento17b61b42018-11-21 23:10:48 -05001223 optional_constexpr14 value_type value_or( U && v ) optional_refref_qual
Davide Pesavento1fd00242018-05-20 00:11:01 -04001224 {
1225 return has_value() ? std::move( contained.value() ) : static_cast<T>(std::forward<U>( v ) );
1226 }
1227
1228#else
1229
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001230 template< typename U >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001231 optional_constexpr value_type value_or( U const & v ) const
1232 {
1233 return has_value() ? contained.value() : static_cast<value_type>( v );
1234 }
1235
1236#endif // optional_CPP11_OR_GREATER
1237
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001238 // x.x.3.6, modifiers
Davide Pesavento1fd00242018-05-20 00:11:01 -04001239
1240 void reset() optional_noexcept
1241 {
1242 if ( has_value() )
1243 contained.destruct_value();
1244
1245 has_value_ = false;
1246 }
1247
1248private:
1249 void this_type_does_not_support_comparisons() const {}
1250
1251 template< typename V >
1252 void initialize( V const & value )
1253 {
1254 assert( ! has_value() );
1255 contained.construct_value( value );
1256 has_value_ = true;
1257 }
1258
1259#if optional_CPP11_OR_GREATER
1260 template< typename V >
1261 void initialize( V && value )
1262 {
1263 assert( ! has_value() );
1264 contained.construct_value( std::move( value ) );
1265 has_value_ = true;
1266 }
Davide Pesaventobc76da12018-07-17 15:20:24 -04001267
Davide Pesavento1fd00242018-05-20 00:11:01 -04001268#endif
1269
1270private:
1271 bool has_value_;
1272 detail::storage_t< value_type > contained;
1273
1274};
1275
1276// Relational operators
1277
1278template< typename T, typename U >
1279inline optional_constexpr bool operator==( optional<T> const & x, optional<U> const & y )
1280{
1281 return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y;
1282}
1283
1284template< typename T, typename U >
1285inline optional_constexpr bool operator!=( optional<T> const & x, optional<U> const & y )
1286{
1287 return !(x == y);
1288}
1289
1290template< typename T, typename U >
1291inline optional_constexpr bool operator<( optional<T> const & x, optional<U> const & y )
1292{
1293 return (!y) ? false : (!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 (y < x);
1300}
1301
1302template< typename T, typename U >
1303inline optional_constexpr bool operator<=( optional<T> const & x, optional<U> const & y )
1304{
1305 return !(y < x);
1306}
1307
1308template< typename T, typename U >
1309inline optional_constexpr bool operator>=( optional<T> const & x, optional<U> const & y )
1310{
1311 return !(x < y);
1312}
1313
1314// Comparison with nullopt
1315
1316template< typename T >
1317inline optional_constexpr bool operator==( optional<T> const & x, nullopt_t ) optional_noexcept
1318{
1319 return (!x);
1320}
1321
1322template< typename T >
1323inline optional_constexpr bool operator==( nullopt_t, optional<T> const & x ) optional_noexcept
1324{
1325 return (!x);
1326}
1327
1328template< typename T >
1329inline optional_constexpr bool operator!=( optional<T> const & x, nullopt_t ) optional_noexcept
1330{
1331 return bool(x);
1332}
1333
1334template< typename T >
1335inline optional_constexpr bool operator!=( nullopt_t, optional<T> const & x ) optional_noexcept
1336{
1337 return bool(x);
1338}
1339
1340template< typename T >
1341inline optional_constexpr bool operator<( optional<T> const &, nullopt_t ) optional_noexcept
1342{
1343 return false;
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 & x, nullopt_t ) optional_noexcept
1354{
1355 return (!x);
1356}
1357
1358template< typename T >
1359inline optional_constexpr bool operator<=( nullopt_t, optional<T> const & ) optional_noexcept
1360{
1361 return true;
1362}
1363
1364template< typename T >
1365inline optional_constexpr bool operator>( optional<T> const & x, nullopt_t ) optional_noexcept
1366{
1367 return bool(x);
1368}
1369
1370template< typename T >
1371inline optional_constexpr bool operator>( nullopt_t, optional<T> const & ) optional_noexcept
1372{
1373 return false;
1374}
1375
1376template< typename T >
1377inline optional_constexpr bool operator>=( optional<T> const &, nullopt_t ) optional_noexcept
1378{
1379 return true;
1380}
1381
1382template< typename T >
1383inline optional_constexpr bool operator>=( nullopt_t, optional<T> const & x ) optional_noexcept
1384{
1385 return (!x);
1386}
1387
1388// Comparison with T
1389
1390template< typename T, typename U >
1391inline optional_constexpr bool operator==( optional<T> const & x, U const & v )
1392{
1393 return bool(x) ? *x == v : false;
1394}
1395
1396template< typename T, typename U >
1397inline optional_constexpr bool operator==( U const & v, optional<T> const & x )
1398{
1399 return bool(x) ? v == *x : false;
1400}
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 : true;
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 : true;
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 : false;
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 : false;
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 : true;
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
1462// Specialized algorithms
1463
1464template< typename T >
1465void swap( optional<T> & x, optional<T> & y )
1466#if optional_CPP11_OR_GREATER
1467 noexcept( noexcept( x.swap(y) ) )
1468#endif
1469{
1470 x.swap( y );
1471}
1472
1473#if optional_CPP11_OR_GREATER
1474
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001475template< typename T >
1476optional_constexpr optional< typename std::decay<T>::type > make_optional( T && value )
Davide Pesavento1fd00242018-05-20 00:11:01 -04001477{
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001478 return optional< typename std::decay<T>::type >( std::forward<T>( value ) );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001479}
1480
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001481template< typename T, typename...Args >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001482optional_constexpr optional<T> make_optional( Args&&... args )
1483{
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001484 return optional<T>( nonstd_lite_in_place(T), std::forward<Args>(args)...);
Davide Pesavento1fd00242018-05-20 00:11:01 -04001485}
1486
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001487template< typename T, typename U, typename... Args >
Davide Pesavento1fd00242018-05-20 00:11:01 -04001488optional_constexpr optional<T> make_optional( std::initializer_list<U> il, Args&&... args )
1489{
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001490 return optional<T>( nonstd_lite_in_place(T), il, std::forward<Args>(args)...);
Davide Pesavento1fd00242018-05-20 00:11:01 -04001491}
1492
1493#else
1494
1495template< typename T >
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001496optional<T> make_optional( T const & value )
Davide Pesavento1fd00242018-05-20 00:11:01 -04001497{
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001498 return optional<T>( value );
Davide Pesavento1fd00242018-05-20 00:11:01 -04001499}
1500
1501#endif // optional_CPP11_OR_GREATER
1502
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001503} // namespace optional_lite
Davide Pesavento1fd00242018-05-20 00:11:01 -04001504
1505using namespace optional_lite;
1506
1507} // namespace nonstd
1508
1509#if optional_CPP11_OR_GREATER
1510
1511// specialize the std::hash algorithm:
1512
1513namespace std {
1514
1515template< class T >
1516struct hash< nonstd::optional<T> >
1517{
1518public:
1519 std::size_t operator()( nonstd::optional<T> const & v ) const optional_noexcept
1520 {
1521 return bool( v ) ? hash<T>()( *v ) : 0;
1522 }
1523};
1524
1525} //namespace std
1526
1527#endif // optional_CPP11_OR_GREATER
1528
Davide Pesavento17b61b42018-11-21 23:10:48 -05001529#if defined(__clang__)
Davide Pesavento1fd00242018-05-20 00:11:01 -04001530# pragma clang diagnostic pop
Davide Pesavento17b61b42018-11-21 23:10:48 -05001531#elif defined(__GNUC__)
Davide Pesavento1fd00242018-05-20 00:11:01 -04001532# pragma GCC diagnostic pop
1533#endif
1534
Davide Pesaventod2c750b2018-09-16 12:48:01 -04001535#endif // optional_USES_STD_OPTIONAL
Davide Pesavento1fd00242018-05-20 00:11:01 -04001536
1537#endif // NONSTD_OPTIONAL_LITE_HPP