Add `std::optional` replacement (`nonstd::optional`)
[babeltrace.git] / src / cpp-common / optional.hpp
1 //
2 // Copyright (c) 2014-2021 Martin Moene
3 //
4 // https://github.com/martinmoene/optional-lite
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8
9 #pragma once
10
11 #ifndef NONSTD_OPTIONAL_LITE_HPP
12 #define NONSTD_OPTIONAL_LITE_HPP
13
14 #define optional_lite_MAJOR 3
15 #define optional_lite_MINOR 5
16 #define optional_lite_PATCH 0
17
18 #define optional_lite_VERSION optional_STRINGIFY(optional_lite_MAJOR) "." optional_STRINGIFY(optional_lite_MINOR) "." optional_STRINGIFY(optional_lite_PATCH)
19
20 #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 // tweak header support:
30
31 #ifdef __has_include
32 # if __has_include(<nonstd/optional.tweak.hpp>)
33 # include <nonstd/optional.tweak.hpp>
34 # endif
35 #define optional_HAVE_TWEAK_HEADER 1
36 #else
37 #define optional_HAVE_TWEAK_HEADER 0
38 //# pragma message("optional.hpp: Note: Tweak header not supported.")
39 #endif
40
41 // optional selection and configuration:
42
43 #if !defined( optional_CONFIG_SELECT_OPTIONAL )
44 # define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD )
45 #endif
46
47 // Control presence of extensions:
48
49 #ifndef optional_CONFIG_NO_EXTENSIONS
50 #define optional_CONFIG_NO_EXTENSIONS 0
51 #endif
52
53 // Control presence of exception handling (try and auto discover):
54
55 #ifndef optional_CONFIG_NO_EXCEPTIONS
56 # if defined(_MSC_VER)
57 # include <cstddef> // for _HAS_EXCEPTIONS
58 # endif
59 # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
60 # define optional_CONFIG_NO_EXCEPTIONS 0
61 # else
62 # define optional_CONFIG_NO_EXCEPTIONS 1
63 # endif
64 #endif
65
66 // C++ language version detection (C++20 is speculative):
67 // Note: VC14.0/1900 (VS2015) lacks too much from C++14.
68
69 #ifndef optional_CPLUSPLUS
70 # if defined(_MSVC_LANG ) && !defined(__clang__)
71 # define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
72 # else
73 # define optional_CPLUSPLUS __cplusplus
74 # endif
75 #endif
76
77 #define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L )
78 #define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L )
79 #define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L )
80 #define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L )
81 #define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L )
82 #define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L )
83
84 // C++ language version (represent 98 as 3):
85
86 #define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) )
87
88 // Use C++17 std::optional if available and requested:
89
90 #if optional_CPP17_OR_GREATER && defined(__has_include )
91 # if __has_include( <optional> )
92 # define optional_HAVE_STD_OPTIONAL 1
93 # else
94 # define optional_HAVE_STD_OPTIONAL 0
95 # endif
96 #else
97 # define optional_HAVE_STD_OPTIONAL 0
98 #endif
99
100 #define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) )
101
102 //
103 // in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite:
104 //
105
106 #ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
107 #define nonstd_lite_HAVE_IN_PLACE_TYPES 1
108
109 // C++17 std::in_place in <utility>:
110
111 #if optional_CPP17_OR_GREATER
112
113 #include <utility>
114
115 namespace nonstd {
116
117 using std::in_place;
118 using std::in_place_type;
119 using std::in_place_index;
120 using std::in_place_t;
121 using std::in_place_type_t;
122 using std::in_place_index_t;
123
124 #define nonstd_lite_in_place_t( T) std::in_place_t
125 #define nonstd_lite_in_place_type_t( T) std::in_place_type_t<T>
126 #define nonstd_lite_in_place_index_t(K) std::in_place_index_t<K>
127
128 #define nonstd_lite_in_place( T) std::in_place_t{}
129 #define nonstd_lite_in_place_type( T) std::in_place_type_t<T>{}
130 #define nonstd_lite_in_place_index(K) std::in_place_index_t<K>{}
131
132 } // namespace nonstd
133
134 #else // optional_CPP17_OR_GREATER
135
136 #include <cstddef>
137
138 namespace nonstd {
139 namespace detail {
140
141 template< class T >
142 struct in_place_type_tag {};
143
144 template< std::size_t K >
145 struct in_place_index_tag {};
146
147 } // namespace detail
148
149 struct in_place_t {};
150
151 template< class T >
152 inline in_place_t in_place( detail::in_place_type_tag<T> /*unused*/ = detail::in_place_type_tag<T>() )
153 {
154 return in_place_t();
155 }
156
157 template< std::size_t K >
158 inline in_place_t in_place( detail::in_place_index_tag<K> /*unused*/ = detail::in_place_index_tag<K>() )
159 {
160 return in_place_t();
161 }
162
163 template< class T >
164 inline in_place_t in_place_type( detail::in_place_type_tag<T> /*unused*/ = detail::in_place_type_tag<T>() )
165 {
166 return in_place_t();
167 }
168
169 template< std::size_t K >
170 inline in_place_t in_place_index( detail::in_place_index_tag<K> /*unused*/ = detail::in_place_index_tag<K>() )
171 {
172 return in_place_t();
173 }
174
175 // mimic templated typedef:
176
177 #define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
178 #define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
179 #define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<K> )
180
181 #define nonstd_lite_in_place( T) nonstd::in_place_type<T>
182 #define nonstd_lite_in_place_type( T) nonstd::in_place_type<T>
183 #define nonstd_lite_in_place_index(K) nonstd::in_place_index<K>
184
185 } // namespace nonstd
186
187 #endif // optional_CPP17_OR_GREATER
188 #endif // nonstd_lite_HAVE_IN_PLACE_TYPES
189
190 //
191 // Using std::optional:
192 //
193
194 #if optional_USES_STD_OPTIONAL
195
196 #include <optional>
197
198 namespace nonstd {
199
200 using std::optional;
201 using std::bad_optional_access;
202 using std::hash;
203
204 using std::nullopt;
205 using std::nullopt_t;
206
207 using std::operator==;
208 using std::operator!=;
209 using std::operator<;
210 using std::operator<=;
211 using std::operator>;
212 using std::operator>=;
213 using std::make_optional;
214 using std::swap;
215 }
216
217 #else // optional_USES_STD_OPTIONAL
218
219 #include <cassert>
220 #include <utility>
221
222 // optional-lite alignment configuration:
223
224 #ifndef optional_CONFIG_MAX_ALIGN_HACK
225 # define optional_CONFIG_MAX_ALIGN_HACK 0
226 #endif
227
228 #ifndef optional_CONFIG_ALIGN_AS
229 // no default, used in #if defined()
230 #endif
231
232 #ifndef optional_CONFIG_ALIGN_AS_FALLBACK
233 # define optional_CONFIG_ALIGN_AS_FALLBACK double
234 #endif
235
236 // Compiler warning suppression:
237
238 #if defined(__clang__)
239 # pragma clang diagnostic push
240 # pragma clang diagnostic ignored "-Wundef"
241 #elif defined(__GNUC__)
242 # pragma GCC diagnostic push
243 # pragma GCC diagnostic ignored "-Wundef"
244 #elif defined(_MSC_VER )
245 # pragma warning( push )
246 #endif
247
248 // half-open range [lo..hi):
249 #define optional_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
250
251 // Compiler versions:
252 //
253 // MSVC++ 6.0 _MSC_VER == 1200 optional_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0)
254 // MSVC++ 7.0 _MSC_VER == 1300 optional_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002)
255 // MSVC++ 7.1 _MSC_VER == 1310 optional_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003)
256 // MSVC++ 8.0 _MSC_VER == 1400 optional_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005)
257 // MSVC++ 9.0 _MSC_VER == 1500 optional_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008)
258 // MSVC++ 10.0 _MSC_VER == 1600 optional_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010)
259 // MSVC++ 11.0 _MSC_VER == 1700 optional_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012)
260 // MSVC++ 12.0 _MSC_VER == 1800 optional_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013)
261 // MSVC++ 14.0 _MSC_VER == 1900 optional_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015)
262 // MSVC++ 14.1 _MSC_VER >= 1910 optional_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017)
263 // MSVC++ 14.2 _MSC_VER >= 1920 optional_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019)
264
265 #if defined(_MSC_VER ) && !defined(__clang__)
266 # define optional_COMPILER_MSVC_VER (_MSC_VER )
267 # define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) )
268 #else
269 # define optional_COMPILER_MSVC_VER 0
270 # define optional_COMPILER_MSVC_VERSION 0
271 #endif
272
273 #define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * (major) + (minor) ) + (patch) )
274
275 #if defined(__GNUC__) && !defined(__clang__)
276 # define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
277 #else
278 # define optional_COMPILER_GNUC_VERSION 0
279 #endif
280
281 #if defined(__clang__)
282 # define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
283 #else
284 # define optional_COMPILER_CLANG_VERSION 0
285 #endif
286
287 #if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 )
288 # pragma warning( disable: 4345 ) // initialization behavior changed
289 #endif
290
291 #if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 )
292 # pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const'
293 #endif
294
295 // Presence of language and library features:
296
297 #define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE )
298
299 #ifdef _HAS_CPP0X
300 # define optional_HAS_CPP0X _HAS_CPP0X
301 #else
302 # define optional_HAS_CPP0X 0
303 #endif
304
305 // Unless defined otherwise below, consider VC14 as C++11 for optional-lite:
306
307 #if optional_COMPILER_MSVC_VER >= 1900
308 # undef optional_CPP11_OR_GREATER
309 # define optional_CPP11_OR_GREATER 1
310 #endif
311
312 #define optional_CPP11_90 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1500)
313 #define optional_CPP11_100 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1600)
314 #define optional_CPP11_110 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1700)
315 #define optional_CPP11_120 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1800)
316 #define optional_CPP11_140 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1900)
317 #define optional_CPP11_141 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1910)
318
319 #define optional_CPP14_000 (optional_CPP14_OR_GREATER)
320 #define optional_CPP17_000 (optional_CPP17_OR_GREATER)
321
322 // clang >= 2.9, gcc >= 4.9, msvc >= vc14.0/1900 (vs15):
323 #define optional_CPP11_140_C290_G490 ((optional_CPP11_OR_GREATER_ && (optional_COMPILER_CLANG_VERSION >= 290 || optional_COMPILER_GNUC_VERSION >= 490)) || (optional_COMPILER_MSVC_VER >= 1900))
324
325 // clang >= 3.5, msvc >= vc11 (vs12):
326 #define optional_CPP11_110_C350 ( optional_CPP11_110 && !optional_BETWEEN( optional_COMPILER_CLANG_VERSION, 1, 350 ) )
327
328 // clang >= 3.5, gcc >= 5.0, msvc >= vc11 (vs12):
329 #define optional_CPP11_110_C350_G500 \
330 ( optional_CPP11_110 && \
331 !( optional_BETWEEN( optional_COMPILER_CLANG_VERSION, 1, 350 ) \
332 || optional_BETWEEN( optional_COMPILER_GNUC_VERSION , 1, 500 ) ) )
333
334 // Presence of C++11 language features:
335
336 #define optional_HAVE_CONSTEXPR_11 optional_CPP11_140
337 #define optional_HAVE_IS_DEFAULT optional_CPP11_140
338 #define optional_HAVE_NOEXCEPT optional_CPP11_140
339 #define optional_HAVE_NULLPTR optional_CPP11_100
340 #define optional_HAVE_REF_QUALIFIER optional_CPP11_140_C290_G490
341 #define optional_HAVE_STATIC_ASSERT optional_CPP11_110
342 #define optional_HAVE_INITIALIZER_LIST optional_CPP11_140
343
344 // Presence of C++14 language features:
345
346 #define optional_HAVE_CONSTEXPR_14 optional_CPP14_000
347
348 // Presence of C++17 language features:
349
350 #define optional_HAVE_NODISCARD optional_CPP17_000
351
352 // Presence of C++ library features:
353
354 #define optional_HAVE_CONDITIONAL optional_CPP11_120
355 #define optional_HAVE_REMOVE_CV optional_CPP11_120
356 #define optional_HAVE_TYPE_TRAITS optional_CPP11_90
357
358 #define optional_HAVE_TR1_TYPE_TRAITS (!! optional_COMPILER_GNUC_VERSION )
359 #define optional_HAVE_TR1_ADD_POINTER (!! optional_COMPILER_GNUC_VERSION )
360
361 #define optional_HAVE_IS_ASSIGNABLE optional_CPP11_110_C350
362 #define optional_HAVE_IS_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350
363 #define optional_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE optional_CPP11_110_C350
364 #define optional_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350
365 #define optional_HAVE_IS_TRIVIALLY_COPY_CONSTRUCTIBLE optional_CPP11_110_C350_G500
366 #define optional_HAVE_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350_G500
367
368 // C++ feature usage:
369
370 #if optional_HAVE( CONSTEXPR_11 )
371 # define optional_constexpr constexpr
372 #else
373 # define optional_constexpr /*constexpr*/
374 #endif
375
376 #if optional_HAVE( IS_DEFAULT )
377 # define optional_is_default = default;
378 #else
379 # define optional_is_default {}
380 #endif
381
382 #if optional_HAVE( CONSTEXPR_14 )
383 # define optional_constexpr14 constexpr
384 #else
385 # define optional_constexpr14 /*constexpr*/
386 #endif
387
388 #if optional_HAVE( NODISCARD )
389 # define optional_nodiscard [[nodiscard]]
390 #else
391 # define optional_nodiscard /*[[nodiscard]]*/
392 #endif
393
394 #if optional_HAVE( NOEXCEPT )
395 # define optional_noexcept noexcept
396 #else
397 # define optional_noexcept /*noexcept*/
398 #endif
399
400 #if optional_HAVE( NULLPTR )
401 # define optional_nullptr nullptr
402 #else
403 # define optional_nullptr NULL
404 #endif
405
406 #if optional_HAVE( REF_QUALIFIER )
407 // NOLINTNEXTLINE( bugprone-macro-parentheses )
408 # define optional_ref_qual &
409 # define optional_refref_qual &&
410 #else
411 # define optional_ref_qual /*&*/
412 # define optional_refref_qual /*&&*/
413 #endif
414
415 #if optional_HAVE( STATIC_ASSERT )
416 # define optional_static_assert(expr, text) static_assert(expr, text);
417 #else
418 # define optional_static_assert(expr, text) /*static_assert(expr, text);*/
419 #endif
420
421 // additional includes:
422
423 #if optional_CONFIG_NO_EXCEPTIONS
424 // already included: <cassert>
425 #else
426 # include <stdexcept>
427 #endif
428
429 #if optional_CPP11_OR_GREATER
430 # include <functional>
431 #endif
432
433 #if optional_HAVE( INITIALIZER_LIST )
434 # include <initializer_list>
435 #endif
436
437 #if optional_HAVE( TYPE_TRAITS )
438 # include <type_traits>
439 #elif optional_HAVE( TR1_TYPE_TRAITS )
440 # include <tr1/type_traits>
441 #endif
442
443 // Method enabling
444
445 #if optional_CPP11_OR_GREATER
446
447 #define optional_REQUIRES_0(...) \
448 template< bool B = (__VA_ARGS__), typename std::enable_if<B, int>::type = 0 >
449
450 #define optional_REQUIRES_T(...) \
451 , typename std::enable_if< (__VA_ARGS__), int >::type = 0
452
453 #define optional_REQUIRES_R(R, ...) \
454 typename std::enable_if< (__VA_ARGS__), R>::type
455
456 #define optional_REQUIRES_A(...) \
457 , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr
458
459 #endif
460
461 //
462 // optional:
463 //
464
465 namespace nonstd { namespace optional_lite {
466
467 namespace std11 {
468
469 template< class T, T v > struct integral_constant { enum { value = v }; };
470 template< bool B > struct bool_constant : integral_constant<bool, B>{};
471
472 typedef bool_constant< true > true_type;
473 typedef bool_constant< false > false_type;
474
475 #if optional_CPP11_OR_GREATER
476 using std::move;
477 #else
478 template< typename T > T & move( T & t ) { return t; }
479 #endif
480
481 #if optional_HAVE( CONDITIONAL )
482 using std::conditional;
483 #else
484 template< bool B, typename T, typename F > struct conditional { typedef T type; };
485 template< typename T, typename F > struct conditional<false, T, F> { typedef F type; };
486 #endif // optional_HAVE_CONDITIONAL
487
488 #if optional_HAVE( IS_ASSIGNABLE )
489 using std::is_assignable;
490 #else
491 template< class T, class U > struct is_assignable : std11::true_type{};
492 #endif
493
494 #if optional_HAVE( IS_MOVE_CONSTRUCTIBLE )
495 using std::is_move_constructible;
496 #else
497 template< class T > struct is_move_constructible : std11::true_type{};
498 #endif
499
500 #if optional_HAVE( IS_NOTHROW_MOVE_ASSIGNABLE )
501 using std::is_nothrow_move_assignable;
502 #else
503 template< class T > struct is_nothrow_move_assignable : std11::true_type{};
504 #endif
505
506 #if optional_HAVE( IS_NOTHROW_MOVE_CONSTRUCTIBLE )
507 using std::is_nothrow_move_constructible;
508 #else
509 template< class T > struct is_nothrow_move_constructible : std11::true_type{};
510 #endif
511
512 #if optional_HAVE( IS_TRIVIALLY_COPY_CONSTRUCTIBLE )
513 using std::is_trivially_copy_constructible;
514 #else
515 template< class T > struct is_trivially_copy_constructible : std11::true_type{};
516 #endif
517
518 #if optional_HAVE( IS_TRIVIALLY_MOVE_CONSTRUCTIBLE )
519 using std::is_trivially_move_constructible;
520 #else
521 template< class T > struct is_trivially_move_constructible : std11::true_type{};
522 #endif
523
524 } // namespace std11
525
526 #if optional_CPP11_OR_GREATER
527
528 /// type traits C++17:
529
530 namespace std17 {
531
532 #if optional_CPP17_OR_GREATER
533
534 using std::is_swappable;
535 using std::is_nothrow_swappable;
536
537 #elif optional_CPP11_OR_GREATER
538
539 namespace detail {
540
541 using std::swap;
542
543 struct is_swappable
544 {
545 template< typename T, typename = decltype( swap( std::declval<T&>(), std::declval<T&>() ) ) >
546 static std11::true_type test( int /*unused*/ );
547
548 template< typename >
549 static std11::false_type test(...);
550 };
551
552 struct is_nothrow_swappable
553 {
554 // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015):
555
556 template< typename T >
557 static constexpr bool satisfies()
558 {
559 return noexcept( swap( std::declval<T&>(), std::declval<T&>() ) );
560 }
561
562 template< typename T >
563 static auto test( int /*unused*/ ) -> std11::integral_constant<bool, satisfies<T>()>{}
564
565 template< typename >
566 static auto test(...) -> std11::false_type;
567 };
568
569 } // namespace detail
570
571 // is [nothow] swappable:
572
573 template< typename T >
574 struct is_swappable : decltype( detail::is_swappable::test<T>(0) ){};
575
576 template< typename T >
577 struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test<T>(0) ){};
578
579 #endif // optional_CPP17_OR_GREATER
580
581 } // namespace std17
582
583 /// type traits C++20:
584
585 namespace std20 {
586
587 template< typename T >
588 struct remove_cvref
589 {
590 typedef typename std::remove_cv< typename std::remove_reference<T>::type >::type type;
591 };
592
593 } // namespace std20
594
595 #endif // optional_CPP11_OR_GREATER
596
597 /// class optional
598
599 template< typename T >
600 class optional;
601
602 namespace detail {
603
604 // C++11 emulation:
605
606 struct nulltype{};
607
608 template< typename Head, typename Tail >
609 struct typelist
610 {
611 typedef Head head;
612 typedef Tail tail;
613 };
614
615 #if optional_CONFIG_MAX_ALIGN_HACK
616
617 // Max align, use most restricted type for alignment:
618
619 #define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ )
620 #define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line )
621 #define optional_UNIQUE3( name, line ) name ## line
622
623 #define optional_ALIGN_TYPE( type ) \
624 type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st )
625
626 template< typename T >
627 struct struct_t { T _; };
628
629 union max_align_t
630 {
631 optional_ALIGN_TYPE( char );
632 optional_ALIGN_TYPE( short int );
633 optional_ALIGN_TYPE( int );
634 optional_ALIGN_TYPE( long int );
635 optional_ALIGN_TYPE( float );
636 optional_ALIGN_TYPE( double );
637 optional_ALIGN_TYPE( long double );
638 optional_ALIGN_TYPE( char * );
639 optional_ALIGN_TYPE( short int * );
640 optional_ALIGN_TYPE( int * );
641 optional_ALIGN_TYPE( long int * );
642 optional_ALIGN_TYPE( float * );
643 optional_ALIGN_TYPE( double * );
644 optional_ALIGN_TYPE( long double * );
645 optional_ALIGN_TYPE( void * );
646
647 #ifdef HAVE_LONG_LONG
648 optional_ALIGN_TYPE( long long );
649 #endif
650
651 struct Unknown;
652
653 Unknown ( * optional_UNIQUE(_) )( Unknown );
654 Unknown * Unknown::* optional_UNIQUE(_);
655 Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown );
656
657 struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_);
658 struct_t< Unknown * Unknown::* > optional_UNIQUE(_);
659 struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_);
660 };
661
662 #undef optional_UNIQUE
663 #undef optional_UNIQUE2
664 #undef optional_UNIQUE3
665
666 #undef optional_ALIGN_TYPE
667
668 #elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK
669
670 // Use user-specified type for alignment:
671
672 #define optional_ALIGN_AS( unused ) \
673 optional_CONFIG_ALIGN_AS
674
675 #else // optional_CONFIG_MAX_ALIGN_HACK
676
677 // Determine POD type to use for alignment:
678
679 #define optional_ALIGN_AS( to_align ) \
680 typename type_of_size< alignment_types, alignment_of< to_align >::value >::type
681
682 template< typename T >
683 struct alignment_of;
684
685 template< typename T >
686 struct alignment_of_hack
687 {
688 char c;
689 T t;
690 alignment_of_hack();
691 };
692
693 template< size_t A, size_t S >
694 struct alignment_logic
695 {
696 enum { value = A < S ? A : S };
697 };
698
699 template< typename T >
700 struct alignment_of
701 {
702 enum { value = alignment_logic<
703 sizeof( alignment_of_hack<T> ) - sizeof(T), sizeof(T) >::value };
704 };
705
706 template< typename List, size_t N >
707 struct type_of_size
708 {
709 typedef typename std11::conditional<
710 N == sizeof( typename List::head ),
711 typename List::head,
712 typename type_of_size<typename List::tail, N >::type >::type type;
713 };
714
715 template< size_t N >
716 struct type_of_size< nulltype, N >
717 {
718 typedef optional_CONFIG_ALIGN_AS_FALLBACK type;
719 };
720
721 template< typename T>
722 struct struct_t { T _; };
723
724 #define optional_ALIGN_TYPE( type ) \
725 typelist< type , typelist< struct_t< type >
726
727 struct Unknown;
728
729 typedef
730 optional_ALIGN_TYPE( char ),
731 optional_ALIGN_TYPE( short ),
732 optional_ALIGN_TYPE( int ),
733 optional_ALIGN_TYPE( long ),
734 optional_ALIGN_TYPE( float ),
735 optional_ALIGN_TYPE( double ),
736 optional_ALIGN_TYPE( long double ),
737
738 optional_ALIGN_TYPE( char *),
739 optional_ALIGN_TYPE( short * ),
740 optional_ALIGN_TYPE( int * ),
741 optional_ALIGN_TYPE( long * ),
742 optional_ALIGN_TYPE( float * ),
743 optional_ALIGN_TYPE( double * ),
744 optional_ALIGN_TYPE( long double * ),
745
746 optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ),
747 optional_ALIGN_TYPE( Unknown * Unknown::* ),
748 optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ),
749
750 nulltype
751 > > > > > > > > > > > > > >
752 > > > > > > > > > > > > > >
753 > > > > > >
754 alignment_types;
755
756 #undef optional_ALIGN_TYPE
757
758 #endif // optional_CONFIG_MAX_ALIGN_HACK
759
760 /// C++03 constructed union to hold value.
761
762 template< typename T >
763 union storage_t
764 {
765 //private:
766 // template< typename > friend class optional;
767
768 typedef T value_type;
769
770 storage_t() optional_is_default
771
772 explicit storage_t( value_type const & v )
773 {
774 construct_value( v );
775 }
776
777 void construct_value( value_type const & v )
778 {
779 ::new( value_ptr() ) value_type( v );
780 }
781
782 #if optional_CPP11_OR_GREATER
783
784 explicit storage_t( value_type && v )
785 {
786 construct_value( std::move( v ) );
787 }
788
789 void construct_value( value_type && v )
790 {
791 ::new( value_ptr() ) value_type( std::move( v ) );
792 }
793
794 template< class... Args >
795 storage_t( nonstd_lite_in_place_t(T), Args&&... args )
796 {
797 emplace( std::forward<Args>(args)... );
798 }
799
800 template< class... Args >
801 void emplace( Args&&... args )
802 {
803 ::new( value_ptr() ) value_type( std::forward<Args>(args)... );
804 }
805
806 template< class U, class... Args >
807 void emplace( std::initializer_list<U> il, Args&&... args )
808 {
809 ::new( value_ptr() ) value_type( il, std::forward<Args>(args)... );
810 }
811
812 #endif
813
814 void destruct_value()
815 {
816 value_ptr()->~T();
817 }
818
819 optional_nodiscard value_type const * value_ptr() const
820 {
821 return as<value_type>();
822 }
823
824 value_type * value_ptr()
825 {
826 return as<value_type>();
827 }
828
829 optional_nodiscard value_type const & value() const optional_ref_qual
830 {
831 return * value_ptr();
832 }
833
834 value_type & value() optional_ref_qual
835 {
836 return * value_ptr();
837 }
838
839 #if optional_HAVE( REF_QUALIFIER )
840
841 optional_nodiscard value_type const && value() const optional_refref_qual
842 {
843 return std::move( value() );
844 }
845
846 value_type && value() optional_refref_qual
847 {
848 return std::move( value() );
849 }
850
851 #endif
852
853 #if optional_CPP11_OR_GREATER
854
855 using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type;
856 aligned_storage_t data;
857
858 #elif optional_CONFIG_MAX_ALIGN_HACK
859
860 typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t;
861
862 max_align_t hack;
863 aligned_storage_t data;
864
865 #else
866 typedef optional_ALIGN_AS(value_type) align_as_type;
867
868 typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t;
869 aligned_storage_t data;
870
871 # undef optional_ALIGN_AS
872
873 #endif // optional_CONFIG_MAX_ALIGN_HACK
874
875 optional_nodiscard void * ptr() optional_noexcept
876 {
877 return &data;
878 }
879
880 optional_nodiscard void const * ptr() const optional_noexcept
881 {
882 return &data;
883 }
884
885 template <typename U>
886 optional_nodiscard U * as()
887 {
888 return reinterpret_cast<U*>( ptr() );
889 }
890
891 template <typename U>
892 optional_nodiscard U const * as() const
893 {
894 return reinterpret_cast<U const *>( ptr() );
895 }
896 };
897
898 } // namespace detail
899
900 /// disengaged state tag
901
902 struct nullopt_t
903 {
904 struct init{};
905 explicit optional_constexpr nullopt_t( init /*unused*/ ) optional_noexcept {}
906 };
907
908 #if optional_HAVE( CONSTEXPR_11 )
909 constexpr nullopt_t nullopt{ nullopt_t::init{} };
910 #else
911 // extra parenthesis to prevent the most vexing parse:
912 const nullopt_t nullopt(( nullopt_t::init() ));
913 #endif
914
915 /// optional access error
916
917 #if ! optional_CONFIG_NO_EXCEPTIONS
918
919 class bad_optional_access : public std::logic_error
920 {
921 public:
922 explicit bad_optional_access()
923 : logic_error( "bad optional access" ) {}
924 };
925
926 #endif //optional_CONFIG_NO_EXCEPTIONS
927
928 /// optional
929
930 template< typename T>
931 class optional
932 {
933 optional_static_assert(( !std::is_same<typename std::remove_cv<T>::type, nullopt_t>::value ),
934 "T in optional<T> must not be of type 'nullopt_t'.")
935
936 optional_static_assert(( !std::is_same<typename std::remove_cv<T>::type, in_place_t>::value ),
937 "T in optional<T> must not be of type 'in_place_t'.")
938
939 optional_static_assert(( std::is_object<T>::value && std::is_destructible<T>::value && !std::is_array<T>::value ),
940 "T in optional<T> must meet the Cpp17Destructible requirements.")
941
942 private:
943 template< typename > friend class optional;
944
945 typedef void (optional::*safe_bool)() const;
946
947 public:
948 typedef T value_type;
949
950 // x.x.3.1, constructors
951
952 // 1a - default construct
953 optional_constexpr optional() optional_noexcept
954 : has_value_( false )
955 , contained()
956 {}
957
958 // 1b - construct explicitly empty
959 // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions )
960 optional_constexpr optional( nullopt_t /*unused*/ ) optional_noexcept
961 : has_value_( false )
962 , contained()
963 {}
964
965 // 2 - copy-construct
966 #if optional_CPP11_OR_GREATER
967 // template< typename U = T
968 // optional_REQUIRES_T(
969 // std::is_copy_constructible<U>::value
970 // || std11::is_trivially_copy_constructible<U>::value
971 // )
972 // >
973 #endif
974 optional_constexpr14 optional( optional const & other )
975 : has_value_( other.has_value() )
976 {
977 if ( other.has_value() )
978 {
979 contained.construct_value( other.contained.value() );
980 }
981 }
982
983 #if optional_CPP11_OR_GREATER
984
985 // 3 (C++11) - move-construct from optional
986 template< typename U = T
987 optional_REQUIRES_T(
988 std11::is_move_constructible<U>::value
989 || std11::is_trivially_move_constructible<U>::value
990 )
991 >
992 optional_constexpr14 optional( optional && other )
993 // NOLINTNEXTLINE( performance-noexcept-move-constructor )
994 noexcept( std11::is_nothrow_move_constructible<T>::value )
995 : has_value_( other.has_value() )
996 {
997 if ( other.has_value() )
998 {
999 contained.construct_value( std::move( other.contained.value() ) );
1000 }
1001 }
1002
1003 // 4a (C++11) - explicit converting copy-construct from optional
1004 template< typename U
1005 optional_REQUIRES_T(
1006 std::is_constructible<T, U const &>::value
1007 && !std::is_constructible<T, optional<U> & >::value
1008 && !std::is_constructible<T, optional<U> && >::value
1009 && !std::is_constructible<T, optional<U> const & >::value
1010 && !std::is_constructible<T, optional<U> const && >::value
1011 && !std::is_convertible< optional<U> & , T>::value
1012 && !std::is_convertible< optional<U> && , T>::value
1013 && !std::is_convertible< optional<U> const & , T>::value
1014 && !std::is_convertible< optional<U> const &&, T>::value
1015 && !std::is_convertible< U const & , T>::value /*=> explicit */
1016 )
1017 >
1018 explicit optional( optional<U> const & other )
1019 : has_value_( other.has_value() )
1020 {
1021 if ( other.has_value() )
1022 {
1023 contained.construct_value( T{ other.contained.value() } );
1024 }
1025 }
1026 #endif // optional_CPP11_OR_GREATER
1027
1028 // 4b (C++98 and later) - non-explicit converting copy-construct from optional
1029 template< typename U
1030 #if optional_CPP11_OR_GREATER
1031 optional_REQUIRES_T(
1032 std::is_constructible<T, U const &>::value
1033 && !std::is_constructible<T, optional<U> & >::value
1034 && !std::is_constructible<T, optional<U> && >::value
1035 && !std::is_constructible<T, optional<U> const & >::value
1036 && !std::is_constructible<T, optional<U> const && >::value
1037 && !std::is_convertible< optional<U> & , T>::value
1038 && !std::is_convertible< optional<U> && , T>::value
1039 && !std::is_convertible< optional<U> const & , T>::value
1040 && !std::is_convertible< optional<U> const &&, T>::value
1041 && std::is_convertible< U const & , T>::value /*=> non-explicit */
1042 )
1043 #endif // optional_CPP11_OR_GREATER
1044 >
1045 // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions )
1046 /*non-explicit*/ optional( optional<U> const & other )
1047 : has_value_( other.has_value() )
1048 {
1049 if ( other.has_value() )
1050 {
1051 contained.construct_value( other.contained.value() );
1052 }
1053 }
1054
1055 #if optional_CPP11_OR_GREATER
1056
1057 // 5a (C++11) - explicit converting move-construct from optional
1058 template< typename U
1059 optional_REQUIRES_T(
1060 std::is_constructible<T, U &&>::value
1061 && !std::is_constructible<T, optional<U> & >::value
1062 && !std::is_constructible<T, optional<U> && >::value
1063 && !std::is_constructible<T, optional<U> const & >::value
1064 && !std::is_constructible<T, optional<U> const && >::value
1065 && !std::is_convertible< optional<U> & , T>::value
1066 && !std::is_convertible< optional<U> && , T>::value
1067 && !std::is_convertible< optional<U> const & , T>::value
1068 && !std::is_convertible< optional<U> const &&, T>::value
1069 && !std::is_convertible< U &&, T>::value /*=> explicit */
1070 )
1071 >
1072 explicit optional( optional<U> && other
1073 )
1074 : has_value_( other.has_value() )
1075 {
1076 if ( other.has_value() )
1077 {
1078 contained.construct_value( T{ std::move( other.contained.value() ) } );
1079 }
1080 }
1081
1082 // 5a (C++11) - non-explicit converting move-construct from optional
1083 template< typename U
1084 optional_REQUIRES_T(
1085 std::is_constructible<T, U &&>::value
1086 && !std::is_constructible<T, optional<U> & >::value
1087 && !std::is_constructible<T, optional<U> && >::value
1088 && !std::is_constructible<T, optional<U> const & >::value
1089 && !std::is_constructible<T, optional<U> const && >::value
1090 && !std::is_convertible< optional<U> & , T>::value
1091 && !std::is_convertible< optional<U> && , T>::value
1092 && !std::is_convertible< optional<U> const & , T>::value
1093 && !std::is_convertible< optional<U> const &&, T>::value
1094 && std::is_convertible< U &&, T>::value /*=> non-explicit */
1095 )
1096 >
1097 // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions )
1098 /*non-explicit*/ optional( optional<U> && other )
1099 : has_value_( other.has_value() )
1100 {
1101 if ( other.has_value() )
1102 {
1103 contained.construct_value( std::move( other.contained.value() ) );
1104 }
1105 }
1106
1107 // 6 (C++11) - in-place construct
1108 template< typename... Args
1109 optional_REQUIRES_T(
1110 std::is_constructible<T, Args&&...>::value
1111 )
1112 >
1113 optional_constexpr explicit optional( nonstd_lite_in_place_t(T), Args&&... args )
1114 : has_value_( true )
1115 , contained( in_place, std::forward<Args>(args)... )
1116 {}
1117
1118 // 7 (C++11) - in-place construct, initializer-list
1119 template< typename U, typename... Args
1120 optional_REQUIRES_T(
1121 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value
1122 )
1123 >
1124 optional_constexpr explicit optional( nonstd_lite_in_place_t(T), std::initializer_list<U> il, Args&&... args )
1125 : has_value_( true )
1126 , contained( T( il, std::forward<Args>(args)...) )
1127 {}
1128
1129 // 8a (C++11) - explicit move construct from value
1130 template< typename U = T
1131 optional_REQUIRES_T(
1132 std::is_constructible<T, U&&>::value
1133 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
1134 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
1135 && !std::is_convertible<U&&, T>::value /*=> explicit */
1136 )
1137 >
1138 optional_constexpr explicit optional( U && value )
1139 : has_value_( true )
1140 , contained( nonstd_lite_in_place(T), std::forward<U>( value ) )
1141 {}
1142
1143 // 8b (C++11) - non-explicit move construct from value
1144 template< typename U = T
1145 optional_REQUIRES_T(
1146 std::is_constructible<T, U&&>::value
1147 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
1148 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
1149 && std::is_convertible<U&&, T>::value /*=> non-explicit */
1150 )
1151 >
1152 // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions )
1153 optional_constexpr /*non-explicit*/ optional( U && value )
1154 : has_value_( true )
1155 , contained( nonstd_lite_in_place(T), std::forward<U>( value ) )
1156 {}
1157
1158 #else // optional_CPP11_OR_GREATER
1159
1160 // 8 (C++98)
1161 optional( value_type const & value )
1162 : has_value_( true )
1163 , contained( value )
1164 {}
1165
1166 #endif // optional_CPP11_OR_GREATER
1167
1168 // x.x.3.2, destructor
1169
1170 ~optional()
1171 {
1172 if ( has_value() )
1173 {
1174 contained.destruct_value();
1175 }
1176 }
1177
1178 // x.x.3.3, assignment
1179
1180 // 1 (C++98and later) - assign explicitly empty
1181 optional & operator=( nullopt_t /*unused*/) optional_noexcept
1182 {
1183 reset();
1184 return *this;
1185 }
1186
1187 // 2 (C++98and later) - copy-assign from optional
1188 #if optional_CPP11_OR_GREATER
1189 // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator )
1190 optional_REQUIRES_R(
1191 optional &,
1192 true
1193 // std::is_copy_constructible<T>::value
1194 // && std::is_copy_assignable<T>::value
1195 )
1196 operator=( optional const & other )
1197 noexcept(
1198 std11::is_nothrow_move_assignable<T>::value
1199 && std11::is_nothrow_move_constructible<T>::value
1200 )
1201 #else
1202 optional & operator=( optional const & other )
1203 #endif
1204 {
1205 if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); }
1206 else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( *other ); }
1207 else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = *other; }
1208 return *this;
1209 }
1210
1211 #if optional_CPP11_OR_GREATER
1212
1213 // 3 (C++11) - move-assign from optional
1214 // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator )
1215 optional_REQUIRES_R(
1216 optional &,
1217 true
1218 // std11::is_move_constructible<T>::value
1219 // && std::is_move_assignable<T>::value
1220 )
1221 operator=( optional && other ) noexcept
1222 {
1223 if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); }
1224 else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std::move( *other ) ); }
1225 else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = std::move( *other ); }
1226 return *this;
1227 }
1228
1229 // 4 (C++11) - move-assign from value
1230 template< typename U = T >
1231 // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator )
1232 optional_REQUIRES_R(
1233 optional &,
1234 std::is_constructible<T , U>::value
1235 && std11::is_assignable<T&, U>::value
1236 && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
1237 && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value
1238 && !(std::is_scalar<T>::value && std::is_same<T, typename std::decay<U>::type>::value)
1239 )
1240 operator=( U && value )
1241 {
1242 if ( has_value() )
1243 {
1244 contained.value() = std::forward<U>( value );
1245 }
1246 else
1247 {
1248 initialize( T( std::forward<U>( value ) ) );
1249 }
1250 return *this;
1251 }
1252
1253 #else // optional_CPP11_OR_GREATER
1254
1255 // 4 (C++98) - copy-assign from value
1256 template< typename U /*= T*/ >
1257 optional & operator=( U const & value )
1258 {
1259 if ( has_value() ) contained.value() = value;
1260 else initialize( T( value ) );
1261 return *this;
1262 }
1263
1264 #endif // optional_CPP11_OR_GREATER
1265
1266 // 5 (C++98 and later) - converting copy-assign from optional
1267 template< typename U >
1268 #if optional_CPP11_OR_GREATER
1269 // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator )
1270 optional_REQUIRES_R(
1271 optional&,
1272 std::is_constructible< T , U const &>::value
1273 && std11::is_assignable< T&, U const &>::value
1274 && !std::is_constructible<T, optional<U> & >::value
1275 && !std::is_constructible<T, optional<U> && >::value
1276 && !std::is_constructible<T, optional<U> const & >::value
1277 && !std::is_constructible<T, optional<U> const && >::value
1278 && !std::is_convertible< optional<U> & , T>::value
1279 && !std::is_convertible< optional<U> && , T>::value
1280 && !std::is_convertible< optional<U> const & , T>::value
1281 && !std::is_convertible< optional<U> const &&, T>::value
1282 && !std11::is_assignable< T&, optional<U> & >::value
1283 && !std11::is_assignable< T&, optional<U> && >::value
1284 && !std11::is_assignable< T&, optional<U> const & >::value
1285 && !std11::is_assignable< T&, optional<U> const && >::value
1286 )
1287 #else
1288 optional&
1289 #endif // optional_CPP11_OR_GREATER
1290 operator=( optional<U> const & other )
1291 {
1292 return *this = optional( other );
1293 }
1294
1295 #if optional_CPP11_OR_GREATER
1296
1297 // 6 (C++11) - converting move-assign from optional
1298 template< typename U >
1299 // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator )
1300 optional_REQUIRES_R(
1301 optional&,
1302 std::is_constructible< T , U>::value
1303 && std11::is_assignable< T&, U>::value
1304 && !std::is_constructible<T, optional<U> & >::value
1305 && !std::is_constructible<T, optional<U> && >::value
1306 && !std::is_constructible<T, optional<U> const & >::value
1307 && !std::is_constructible<T, optional<U> const && >::value
1308 && !std::is_convertible< optional<U> & , T>::value
1309 && !std::is_convertible< optional<U> && , T>::value
1310 && !std::is_convertible< optional<U> const & , T>::value
1311 && !std::is_convertible< optional<U> const &&, T>::value
1312 && !std11::is_assignable< T&, optional<U> & >::value
1313 && !std11::is_assignable< T&, optional<U> && >::value
1314 && !std11::is_assignable< T&, optional<U> const & >::value
1315 && !std11::is_assignable< T&, optional<U> const && >::value
1316 )
1317 operator=( optional<U> && other )
1318 {
1319 return *this = optional( std::move( other ) );
1320 }
1321
1322 // 7 (C++11) - emplace
1323 template< typename... Args
1324 optional_REQUIRES_T(
1325 std::is_constructible<T, Args&&...>::value
1326 )
1327 >
1328 T& emplace( Args&&... args )
1329 {
1330 *this = nullopt;
1331 contained.emplace( std::forward<Args>(args)... );
1332 has_value_ = true;
1333 return contained.value();
1334 }
1335
1336 // 8 (C++11) - emplace, initializer-list
1337 template< typename U, typename... Args
1338 optional_REQUIRES_T(
1339 std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value
1340 )
1341 >
1342 T& emplace( std::initializer_list<U> il, Args&&... args )
1343 {
1344 *this = nullopt;
1345 contained.emplace( il, std::forward<Args>(args)... );
1346 has_value_ = true;
1347 return contained.value();
1348 }
1349
1350 #endif // optional_CPP11_OR_GREATER
1351
1352 // x.x.3.4, swap
1353
1354 void swap( optional & other )
1355 #if optional_CPP11_OR_GREATER
1356 noexcept(
1357 std11::is_nothrow_move_constructible<T>::value
1358 && std17::is_nothrow_swappable<T>::value
1359 )
1360 #endif
1361 {
1362 using std::swap;
1363 if ( (has_value() == true ) && (other.has_value() == true ) ) { swap( **this, *other ); }
1364 else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std11::move(*other) ); other.reset(); }
1365 else if ( (has_value() == true ) && (other.has_value() == false) ) { other.initialize( std11::move(**this) ); reset(); }
1366 }
1367
1368 // x.x.3.5, observers
1369
1370 optional_constexpr value_type const * operator ->() const
1371 {
1372 return assert( has_value() ),
1373 contained.value_ptr();
1374 }
1375
1376 optional_constexpr14 value_type * operator ->()
1377 {
1378 return assert( has_value() ),
1379 contained.value_ptr();
1380 }
1381
1382 optional_constexpr value_type const & operator *() const optional_ref_qual
1383 {
1384 return assert( has_value() ),
1385 contained.value();
1386 }
1387
1388 optional_constexpr14 value_type & operator *() optional_ref_qual
1389 {
1390 return assert( has_value() ),
1391 contained.value();
1392 }
1393
1394 #if optional_HAVE( REF_QUALIFIER )
1395
1396 optional_constexpr value_type const && operator *() const optional_refref_qual
1397 {
1398 return std::move( **this );
1399 }
1400
1401 optional_constexpr14 value_type && operator *() optional_refref_qual
1402 {
1403 return std::move( **this );
1404 }
1405
1406 #endif
1407
1408 #if optional_CPP11_OR_GREATER
1409 optional_constexpr explicit operator bool() const optional_noexcept
1410 {
1411 return has_value();
1412 }
1413 #else
1414 optional_constexpr operator safe_bool() const optional_noexcept
1415 {
1416 return has_value() ? &optional::this_type_does_not_support_comparisons : 0;
1417 }
1418 #endif
1419
1420 // NOLINTNEXTLINE( modernize-use-nodiscard )
1421 /*optional_nodiscard*/ optional_constexpr bool has_value() const optional_noexcept
1422 {
1423 return has_value_;
1424 }
1425
1426 // NOLINTNEXTLINE( modernize-use-nodiscard )
1427 /*optional_nodiscard*/ optional_constexpr14 value_type const & value() const optional_ref_qual
1428 {
1429 #if optional_CONFIG_NO_EXCEPTIONS
1430 assert( has_value() );
1431 #else
1432 if ( ! has_value() )
1433 {
1434 throw bad_optional_access();
1435 }
1436 #endif
1437 return contained.value();
1438 }
1439
1440 optional_constexpr14 value_type & value() optional_ref_qual
1441 {
1442 #if optional_CONFIG_NO_EXCEPTIONS
1443 assert( has_value() );
1444 #else
1445 if ( ! has_value() )
1446 {
1447 throw bad_optional_access();
1448 }
1449 #endif
1450 return contained.value();
1451 }
1452
1453 #if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 )
1454
1455 // NOLINTNEXTLINE( modernize-use-nodiscard )
1456 /*optional_nodiscard*/ optional_constexpr value_type const && value() const optional_refref_qual
1457 {
1458 return std::move( value() );
1459 }
1460
1461 optional_constexpr14 value_type && value() optional_refref_qual
1462 {
1463 return std::move( value() );
1464 }
1465
1466 #endif
1467
1468 #if optional_HAVE( REF_QUALIFIER )
1469
1470 template< typename U >
1471 optional_constexpr value_type value_or( U && v ) const optional_ref_qual
1472 {
1473 return has_value() ? contained.value() : static_cast<T>(std::forward<U>( v ) );
1474 }
1475
1476 template< typename U >
1477 optional_constexpr14 value_type value_or( U && v ) optional_refref_qual
1478 {
1479 #if optional_COMPILER_CLANG_VERSION
1480 return has_value() ? /*std::move*/( contained.value() ) : static_cast<T>(std::forward<U>( v ) );
1481 #else
1482 return has_value() ? std::move( contained.value() ) : static_cast<T>(std::forward<U>( v ) );
1483 #endif
1484 }
1485
1486 #else
1487
1488 template< typename U >
1489 optional_constexpr value_type value_or( U const & v ) const
1490 {
1491 return has_value() ? contained.value() : static_cast<value_type>( v );
1492 }
1493
1494 #endif // optional_HAVE( REF_QUALIFIER )
1495
1496 #if !optional_CONFIG_NO_EXTENSIONS
1497 #if optional_HAVE( REF_QUALIFIER )
1498
1499 template< typename F >
1500 optional_constexpr value_type value_or_eval( F f ) const &
1501 {
1502 return has_value() ? contained.value() : f();
1503 }
1504
1505 template< typename F >
1506 optional_constexpr14 value_type value_or_eval( F f ) &&
1507 {
1508 if ( has_value() )
1509 {
1510 return std::move( contained.value() );
1511 }
1512 else
1513 {
1514 return f();
1515 }
1516 }
1517
1518 #else
1519
1520 template< typename F >
1521 optional_constexpr value_type value_or_eval( F f ) const
1522 {
1523 return has_value() ? contained.value() : f();
1524 }
1525
1526 #endif // optional_HAVE( REF_QUALIFIER )
1527 #endif // !optional_CONFIG_NO_EXTENSIONS
1528
1529 // x.x.3.6, modifiers
1530
1531 void reset() optional_noexcept
1532 {
1533 if ( has_value() )
1534 {
1535 contained.destruct_value();
1536 }
1537
1538 has_value_ = false;
1539 }
1540
1541 private:
1542 void this_type_does_not_support_comparisons() const {}
1543
1544 template< typename V >
1545 void initialize( V const & value )
1546 {
1547 assert( ! has_value() );
1548 contained.construct_value( value );
1549 has_value_ = true;
1550 }
1551
1552 #if optional_CPP11_OR_GREATER
1553 template< typename V >
1554 void initialize( V && value )
1555 {
1556 assert( ! has_value() );
1557 contained.construct_value( std::move( value ) );
1558 has_value_ = true;
1559 }
1560
1561 #endif
1562
1563 private:
1564 bool has_value_;
1565 detail::storage_t< value_type > contained;
1566
1567 };
1568
1569 // Relational operators
1570
1571 template< typename T, typename U >
1572 optional_nodiscard optional_constexpr bool operator==( optional<T> const & x, optional<U> const & y )
1573 {
1574 return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y;
1575 }
1576
1577 template< typename T, typename U >
1578 optional_nodiscard optional_constexpr bool operator!=( optional<T> const & x, optional<U> const & y )
1579 {
1580 return !(x == y);
1581 }
1582
1583 template< typename T, typename U >
1584 optional_nodiscard optional_constexpr bool operator<( optional<T> const & x, optional<U> const & y )
1585 {
1586 return (!y) ? false : (!x) ? true : *x < *y;
1587 }
1588
1589 template< typename T, typename U >
1590 optional_nodiscard optional_constexpr bool operator>( optional<T> const & x, optional<U> const & y )
1591 {
1592 return (y < x);
1593 }
1594
1595 template< typename T, typename U >
1596 optional_nodiscard optional_constexpr bool operator<=( optional<T> const & x, optional<U> const & y )
1597 {
1598 return !(y < x);
1599 }
1600
1601 template< typename T, typename U >
1602 optional_nodiscard optional_constexpr bool operator>=( optional<T> const & x, optional<U> const & y )
1603 {
1604 return !(x < y);
1605 }
1606
1607 // Comparison with nullopt
1608
1609 template< typename T >
1610 optional_nodiscard optional_constexpr bool operator==( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
1611 {
1612 return (!x);
1613 }
1614
1615 template< typename T >
1616 optional_nodiscard optional_constexpr bool operator==( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
1617 {
1618 return (!x);
1619 }
1620
1621 template< typename T >
1622 optional_nodiscard optional_constexpr bool operator!=( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
1623 {
1624 return bool(x);
1625 }
1626
1627 template< typename T >
1628 optional_nodiscard optional_constexpr bool operator!=( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
1629 {
1630 return bool(x);
1631 }
1632
1633 template< typename T >
1634 optional_nodiscard optional_constexpr bool operator<( optional<T> const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept
1635 {
1636 return false;
1637 }
1638
1639 template< typename T >
1640 optional_nodiscard optional_constexpr bool operator<( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
1641 {
1642 return bool(x);
1643 }
1644
1645 template< typename T >
1646 optional_nodiscard optional_constexpr bool operator<=( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
1647 {
1648 return (!x);
1649 }
1650
1651 template< typename T >
1652 optional_nodiscard optional_constexpr bool operator<=( nullopt_t /*unused*/, optional<T> const & /*unused*/ ) optional_noexcept
1653 {
1654 return true;
1655 }
1656
1657 template< typename T >
1658 optional_nodiscard optional_constexpr bool operator>( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
1659 {
1660 return bool(x);
1661 }
1662
1663 template< typename T >
1664 optional_nodiscard optional_constexpr bool operator>( nullopt_t /*unused*/, optional<T> const & /*unused*/ ) optional_noexcept
1665 {
1666 return false;
1667 }
1668
1669 template< typename T >
1670 optional_nodiscard optional_constexpr bool operator>=( optional<T> const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept
1671 {
1672 return true;
1673 }
1674
1675 template< typename T >
1676 optional_nodiscard optional_constexpr bool operator>=( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
1677 {
1678 return (!x);
1679 }
1680
1681 // Comparison with T
1682
1683 template< typename T, typename U >
1684 optional_nodiscard optional_constexpr bool operator==( optional<T> const & x, U const & v )
1685 {
1686 return bool(x) ? *x == v : false;
1687 }
1688
1689 template< typename T, typename U >
1690 optional_nodiscard optional_constexpr bool operator==( U const & v, optional<T> const & x )
1691 {
1692 return bool(x) ? v == *x : false;
1693 }
1694
1695 template< typename T, typename U >
1696 optional_nodiscard optional_constexpr bool operator!=( optional<T> const & x, U const & v )
1697 {
1698 return bool(x) ? *x != v : true;
1699 }
1700
1701 template< typename T, typename U >
1702 optional_nodiscard optional_constexpr bool operator!=( U const & v, optional<T> const & x )
1703 {
1704 return bool(x) ? v != *x : true;
1705 }
1706
1707 template< typename T, typename U >
1708 optional_nodiscard optional_constexpr bool operator<( optional<T> const & x, U const & v )
1709 {
1710 return bool(x) ? *x < v : true;
1711 }
1712
1713 template< typename T, typename U >
1714 optional_nodiscard optional_constexpr bool operator<( U const & v, optional<T> const & x )
1715 {
1716 return bool(x) ? v < *x : false;
1717 }
1718
1719 template< typename T, typename U >
1720 optional_nodiscard optional_constexpr bool operator<=( optional<T> const & x, U const & v )
1721 {
1722 return bool(x) ? *x <= v : true;
1723 }
1724
1725 template< typename T, typename U >
1726 optional_nodiscard optional_constexpr bool operator<=( U const & v, optional<T> const & x )
1727 {
1728 return bool(x) ? v <= *x : false;
1729 }
1730
1731 template< typename T, typename U >
1732 optional_nodiscard optional_constexpr bool operator>( optional<T> const & x, U const & v )
1733 {
1734 return bool(x) ? *x > v : false;
1735 }
1736
1737 template< typename T, typename U >
1738 optional_nodiscard optional_constexpr bool operator>( U const & v, optional<T> const & x )
1739 {
1740 return bool(x) ? v > *x : true;
1741 }
1742
1743 template< typename T, typename U >
1744 optional_nodiscard optional_constexpr bool operator>=( optional<T> const & x, U const & v )
1745 {
1746 return bool(x) ? *x >= v : false;
1747 }
1748
1749 template< typename T, typename U >
1750 optional_nodiscard optional_constexpr bool operator>=( U const & v, optional<T> const & x )
1751 {
1752 return bool(x) ? v >= *x : true;
1753 }
1754
1755 // Specialized algorithms
1756
1757 template< typename T
1758 #if optional_CPP11_OR_GREATER
1759 optional_REQUIRES_T(
1760 std11::is_move_constructible<T>::value
1761 && std17::is_swappable<T>::value )
1762 #endif
1763 >
1764 void swap( optional<T> & x, optional<T> & y )
1765 #if optional_CPP11_OR_GREATER
1766 noexcept( noexcept( x.swap(y) ) )
1767 #endif
1768 {
1769 x.swap( y );
1770 }
1771
1772 #if optional_CPP11_OR_GREATER
1773
1774 template< typename T >
1775 optional_constexpr optional< typename std::decay<T>::type > make_optional( T && value )
1776 {
1777 return optional< typename std::decay<T>::type >( std::forward<T>( value ) );
1778 }
1779
1780 template< typename T, typename...Args >
1781 optional_constexpr optional<T> make_optional( Args&&... args )
1782 {
1783 return optional<T>( nonstd_lite_in_place(T), std::forward<Args>(args)...);
1784 }
1785
1786 template< typename T, typename U, typename... Args >
1787 optional_constexpr optional<T> make_optional( std::initializer_list<U> il, Args&&... args )
1788 {
1789 return optional<T>( nonstd_lite_in_place(T), il, std::forward<Args>(args)...);
1790 }
1791
1792 #else
1793
1794 template< typename T >
1795 optional<T> make_optional( T const & value )
1796 {
1797 return optional<T>( value );
1798 }
1799
1800 #endif // optional_CPP11_OR_GREATER
1801
1802 } // namespace optional_lite
1803
1804 using optional_lite::optional;
1805 using optional_lite::nullopt_t;
1806 using optional_lite::nullopt;
1807
1808 #if ! optional_CONFIG_NO_EXCEPTIONS
1809 using optional_lite::bad_optional_access;
1810 #endif
1811
1812 using optional_lite::make_optional;
1813
1814 } // namespace nonstd
1815
1816 #if optional_CPP11_OR_GREATER
1817
1818 // specialize the std::hash algorithm:
1819
1820 namespace std {
1821
1822 template< class T >
1823 struct hash< nonstd::optional<T> >
1824 {
1825 public:
1826 std::size_t operator()( nonstd::optional<T> const & v ) const optional_noexcept
1827 {
1828 return bool( v ) ? std::hash<T>{}( *v ) : 0;
1829 }
1830 };
1831
1832 } //namespace std
1833
1834 #endif // optional_CPP11_OR_GREATER
1835
1836 #if defined(__clang__)
1837 # pragma clang diagnostic pop
1838 #elif defined(__GNUC__)
1839 # pragma GCC diagnostic pop
1840 #elif defined(_MSC_VER )
1841 # pragma warning( pop )
1842 #endif
1843
1844 #endif // optional_USES_STD_OPTIONAL
1845
1846 #endif // NONSTD_OPTIONAL_LITE_HPP
This page took 0.095154 seconds and 4 git commands to generate.