// Vendored from git tag v3.2.0 // Copyright (c) 2014-2018 Martin Moene // // https://github.com/martinmoene/optional-lite // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #pragma once #ifndef NONSTD_OPTIONAL_LITE_HPP #define NONSTD_OPTIONAL_LITE_HPP #define optional_lite_MAJOR 3 #define optional_lite_MINOR 2 #define optional_lite_PATCH 0 #define optional_lite_VERSION optional_STRINGIFY(optional_lite_MAJOR) "." optional_STRINGIFY(optional_lite_MINOR) "." optional_STRINGIFY(optional_lite_PATCH) #define optional_STRINGIFY( x ) optional_STRINGIFY_( x ) #define optional_STRINGIFY_( x ) #x // optional-lite configuration: #define optional_OPTIONAL_DEFAULT 0 #define optional_OPTIONAL_NONSTD 1 #define optional_OPTIONAL_STD 2 #if !defined( optional_CONFIG_SELECT_OPTIONAL ) # define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD ) #endif // Control presence of exception handling (try and auto discover): #ifndef optional_CONFIG_NO_EXCEPTIONS # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) # define optional_CONFIG_NO_EXCEPTIONS 0 # else # define optional_CONFIG_NO_EXCEPTIONS 1 # endif #endif // C++ language version detection (C++20 is speculative): // Note: VC14.0/1900 (VS2015) lacks too much from C++14. #ifndef optional_CPLUSPLUS # if defined(_MSVC_LANG ) && !defined(__clang__) # define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) # else # define optional_CPLUSPLUS __cplusplus # endif #endif #define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L ) #define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L ) #define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L ) #define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L ) #define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L ) #define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L ) // C++ language version (represent 98 as 3): #define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) ) // Use C++17 std::optional if available and requested: #if optional_CPP17_OR_GREATER && defined(__has_include ) # if __has_include( ) # define optional_HAVE_STD_OPTIONAL 1 # else # define optional_HAVE_STD_OPTIONAL 0 # endif #else # define optional_HAVE_STD_OPTIONAL 0 #endif #define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) ) // // in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite: // #ifndef nonstd_lite_HAVE_IN_PLACE_TYPES #define nonstd_lite_HAVE_IN_PLACE_TYPES 1 // C++17 std::in_place in : #if optional_CPP17_OR_GREATER #include namespace nonstd { using std::in_place; using std::in_place_type; using std::in_place_index; using std::in_place_t; using std::in_place_type_t; using std::in_place_index_t; #define nonstd_lite_in_place_t( T) std::in_place_t #define nonstd_lite_in_place_type_t( T) std::in_place_type_t #define nonstd_lite_in_place_index_t(K) std::in_place_index_t #define nonstd_lite_in_place( T) std::in_place_t{} #define nonstd_lite_in_place_type( T) std::in_place_type_t{} #define nonstd_lite_in_place_index(K) std::in_place_index_t{} } // namespace nonstd #else // optional_CPP17_OR_GREATER #include namespace nonstd { namespace detail { template< class T > struct in_place_type_tag {}; template< std::size_t K > struct in_place_index_tag {}; } // namespace detail struct in_place_t {}; template< class T > inline in_place_t in_place( detail::in_place_type_tag /*unused*/ = detail::in_place_type_tag() ) { return in_place_t(); } template< std::size_t K > inline in_place_t in_place( detail::in_place_index_tag /*unused*/ = detail::in_place_index_tag() ) { return in_place_t(); } template< class T > inline in_place_t in_place_type( detail::in_place_type_tag /*unused*/ = detail::in_place_type_tag() ) { return in_place_t(); } template< std::size_t K > inline in_place_t in_place_index( detail::in_place_index_tag /*unused*/ = detail::in_place_index_tag() ) { return in_place_t(); } // mimic templated typedef: #define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) #define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) #define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) #define nonstd_lite_in_place( T) nonstd::in_place_type #define nonstd_lite_in_place_type( T) nonstd::in_place_type #define nonstd_lite_in_place_index(K) nonstd::in_place_index } // namespace nonstd #endif // optional_CPP17_OR_GREATER #endif // nonstd_lite_HAVE_IN_PLACE_TYPES // // Using std::optional: // #if optional_USES_STD_OPTIONAL #include namespace nonstd { using std::optional; using std::bad_optional_access; using std::hash; using std::nullopt; using std::nullopt_t; using std::operator==; using std::operator!=; using std::operator<; using std::operator<=; using std::operator>; using std::operator>=; using std::make_optional; using std::swap; } #else // optional_USES_STD_OPTIONAL #include #include // optional-lite alignment configuration: #ifndef optional_CONFIG_MAX_ALIGN_HACK # define optional_CONFIG_MAX_ALIGN_HACK 0 #endif #ifndef optional_CONFIG_ALIGN_AS // no default, used in #if defined() #endif #ifndef optional_CONFIG_ALIGN_AS_FALLBACK # define optional_CONFIG_ALIGN_AS_FALLBACK double #endif // Compiler warning suppression: #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wundef" #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wundef" #elif defined(_MSC_VER ) # pragma warning( push ) #endif // half-open range [lo..hi): #define optional_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) // Compiler versions: // // MSVC++ 6.0 _MSC_VER == 1200 (Visual Studio 6.0) // MSVC++ 7.0 _MSC_VER == 1300 (Visual Studio .NET 2002) // MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio .NET 2003) // MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) // MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) // MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) // MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) // MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) // MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) // MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017) #if defined(_MSC_VER ) && !defined(__clang__) # define optional_COMPILER_MSVC_VER (_MSC_VER ) # define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) #else # define optional_COMPILER_MSVC_VER 0 # define optional_COMPILER_MSVC_VERSION 0 #endif #define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * (major) + (minor) ) + (patch) ) #if defined(__GNUC__) && !defined(__clang__) # define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #else # define optional_COMPILER_GNUC_VERSION 0 #endif #if defined(__clang__) # define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) #else # define optional_COMPILER_CLANG_VERSION 0 #endif #if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 ) # pragma warning( disable: 4345 ) // initialization behavior changed #endif #if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 ) # pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const' #endif // Presence of language and library features: #define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE ) #ifdef _HAS_CPP0X # define optional_HAS_CPP0X _HAS_CPP0X #else # define optional_HAS_CPP0X 0 #endif // Unless defined otherwise below, consider VC14 as C++11 for optional-lite: #if optional_COMPILER_MSVC_VER >= 1900 # undef optional_CPP11_OR_GREATER # define optional_CPP11_OR_GREATER 1 #endif #define optional_CPP11_90 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1500) #define optional_CPP11_100 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1600) #define optional_CPP11_110 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1700) #define optional_CPP11_120 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1800) #define optional_CPP11_140 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1900) #define optional_CPP11_141 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1910) #define optional_CPP14_000 (optional_CPP14_OR_GREATER) #define optional_CPP17_000 (optional_CPP17_OR_GREATER) // Presence of C++11 language features: #define optional_HAVE_CONSTEXPR_11 optional_CPP11_140 #define optional_HAVE_IS_DEFAULT optional_CPP11_140 #define optional_HAVE_NOEXCEPT optional_CPP11_140 #define optional_HAVE_NULLPTR optional_CPP11_100 #define optional_HAVE_REF_QUALIFIER optional_CPP11_140 // Presence of C++14 language features: #define optional_HAVE_CONSTEXPR_14 optional_CPP14_000 // Presence of C++17 language features: #define optional_HAVE_NODISCARD optional_CPP17_000 // Presence of C++ library features: #define optional_HAVE_CONDITIONAL optional_CPP11_120 #define optional_HAVE_REMOVE_CV optional_CPP11_120 #define optional_HAVE_TYPE_TRAITS optional_CPP11_90 #define optional_HAVE_TR1_TYPE_TRAITS (!! optional_COMPILER_GNUC_VERSION ) #define optional_HAVE_TR1_ADD_POINTER (!! optional_COMPILER_GNUC_VERSION ) // C++ feature usage: #if optional_HAVE( CONSTEXPR_11 ) # define optional_constexpr constexpr #else # define optional_constexpr /*constexpr*/ #endif #if optional_HAVE( IS_DEFAULT ) # define optional_is_default = default; #else # define optional_is_default {} #endif #if optional_HAVE( CONSTEXPR_14 ) # define optional_constexpr14 constexpr #else # define optional_constexpr14 /*constexpr*/ #endif #if optional_HAVE( NODISCARD ) # define optional_nodiscard [[nodiscard]] #else # define optional_nodiscard /*[[nodiscard]]*/ #endif #if optional_HAVE( NOEXCEPT ) # define optional_noexcept noexcept #else # define optional_noexcept /*noexcept*/ #endif #if optional_HAVE( NULLPTR ) # define optional_nullptr nullptr #else # define optional_nullptr NULL #endif #if optional_HAVE( REF_QUALIFIER ) // NOLINTNEXTLINE( bugprone-macro-parentheses ) # define optional_ref_qual & # define optional_refref_qual && #else # define optional_ref_qual /*&*/ # define optional_refref_qual /*&&*/ #endif // additional includes: #if optional_CONFIG_NO_EXCEPTIONS // already included: #else # include #endif #if optional_CPP11_OR_GREATER # include #endif #if optional_HAVE( INITIALIZER_LIST ) # include #endif #if optional_HAVE( TYPE_TRAITS ) # include #elif optional_HAVE( TR1_TYPE_TRAITS ) # include #endif // Method enabling #if optional_CPP11_OR_GREATER #define optional_REQUIRES_0(...) \ template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > #define optional_REQUIRES_T(...) \ , typename = typename std::enable_if< (__VA_ARGS__), nonstd::optional_lite::detail::enabler >::type #define optional_REQUIRES_R(R, ...) \ typename std::enable_if< (__VA_ARGS__), R>::type #define optional_REQUIRES_A(...) \ , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr #endif // // optional: // namespace nonstd { namespace optional_lite { namespace std11 { #if optional_CPP11_OR_GREATER using std::move; #else template< typename T > T & move( T & t ) { return t; } #endif #if optional_HAVE( CONDITIONAL ) using std::conditional; #else template< bool B, typename T, typename F > struct conditional { typedef T type; }; template< typename T, typename F > struct conditional { typedef F type; }; #endif // optional_HAVE_CONDITIONAL } // namespace std11 #if optional_CPP11_OR_GREATER /// type traits C++17: namespace std17 { #if optional_CPP17_OR_GREATER using std::is_swappable; using std::is_nothrow_swappable; #elif optional_CPP11_OR_GREATER namespace detail { using std::swap; struct is_swappable { template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > static std::true_type test( int /*unused*/ ); template< typename > static std::false_type test(...); }; struct is_nothrow_swappable { // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015): template< typename T > static constexpr bool satisfies() { return noexcept( swap( std::declval(), std::declval() ) ); } template< typename T > static auto test( int /*unused*/ ) -> std::integral_constant()>{} template< typename > static auto test(...) -> std::false_type; }; } // namespace detail // is [nothow] swappable: template< typename T > struct is_swappable : decltype( detail::is_swappable::test(0) ){}; template< typename T > struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; #endif // optional_CPP17_OR_GREATER } // namespace std17 /// type traits C++20: namespace std20 { template< typename T > struct remove_cvref { typedef typename std::remove_cv< typename std::remove_reference::type >::type type; }; } // namespace std20 #endif // optional_CPP11_OR_GREATER /// class optional template< typename T > class optional; namespace detail { // for optional_REQUIRES_T #if optional_CPP11_OR_GREATER enum class enabler{}; #endif // C++11 emulation: struct nulltype{}; template< typename Head, typename Tail > struct typelist { typedef Head head; typedef Tail tail; }; #if optional_CONFIG_MAX_ALIGN_HACK // Max align, use most restricted type for alignment: #define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ ) #define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line ) #define optional_UNIQUE3( name, line ) name ## line #define optional_ALIGN_TYPE( type ) \ type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st ) template< typename T > struct struct_t { T _; }; union max_align_t { optional_ALIGN_TYPE( char ); optional_ALIGN_TYPE( short int ); optional_ALIGN_TYPE( int ); optional_ALIGN_TYPE( long int ); optional_ALIGN_TYPE( float ); optional_ALIGN_TYPE( double ); optional_ALIGN_TYPE( long double ); optional_ALIGN_TYPE( char * ); optional_ALIGN_TYPE( short int * ); optional_ALIGN_TYPE( int * ); optional_ALIGN_TYPE( long int * ); optional_ALIGN_TYPE( float * ); optional_ALIGN_TYPE( double * ); optional_ALIGN_TYPE( long double * ); optional_ALIGN_TYPE( void * ); #ifdef HAVE_LONG_LONG optional_ALIGN_TYPE( long long ); #endif struct Unknown; Unknown ( * optional_UNIQUE(_) )( Unknown ); Unknown * Unknown::* optional_UNIQUE(_); Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown ); struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_); struct_t< Unknown * Unknown::* > optional_UNIQUE(_); struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_); }; #undef optional_UNIQUE #undef optional_UNIQUE2 #undef optional_UNIQUE3 #undef optional_ALIGN_TYPE #elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK // Use user-specified type for alignment: #define optional_ALIGN_AS( unused ) \ optional_CONFIG_ALIGN_AS #else // optional_CONFIG_MAX_ALIGN_HACK // Determine POD type to use for alignment: #define optional_ALIGN_AS( to_align ) \ typename type_of_size< alignment_types, alignment_of< to_align >::value >::type template< typename T > struct alignment_of; template< typename T > struct alignment_of_hack { char c; T t; alignment_of_hack(); }; template< size_t A, size_t S > struct alignment_logic { enum { value = A < S ? A : S }; }; template< typename T > struct alignment_of { enum { value = alignment_logic< sizeof( alignment_of_hack ) - sizeof(T), sizeof(T) >::value }; }; template< typename List, size_t N > struct type_of_size { typedef typename std11::conditional< N == sizeof( typename List::head ), typename List::head, typename type_of_size::type >::type type; }; template< size_t N > struct type_of_size< nulltype, N > { typedef optional_CONFIG_ALIGN_AS_FALLBACK type; }; template< typename T> struct struct_t { T _; }; #define optional_ALIGN_TYPE( type ) \ typelist< type , typelist< struct_t< type > struct Unknown; typedef optional_ALIGN_TYPE( char ), optional_ALIGN_TYPE( short ), optional_ALIGN_TYPE( int ), optional_ALIGN_TYPE( long), optional_ALIGN_TYPE(float), optional_ALIGN_TYPE(double), optional_ALIGN_TYPE(long double), optional_ALIGN_TYPE(char*), optional_ALIGN_TYPE(short*), optional_ALIGN_TYPE(int*), optional_ALIGN_TYPE(long*), optional_ALIGN_TYPE(float*), optional_ALIGN_TYPE(double*), optional_ALIGN_TYPE(long double*), optional_ALIGN_TYPE(Unknown (*)(Unknown)), optional_ALIGN_TYPE(Unknown* Unknown::*), optional_ALIGN_TYPE(Unknown (Unknown::*)(Unknown)), nulltype >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> alignment_types; #undef optional_ALIGN_TYPE #endif // optional_CONFIG_MAX_ALIGN_HACK /// C++03 constructed union to hold value. template union storage_t { // private: // template< typename > friend class optional; typedef T value_type; storage_t() optional_is_default explicit storage_t(value_type const& v) { construct_value(v); } void construct_value(value_type const& v) { ::new (value_ptr()) value_type(v); } #if optional_CPP11_OR_GREATER explicit storage_t(value_type&& v) { construct_value(std::move(v)); } void construct_value(value_type&& v) { ::new (value_ptr()) value_type(std::move(v)); } template void emplace(Args&&... args) { ::new (value_ptr()) value_type(std::forward(args)...); } template void emplace(std::initializer_list il, Args&&... args) { ::new (value_ptr()) value_type(il, std::forward(args)...); } #endif void destruct_value() { value_ptr()->~T(); } optional_nodiscard value_type const* value_ptr() const { return as(); } value_type* value_ptr() { return as(); } optional_nodiscard value_type const& value() const optional_ref_qual { return *value_ptr(); } value_type& value() optional_ref_qual { return *value_ptr(); } #if optional_CPP11_OR_GREATER optional_nodiscard value_type const&& value() const optional_refref_qual { return std::move(value()); } value_type&& value() optional_refref_qual { return std::move(value()); } #endif #if optional_CPP11_OR_GREATER using aligned_storage_t = typename std::aligned_storage::type; aligned_storage_t data; #elif optional_CONFIG_MAX_ALIGN_HACK typedef struct { unsigned char data[sizeof(value_type)]; } aligned_storage_t; max_align_t hack; aligned_storage_t data; #else typedef optional_ALIGN_AS(value_type) align_as_type; typedef struct { align_as_type data[1 + (sizeof(value_type) - 1) / sizeof(align_as_type)]; } aligned_storage_t; aligned_storage_t data; #undef optional_ALIGN_AS #endif // optional_CONFIG_MAX_ALIGN_HACK optional_nodiscard void* ptr() optional_noexcept { return &data; } optional_nodiscard void const* ptr() const optional_noexcept { return &data; } template optional_nodiscard U* as() { return reinterpret_cast(ptr()); } template optional_nodiscard U const* as() const { return reinterpret_cast(ptr()); } }; } // namespace detail /// disengaged state tag struct nullopt_t { struct init {}; explicit optional_constexpr nullopt_t(init /*unused*/) optional_noexcept {} }; #if optional_HAVE(CONSTEXPR_11) constexpr nullopt_t nullopt{nullopt_t::init{}}; #else // extra parenthesis to prevent the most vexing parse: const nullopt_t nullopt((nullopt_t::init())); #endif /// optional access error #if !optional_CONFIG_NO_EXCEPTIONS class bad_optional_access : public std::logic_error { public: explicit bad_optional_access() : logic_error("bad optional access") {} }; #endif // optional_CONFIG_NO_EXCEPTIONS /// optional template class optional { private: template friend class optional; typedef void (optional::*safe_bool)() const; public: typedef T value_type; // x.x.3.1, constructors // 1a - default construct optional_constexpr optional() optional_noexcept : has_value_(false), contained() {} // 1b - construct explicitly empty // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) optional_constexpr optional(nullopt_t /*unused*/) optional_noexcept : has_value_(false), contained() {} // 2 - copy-construct optional_constexpr14 optional( optional const& other #if optional_CPP11_OR_GREATER optional_REQUIRES_A(true || std::is_copy_constructible::value) #endif ) : has_value_(other.has_value()) { if (other.has_value()) { contained.construct_value(other.contained.value()); } } #if optional_CPP11_OR_GREATER // 3 (C++11) - move-construct from optional optional_constexpr14 optional( optional&& other optional_REQUIRES_A(true || std::is_move_constructible::value) // NOLINTNEXTLINE( performance-noexcept-move-constructor ) ) noexcept(std::is_nothrow_move_constructible::value) : has_value_(other.has_value()) { if (other.has_value()) { contained.construct_value(std::move(other.contained.value())); } } // 4a (C++11) - explicit converting copy-construct from optional template explicit optional(optional const& other optional_REQUIRES_A( std::is_constructible::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_constructible const&>::value && !std::is_constructible const&&>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_convertible const&, T>::value && !std::is_convertible const&&, T>::value && !std::is_convertible::value /*=> explicit */ )) : has_value_(other.has_value()) { if (other.has_value()) { contained.construct_value(T{other.contained.value()}); } } #endif // optional_CPP11_OR_GREATER // 4b (C++98 and later) - non-explicit converting copy-construct from optional template // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) optional( optional const& other #if optional_CPP11_OR_GREATER optional_REQUIRES_A(std::is_constructible::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_constructible const&>::value && !std::is_constructible const&&>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_convertible const&, T>::value && !std::is_convertible const&&, T>::value && std::is_convertible::value /*=> non-explicit */ ) #endif // optional_CPP11_OR_GREATER ) : has_value_(other.has_value()) { if (other.has_value()) { contained.construct_value(other.contained.value()); } } #if optional_CPP11_OR_GREATER // 5a (C++11) - explicit converting move-construct from optional template explicit optional(optional&& other optional_REQUIRES_A( std::is_constructible::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_constructible const&>::value && !std::is_constructible const&&>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_convertible const&, T>::value && !std::is_convertible const&&, T>::value && !std::is_convertible::value /*=> explicit */ )) : has_value_(other.has_value()) { if (other.has_value()) { contained.construct_value(T{std::move(other.contained.value())}); } } // 5a (C++11) - non-explicit converting move-construct from optional template // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) optional(optional&& other optional_REQUIRES_A( std::is_constructible::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_constructible const&>::value && !std::is_constructible const&&>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_convertible const&, T>::value && !std::is_convertible const&&, T>::value && std::is_convertible::value /*=> non-explicit */ )) : has_value_(other.has_value()) { if (other.has_value()) { contained.construct_value(std::move(other.contained.value())); } } // 6 (C++11) - in-place construct template < typename... Args optional_REQUIRES_T(std::is_constructible::value)> optional_constexpr explicit optional(nonstd_lite_in_place_t(T), Args&&... args) : has_value_(true), contained(T(std::forward(args)...)) {} // 7 (C++11) - in-place construct, initializer-list template &, Args&&...>::value)> optional_constexpr explicit optional(nonstd_lite_in_place_t(T), std::initializer_list il, Args&&... args) : has_value_(true), contained(T(il, std::forward(args)...)) {} // 8a (C++11) - explicit move construct from value template optional_constexpr explicit optional(U&& value optional_REQUIRES_A( std::is_constructible::value && !std::is_same::type, nonstd_lite_in_place_t(U)>::value && !std::is_same::type, optional >::value && !std::is_convertible::value /*=> explicit */ )) : has_value_(true), contained(T{std::forward(value)}) {} // 8b (C++11) - non-explicit move construct from value template // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) optional_constexpr optional(U&& value optional_REQUIRES_A( std::is_constructible::value && !std::is_same::type, nonstd_lite_in_place_t(U)>::value && !std::is_same::type, optional >::value && std::is_convertible::value /*=> non-explicit */ )) : has_value_(true), contained(std::forward(value)) {} #else // optional_CPP11_OR_GREATER // 8 (C++98) optional(value_type const& value) : has_value_(true), contained(value) {} #endif // optional_CPP11_OR_GREATER // x.x.3.2, destructor ~optional() { if (has_value()) { contained.destruct_value(); } } // x.x.3.3, assignment // 1 (C++98and later) - assign explicitly empty optional& operator=(nullopt_t /*unused*/) optional_noexcept { reset(); return *this; } // 2 (C++98and later) - copy-assign from optional #if optional_CPP11_OR_GREATER // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, // misc-unconventional-assign-operator ) optional_REQUIRES_R(optional&, true // std::is_copy_constructible::value // && std::is_copy_assignable::value ) operator=(optional const& other) noexcept( std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value) #else optional& operator=(optional const& other) #endif { if ((has_value() == true) && (other.has_value() == false)) { reset(); } else if ((has_value() == false) && (other.has_value() == true)) { initialize(*other); } else if ((has_value() == true) && (other.has_value() == true)) { contained.value() = *other; } return *this; } #if optional_CPP11_OR_GREATER // 3 (C++11) - move-assign from optional // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, // misc-unconventional-assign-operator ) optional_REQUIRES_R(optional&, true // std::is_move_constructible::value // && std::is_move_assignable::value ) operator=(optional&& other) noexcept { if ((has_value() == true) && (other.has_value() == false)) { reset(); } else if ((has_value() == false) && (other.has_value() == true)) { initialize(std::move(*other)); } else if ((has_value() == true) && (other.has_value() == true)) { contained.value() = std::move(*other); } return *this; } // 4 (C++11) - move-assign from value template // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, // misc-unconventional-assign-operator ) optional_REQUIRES_R( optional&, std::is_constructible::value&& std::is_assignable::value && !std::is_same::type, nonstd_lite_in_place_t(U)>::value && !std::is_same::type, optional >::value && !(std::is_scalar::value && std::is_same::type>::value)) operator=(U&& value) { if (has_value()) { contained.value() = std::forward(value); } else { initialize(T(std::forward(value))); } return *this; } #else // optional_CPP11_OR_GREATER // 4 (C++98) - copy-assign from value template optional& operator=(U const& value) { if (has_value()) contained.value() = value; else initialize(T(value)); return *this; } #endif // optional_CPP11_OR_GREATER // 5 (C++98 and later) - converting copy-assign from optional template #if optional_CPP11_OR_GREATER // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, // misc-unconventional-assign-operator ) optional_REQUIRES_R(optional&, std::is_constructible::value&& std::is_assignable::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_constructible const&>::value && !std::is_constructible const&&>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_convertible const&, T>::value && !std::is_convertible const&&, T>::value && !std::is_assignable&>::value && !std::is_assignable&&>::value && !std::is_assignable const&>::value && !std::is_assignable const&&>::value) #else optional& #endif // optional_CPP11_OR_GREATER operator=(optional const& other) { return *this = optional(other); } #if optional_CPP11_OR_GREATER // 6 (C++11) - converting move-assign from optional template // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, // misc-unconventional-assign-operator ) optional_REQUIRES_R( optional&, std::is_constructible::value&& std::is_assignable::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_constructible const&>::value && !std::is_constructible const&&>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_convertible const&, T>::value && !std::is_convertible const&&, T>::value && !std::is_assignable&>::value && !std::is_assignable&&>::value && !std::is_assignable const&>::value && !std::is_assignable const&&>::value) operator=(optional&& other) { return *this = optional(std::move(other)); } // 7 (C++11) - emplace template < typename... Args optional_REQUIRES_T(std::is_constructible::value)> T& emplace(Args&&... args) { *this = nullopt; contained.emplace(std::forward(args)...); has_value_ = true; return contained.value(); } // 8 (C++11) - emplace, initializer-list template &, Args&&...>::value)> T& emplace(std::initializer_list il, Args&&... args) { *this = nullopt; contained.emplace(il, std::forward(args)...); has_value_ = true; return contained.value(); } #endif // optional_CPP11_OR_GREATER // x.x.3.4, swap void swap(optional& other) #if optional_CPP11_OR_GREATER noexcept(std::is_nothrow_move_constructible::value&& std17::is_nothrow_swappable::value) #endif { using std::swap; if ((has_value() == true) && (other.has_value() == true)) { swap(**this, *other); } else if ((has_value() == false) && (other.has_value() == true)) { initialize(std11::move(*other)); other.reset(); } else if ((has_value() == true) && (other.has_value() == false)) { other.initialize(std11::move(**this)); reset(); } } // x.x.3.5, observers optional_constexpr value_type const* operator->() const { return assert(has_value()), contained.value_ptr(); } optional_constexpr14 value_type* operator->() { return assert(has_value()), contained.value_ptr(); } optional_constexpr value_type const& operator*() const optional_ref_qual { return assert(has_value()), contained.value(); } optional_constexpr14 value_type& operator*() optional_ref_qual { return assert(has_value()), contained.value(); } #if optional_HAVE(REF_QUALIFIER) && \ (!optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490) optional_constexpr value_type const&& operator*() const optional_refref_qual { return std::move(**this); } optional_constexpr14 value_type&& operator*() optional_refref_qual { return std::move(**this); } #endif #if optional_CPP11_OR_GREATER optional_constexpr explicit operator bool() const optional_noexcept { return has_value(); } #else optional_constexpr operator safe_bool() const optional_noexcept { return has_value() ? &optional::this_type_does_not_support_comparisons : 0; } #endif // NOLINTNEXTLINE( modernize-use-nodiscard ) /*optional_nodiscard*/ optional_constexpr bool has_value() const optional_noexcept { return has_value_; } // NOLINTNEXTLINE( modernize-use-nodiscard ) /*optional_nodiscard*/ optional_constexpr14 value_type const& value() const optional_ref_qual { #if optional_CONFIG_NO_EXCEPTIONS assert(has_value()); #else if (!has_value()) { throw bad_optional_access(); } #endif return contained.value(); } optional_constexpr14 value_type& value() optional_ref_qual { #if optional_CONFIG_NO_EXCEPTIONS assert(has_value()); #else if (!has_value()) { throw bad_optional_access(); } #endif return contained.value(); } #if optional_HAVE(REF_QUALIFIER) && \ (!optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490) // NOLINTNEXTLINE( modernize-use-nodiscard ) /*optional_nodiscard*/ optional_constexpr value_type const&& value() const optional_refref_qual { return std::move(value()); } optional_constexpr14 value_type&& value() optional_refref_qual { return std::move(value()); } #endif #if optional_CPP11_OR_GREATER template optional_constexpr value_type value_or(U&& v) const optional_ref_qual { return has_value() ? contained.value() : static_cast(std::forward(v)); } template optional_constexpr14 value_type value_or(U&& v) optional_refref_qual { return has_value() ? std::move(contained.value()) : static_cast(std::forward(v)); } #else template optional_constexpr value_type value_or(U const& v) const { return has_value() ? contained.value() : static_cast(v); } #endif // optional_CPP11_OR_GREATER // x.x.3.6, modifiers void reset() optional_noexcept { if (has_value()) { contained.destruct_value(); } has_value_ = false; } private: void this_type_does_not_support_comparisons() const {} template void initialize(V const& value) { assert(!has_value()); contained.construct_value(value); has_value_ = true; } #if optional_CPP11_OR_GREATER template void initialize(V&& value) { assert(!has_value()); contained.construct_value(std::move(value)); has_value_ = true; } #endif private: bool has_value_; detail::storage_t contained; }; // Relational operators template inline optional_constexpr bool operator==(optional const& x, optional const& y) { return bool(x) != bool(y) ? false : !bool(x) ? true : *x == *y; } template inline optional_constexpr bool operator!=(optional const& x, optional const& y) { return !(x == y); } template inline optional_constexpr bool operator<(optional const& x, optional const& y) { return (!y) ? false : (!x) ? true : *x < *y; } template inline optional_constexpr bool operator>(optional const& x, optional const& y) { return (y < x); } template inline optional_constexpr bool operator<=(optional const& x, optional const& y) { return !(y < x); } template inline optional_constexpr bool operator>=(optional const& x, optional const& y) { return !(x < y); } // Comparison with nullopt template inline optional_constexpr bool operator==(optional const& x, nullopt_t /*unused*/) optional_noexcept { return (!x); } template inline optional_constexpr bool operator==(nullopt_t /*unused*/, optional const& x) optional_noexcept { return (!x); } template inline optional_constexpr bool operator!=(optional const& x, nullopt_t /*unused*/) optional_noexcept { return bool(x); } template inline optional_constexpr bool operator!=(nullopt_t /*unused*/, optional const& x) optional_noexcept { return bool(x); } template inline optional_constexpr bool operator<(optional const& /*unused*/, nullopt_t /*unused*/) optional_noexcept { return false; } template inline optional_constexpr bool operator<(nullopt_t /*unused*/, optional const& x) optional_noexcept { return bool(x); } template inline optional_constexpr bool operator<=(optional const& x, nullopt_t /*unused*/) optional_noexcept { return (!x); } template inline optional_constexpr bool operator<=( nullopt_t /*unused*/, optional const& /*unused*/) optional_noexcept { return true; } template inline optional_constexpr bool operator>(optional const& x, nullopt_t /*unused*/) optional_noexcept { return bool(x); } template inline optional_constexpr bool operator>( nullopt_t /*unused*/, optional const& /*unused*/) optional_noexcept { return false; } template inline optional_constexpr bool operator>=(optional const& /*unused*/, nullopt_t /*unused*/) optional_noexcept { return true; } template inline optional_constexpr bool operator>=(nullopt_t /*unused*/, optional const& x) optional_noexcept { return (!x); } // Comparison with T template inline optional_constexpr bool operator==(optional const& x, U const& v) { return bool(x) ? *x == v : false; } template inline optional_constexpr bool operator==(U const& v, optional const& x) { return bool(x) ? v == *x : false; } template inline optional_constexpr bool operator!=(optional const& x, U const& v) { return bool(x) ? *x != v : true; } template inline optional_constexpr bool operator!=(U const& v, optional const& x) { return bool(x) ? v != *x : true; } template inline optional_constexpr bool operator<(optional const& x, U const& v) { return bool(x) ? *x < v : true; } template inline optional_constexpr bool operator<(U const& v, optional const& x) { return bool(x) ? v < *x : false; } template inline optional_constexpr bool operator<=(optional const& x, U const& v) { return bool(x) ? *x <= v : true; } template inline optional_constexpr bool operator<=(U const& v, optional const& x) { return bool(x) ? v <= *x : false; } template inline optional_constexpr bool operator>(optional const& x, U const& v) { return bool(x) ? *x > v : false; } template inline optional_constexpr bool operator>(U const& v, optional const& x) { return bool(x) ? v > *x : true; } template inline optional_constexpr bool operator>=(optional const& x, U const& v) { return bool(x) ? *x >= v : false; } template inline optional_constexpr bool operator>=(U const& v, optional const& x) { return bool(x) ? v >= *x : true; } // Specialized algorithms template ::value&& std17::is_swappable::value) #endif > void swap(optional& x, optional& y) #if optional_CPP11_OR_GREATER noexcept(noexcept(x.swap(y))) #endif { x.swap(y); } #if optional_CPP11_OR_GREATER template optional_constexpr optional::type> make_optional(T&& value) { return optional::type>(std::forward(value)); } template optional_constexpr optional make_optional(Args&&... args) { return optional(nonstd_lite_in_place(T), std::forward(args)...); } template optional_constexpr optional make_optional(std::initializer_list il, Args&&... args) { return optional(nonstd_lite_in_place(T), il, std::forward(args)...); } #else template optional make_optional(T const& value) { return optional(value); } #endif // optional_CPP11_OR_GREATER } // namespace optional_lite using optional_lite::bad_optional_access; using optional_lite::nullopt; using optional_lite::nullopt_t; using optional_lite::optional; using optional_lite::make_optional; } // namespace nonstd #if optional_CPP11_OR_GREATER // specialize the std::hash algorithm: namespace std { template struct hash > { public: std::size_t operator()(nonstd::optional const& v) const optional_noexcept { return bool(v) ? std::hash{}(*v) : 0; } }; } // namespace std #endif // optional_CPP11_OR_GREATER #if defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) #pragma GCC diagnostic pop #elif defined(_MSC_VER) #pragma warning(pop) #endif #endif // optional_USES_STD_OPTIONAL #endif // NONSTD_OPTIONAL_LITE_HPP