You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1214 lines
29 KiB
1214 lines
29 KiB
//
|
|
// 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_VERSION "3.0.0"
|
|
|
|
// Compiler detection (C++20 is speculative):
|
|
// Note: MSVC supports C++14 since it supports C++17.
|
|
|
|
#ifdef _MSVC_LANG
|
|
# define optional_MSVC_LANG _MSVC_LANG
|
|
#else
|
|
# define optional_MSVC_LANG 0
|
|
#endif
|
|
|
|
#define optional_CPP11 (__cplusplus == 201103L )
|
|
#define optional_CPP11_OR_GREATER (__cplusplus >= 201103L || optional_MSVC_LANG >= 201103L )
|
|
#define optional_CPP14_OR_GREATER (__cplusplus >= 201402L || optional_MSVC_LANG >= 201703L )
|
|
#define optional_CPP17_OR_GREATER (__cplusplus >= 201703L || optional_MSVC_LANG >= 201703L )
|
|
#define optional_CPP20_OR_GREATER (__cplusplus >= 202000L || optional_MSVC_LANG >= 202000L )
|
|
|
|
// use C++17 std::optional if available:
|
|
|
|
#if defined( __has_include )
|
|
# define optional_HAS_INCLUDE( arg ) __has_include( arg )
|
|
#else
|
|
# define optional_HAS_INCLUDE( arg ) 0
|
|
#endif
|
|
|
|
#define optional_HAVE_STD_OPTIONAL ( optional_CPP17_OR_GREATER && optional_HAS_INCLUDE( <optional> ) )
|
|
|
|
#if optional_HAVE_STD_OPTIONAL
|
|
|
|
#include <optional>
|
|
|
|
namespace nonstd {
|
|
|
|
using std::optional;
|
|
using std::bad_optional_access;
|
|
using std::hash;
|
|
|
|
using std::nullopt;
|
|
using std::nullopt_t;
|
|
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;
|
|
|
|
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 // C++17 std::optional
|
|
|
|
#include <cassert>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
|
|
// 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:
|
|
|
|
#ifdef __clang__
|
|
# pragma clang diagnostic push
|
|
# pragma clang diagnostic ignored "-Wundef"
|
|
#elif defined __GNUC__
|
|
# pragma GCC diagnostic push
|
|
# pragma GCC diagnostic ignored "-Wundef"
|
|
#endif
|
|
|
|
// half-open range [lo..hi):
|
|
#define optional_BETWEEN( v, lo, hi ) ( lo <= v && v < hi )
|
|
|
|
#if defined(_MSC_VER) && !defined(__clang__)
|
|
# define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900)) )
|
|
#else
|
|
# define optional_COMPILER_MSVC_VERSION 0
|
|
#endif
|
|
|
|
#define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * major + minor ) + patch )
|
|
|
|
#if defined __GNUC__
|
|
# 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( push )
|
|
# pragma warning( disable: 4345 ) // initialization behavior changed
|
|
#endif
|
|
|
|
#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 )
|
|
# pragma warning( push )
|
|
# 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 )
|
|
|
|
// Presence of C++11 language features:
|
|
|
|
#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 100
|
|
# define optional_HAVE_AUTO 1
|
|
# define optional_HAVE_NULLPTR 1
|
|
# define optional_HAVE_STATIC_ASSERT 1
|
|
#endif
|
|
|
|
#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 120
|
|
# define optional_HAVE_DEFAULT_FUNCTION_TEMPLATE_ARG 1
|
|
# define optional_HAVE_INITIALIZER_LIST 1
|
|
#endif
|
|
|
|
#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 140
|
|
# define optional_HAVE_ALIAS_TEMPLATE 1
|
|
# define optional_HAVE_CONSTEXPR_11 1
|
|
# define optional_HAVE_ENUM_CLASS 1
|
|
# define optional_HAVE_EXPLICIT_CONVERSION 1
|
|
# define optional_HAVE_IS_DEFAULT 1
|
|
# define optional_HAVE_IS_DELETE 1
|
|
# define optional_HAVE_NOEXCEPT 1
|
|
# define optional_HAVE_REF_QUALIFIER 1
|
|
#endif
|
|
|
|
// Presence of C++14 language features:
|
|
|
|
#if optional_CPP14_OR_GREATER
|
|
# define optional_HAVE_CONSTEXPR_14 1
|
|
#endif
|
|
|
|
// Presence of C++17 language features:
|
|
|
|
#if optional_CPP17_OR_GREATER
|
|
# define optional_HAVE_ENUM_CLASS_CONSTRUCTION_FROM_UNDERLYING_TYPE 1
|
|
#endif
|
|
|
|
// Presence of C++ library features:
|
|
|
|
#if optional_COMPILER_GNUC_VERSION
|
|
# define optional_HAVE_TR1_TYPE_TRAITS 1
|
|
# define optional_HAVE_TR1_ADD_POINTER 1
|
|
#endif
|
|
|
|
#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 90
|
|
# define optional_HAVE_TYPE_TRAITS 1
|
|
# define optional_HAVE_STD_ADD_POINTER 1
|
|
#endif
|
|
|
|
#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 110
|
|
# define optional_HAVE_ARRAY 1
|
|
#endif
|
|
|
|
#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 120
|
|
# define optional_HAVE_CONDITIONAL 1
|
|
#endif
|
|
|
|
#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 140 || (optional_COMPILER_MSVC_VERSION >= 90 && _HAS_CPP0X)
|
|
# define optional_HAVE_CONTAINER_DATA_METHOD 1
|
|
#endif
|
|
|
|
#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 120
|
|
# define optional_HAVE_REMOVE_CV 1
|
|
#endif
|
|
|
|
#if optional_CPP11_OR_GREATER || optional_COMPILER_MSVC_VERSION >= 140
|
|
# define optional_HAVE_SIZED_TYPES 1
|
|
#endif
|
|
|
|
// For the rest, consider VC14 as C++11 for optional-lite:
|
|
|
|
#if optional_COMPILER_MSVC_VERSION >= 140
|
|
# undef optional_CPP11_OR_GREATER
|
|
# define optional_CPP11_OR_GREATER 1
|
|
#endif
|
|
|
|
// C++ feature usage:
|
|
|
|
#if optional_HAVE( CONSTEXPR_11 )
|
|
# define optional_constexpr constexpr
|
|
#else
|
|
# define optional_constexpr /*constexpr*/
|
|
#endif
|
|
|
|
#if optional_HAVE( CONSTEXPR_14 )
|
|
# define optional_constexpr14 constexpr
|
|
#else
|
|
# define optional_constexpr14 /*constexpr*/
|
|
#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 )
|
|
# define optional_ref_qual &
|
|
# define optional_refref_qual &&
|
|
#else
|
|
# define optional_ref_qual /*&*/
|
|
# define optional_refref_qual /*&&*/
|
|
#endif
|
|
|
|
// additional includes:
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
# include <functional>
|
|
#endif
|
|
|
|
#if optional_HAVE( INITIALIZER_LIST )
|
|
# include <initializer_list>
|
|
#endif
|
|
|
|
#if optional_HAVE( TYPE_TRAITS )
|
|
# include <type_traits>
|
|
#elif optional_HAVE( TR1_TYPE_TRAITS )
|
|
# include <tr1/type_traits>
|
|
#endif
|
|
|
|
// type traits needed:
|
|
|
|
namespace nonstd { namespace optional_lite { namespace detail {
|
|
|
|
#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<false, T, F> { typedef F type; };
|
|
#endif // optional_HAVE_CONDITIONAL
|
|
|
|
}}}
|
|
|
|
//
|
|
// in_place: code duplicated in any-lite, optional-lite, variant-lite:
|
|
//
|
|
|
|
#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
|
|
|
|
namespace nonstd {
|
|
|
|
namespace detail {
|
|
|
|
template< class T >
|
|
struct in_place_type_tag {};
|
|
|
|
template< std::size_t I >
|
|
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<T> = detail::in_place_type_tag<T>() )
|
|
{
|
|
return in_place_t();
|
|
}
|
|
|
|
template< std::size_t I >
|
|
inline in_place_t in_place( detail::in_place_index_tag<I> = detail::in_place_index_tag<I>() )
|
|
{
|
|
return in_place_t();
|
|
}
|
|
|
|
template< class T >
|
|
inline in_place_t in_place_type( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
|
|
{
|
|
return in_place_t();
|
|
}
|
|
|
|
template< std::size_t I >
|
|
inline in_place_t in_place_index( detail::in_place_index_tag<I> = detail::in_place_index_tag<I>() )
|
|
{
|
|
return in_place_t();
|
|
}
|
|
|
|
// mimic templated typedef:
|
|
|
|
#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
|
|
#define nonstd_lite_in_place_index_t(T) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<I> )
|
|
|
|
#define nonstd_lite_HAVE_IN_PLACE_TYPES 1
|
|
|
|
} // namespace nonstd
|
|
|
|
#endif // nonstd_lite_HAVE_IN_PLACE_TYPES
|
|
|
|
//
|
|
// optional:
|
|
//
|
|
|
|
namespace nonstd { namespace optional_lite {
|
|
|
|
/// class optional
|
|
|
|
template< typename T >
|
|
class optional;
|
|
|
|
namespace detail {
|
|
|
|
// 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 <unsigned A, unsigned S>
|
|
struct alignment_logic
|
|
{
|
|
enum { value = A < S ? A : S };
|
|
};
|
|
|
|
template< typename T >
|
|
struct alignment_of
|
|
{
|
|
enum { value = alignment_logic<
|
|
sizeof( alignment_of_hack<T> ) - sizeof(T), sizeof(T) >::value, };
|
|
};
|
|
|
|
template< typename List, size_t N >
|
|
struct type_of_size
|
|
{
|
|
typedef typename conditional<
|
|
N == sizeof( typename List::head ),
|
|
typename List::head,
|
|
typename type_of_size<typename List::tail, N >::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< typename T >
|
|
union storage_t
|
|
{
|
|
private:
|
|
friend class optional<T>;
|
|
|
|
typedef T value_type;
|
|
|
|
storage_t() {}
|
|
|
|
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
|
|
|
|
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< class... Args >
|
|
void emplace( Args&&... args )
|
|
{
|
|
::new( value_ptr() ) value_type( std::forward<Args>(args)... );
|
|
}
|
|
|
|
template< class U, class... Args >
|
|
void emplace( std::initializer_list<U> il, Args&&... args )
|
|
{
|
|
::new( value_ptr() ) value_type( il, std::forward<Args>(args)... );
|
|
}
|
|
|
|
#endif
|
|
|
|
void destruct_value()
|
|
{
|
|
value_ptr()->~T();
|
|
}
|
|
|
|
value_type const * value_ptr() const
|
|
{
|
|
return as<value_type>();
|
|
}
|
|
|
|
value_type * value_ptr()
|
|
{
|
|
return as<value_type>();
|
|
}
|
|
|
|
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
|
|
|
|
value_type const && value() const optional_refref_qual
|
|
{
|
|
return * value_ptr();
|
|
}
|
|
|
|
value_type && value() optional_refref_qual
|
|
{
|
|
return * value_ptr();
|
|
}
|
|
|
|
#endif
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
|
|
using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::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
|
|
|
|
void * ptr() optional_noexcept
|
|
{
|
|
return &data;
|
|
}
|
|
|
|
void const * ptr() const optional_noexcept
|
|
{
|
|
return &data;
|
|
}
|
|
|
|
template <typename U>
|
|
U * as()
|
|
{
|
|
return reinterpret_cast<U*>( ptr() );
|
|
}
|
|
|
|
template <typename U>
|
|
U const * as() const
|
|
{
|
|
return reinterpret_cast<U const *>( ptr() );
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
/// disengaged state tag
|
|
|
|
struct nullopt_t
|
|
{
|
|
struct init{};
|
|
optional_constexpr nullopt_t( init ) {}
|
|
};
|
|
|
|
#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
|
|
|
|
class bad_optional_access : public std::logic_error
|
|
{
|
|
public:
|
|
explicit bad_optional_access()
|
|
: logic_error( "bad optional access" ) {}
|
|
};
|
|
|
|
/// optional
|
|
|
|
template< typename T>
|
|
class optional
|
|
{
|
|
private:
|
|
typedef void (optional::*safe_bool)() const;
|
|
|
|
public:
|
|
typedef T value_type;
|
|
|
|
optional_constexpr optional() optional_noexcept
|
|
: has_value_( false )
|
|
, contained()
|
|
{}
|
|
|
|
optional_constexpr optional( nullopt_t ) optional_noexcept
|
|
: has_value_( false )
|
|
, contained()
|
|
{}
|
|
|
|
optional( optional const & rhs )
|
|
: has_value_( rhs.has_value() )
|
|
{
|
|
if ( rhs.has_value() )
|
|
contained.construct_value( rhs.contained.value() );
|
|
}
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
optional_constexpr14 optional( optional && rhs ) noexcept( std::is_nothrow_move_constructible<T>::value )
|
|
: has_value_( rhs.has_value() )
|
|
{
|
|
if ( rhs.has_value() )
|
|
contained.construct_value( std::move( rhs.contained.value() ) );
|
|
}
|
|
#endif
|
|
|
|
optional_constexpr optional( value_type const & value )
|
|
: has_value_( true )
|
|
, contained( value )
|
|
{}
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
|
|
optional_constexpr optional( value_type && value )
|
|
: has_value_( true )
|
|
, contained( std::move( value ) )
|
|
{}
|
|
|
|
template< class... Args >
|
|
optional_constexpr explicit optional( nonstd_lite_in_place_type_t(T), Args&&... args )
|
|
: has_value_( true )
|
|
, contained( T( std::forward<Args>(args)...) )
|
|
{}
|
|
|
|
template< class U, class... Args >
|
|
optional_constexpr explicit optional( nonstd_lite_in_place_type_t(T), std::initializer_list<U> il, Args&&... args )
|
|
: has_value_( true )
|
|
, contained( T( il, std::forward<Args>(args)...) )
|
|
{}
|
|
|
|
#endif // optional_CPP11_OR_GREATER
|
|
|
|
~optional()
|
|
{
|
|
if ( has_value() )
|
|
contained.destruct_value();
|
|
}
|
|
|
|
// assignment
|
|
|
|
optional & operator=( nullopt_t ) optional_noexcept
|
|
{
|
|
reset();
|
|
return *this;
|
|
}
|
|
|
|
optional & operator=( optional const & rhs )
|
|
#if optional_CPP11_OR_GREATER
|
|
noexcept( std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value )
|
|
#endif
|
|
{
|
|
if ( has_value() == true && rhs.has_value() == false ) reset();
|
|
else if ( has_value() == false && rhs.has_value() == true ) initialize( *rhs );
|
|
else if ( has_value() == true && rhs.has_value() == true ) contained.value() = *rhs;
|
|
return *this;
|
|
}
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
|
|
optional & operator=( optional && rhs ) noexcept
|
|
{
|
|
if ( has_value() == true && rhs.has_value() == false ) reset();
|
|
else if ( has_value() == false && rhs.has_value() == true ) initialize( std::move( *rhs ) );
|
|
else if ( has_value() == true && rhs.has_value() == true ) contained.value() = std::move( *rhs );
|
|
return *this;
|
|
}
|
|
|
|
template< class U,
|
|
typename = typename std::enable_if< std::is_same< typename std::decay<U>::type, T>::value >::type >
|
|
optional & operator=( U && v )
|
|
{
|
|
if ( has_value() ) contained.value() = std::forward<U>( v );
|
|
else initialize( T( std::forward<U>( v ) ) );
|
|
return *this;
|
|
}
|
|
|
|
template< class... Args >
|
|
void emplace( Args&&... args )
|
|
{
|
|
*this = nullopt;
|
|
contained.emplace( std::forward<Args>(args)... );
|
|
has_value_ = true;
|
|
}
|
|
|
|
|
|
template< class U, class... Args >
|
|
void emplace( std::initializer_list<U> il, Args&&... args )
|
|
{
|
|
*this = nullopt;
|
|
contained.emplace( il, std::forward<Args>(args)... );
|
|
has_value_ = true;
|
|
}
|
|
|
|
#endif // optional_CPP11_OR_GREATER
|
|
|
|
// swap
|
|
|
|
void swap( optional & rhs )
|
|
#if optional_CPP11_OR_GREATER
|
|
noexcept( std::is_nothrow_move_constructible<T>::value && noexcept( std::swap( std::declval<T&>(), std::declval<T&>() ) ) )
|
|
#endif
|
|
{
|
|
using std::swap;
|
|
if ( has_value() == true && rhs.has_value() == true ) { swap( **this, *rhs ); }
|
|
else if ( has_value() == false && rhs.has_value() == true ) { initialize( *rhs ); rhs.reset(); }
|
|
else if ( has_value() == true && rhs.has_value() == false ) { rhs.initialize( **this ); reset(); }
|
|
}
|
|
|
|
// 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_CPP11_OR_GREATER
|
|
|
|
optional_constexpr value_type const && operator *() const optional_refref_qual
|
|
{
|
|
return assert( has_value() ),
|
|
std::move( contained.value() );
|
|
}
|
|
|
|
optional_constexpr14 value_type && operator *() optional_refref_qual
|
|
{
|
|
return assert( has_value() ),
|
|
std::move( contained.value() );
|
|
}
|
|
|
|
#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
|
|
|
|
optional_constexpr bool has_value() const optional_noexcept
|
|
{
|
|
return has_value_;
|
|
}
|
|
|
|
optional_constexpr14 value_type const & value() const optional_ref_qual
|
|
{
|
|
if ( ! has_value() )
|
|
throw bad_optional_access();
|
|
|
|
return contained.value();
|
|
}
|
|
|
|
optional_constexpr14 value_type & value() optional_ref_qual
|
|
{
|
|
if ( ! has_value() )
|
|
throw bad_optional_access();
|
|
|
|
return contained.value();
|
|
}
|
|
|
|
#if optional_HAVE( REF_QUALIFIER )
|
|
|
|
optional_constexpr14 value_type const && value() const optional_refref_qual
|
|
{
|
|
if ( ! has_value() )
|
|
throw bad_optional_access();
|
|
|
|
return std::move( contained.value() );
|
|
}
|
|
|
|
optional_constexpr14 value_type && value() optional_refref_qual
|
|
{
|
|
if ( ! has_value() )
|
|
throw bad_optional_access();
|
|
|
|
return std::move( contained.value() );
|
|
}
|
|
|
|
#endif
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
|
|
template< class U >
|
|
optional_constexpr value_type value_or( U && v ) const optional_ref_qual
|
|
{
|
|
return has_value() ? contained.value() : static_cast<T>(std::forward<U>( v ) );
|
|
}
|
|
|
|
template< class U >
|
|
optional_constexpr value_type value_or( U && v ) const optional_refref_qual
|
|
{
|
|
return has_value() ? std::move( contained.value() ) : static_cast<T>(std::forward<U>( v ) );
|
|
}
|
|
|
|
#else
|
|
|
|
template< class U >
|
|
optional_constexpr value_type value_or( U const & v ) const
|
|
{
|
|
return has_value() ? contained.value() : static_cast<value_type>( v );
|
|
}
|
|
|
|
#endif // optional_CPP11_OR_GREATER
|
|
|
|
// modifiers
|
|
|
|
void reset() optional_noexcept
|
|
{
|
|
if ( has_value() )
|
|
contained.destruct_value();
|
|
|
|
has_value_ = false;
|
|
}
|
|
|
|
private:
|
|
void this_type_does_not_support_comparisons() const {}
|
|
|
|
template< typename V >
|
|
void initialize( V const & value )
|
|
{
|
|
assert( ! has_value() );
|
|
contained.construct_value( value );
|
|
has_value_ = true;
|
|
}
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
template< typename V >
|
|
void initialize( V && value )
|
|
{
|
|
assert( ! has_value() );
|
|
contained.construct_value( std::move( value ) );
|
|
has_value_ = true;
|
|
}
|
|
|
|
#endif
|
|
|
|
private:
|
|
bool has_value_;
|
|
detail::storage_t< value_type > contained;
|
|
|
|
};
|
|
|
|
// Relational operators
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator==( optional<T> const & x, optional<U> const & y )
|
|
{
|
|
return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator!=( optional<T> const & x, optional<U> const & y )
|
|
{
|
|
return !(x == y);
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator<( optional<T> const & x, optional<U> const & y )
|
|
{
|
|
return (!y) ? false : (!x) ? true : *x < *y;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator>( optional<T> const & x, optional<U> const & y )
|
|
{
|
|
return (y < x);
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator<=( optional<T> const & x, optional<U> const & y )
|
|
{
|
|
return !(y < x);
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator>=( optional<T> const & x, optional<U> const & y )
|
|
{
|
|
return !(x < y);
|
|
}
|
|
|
|
// Comparison with nullopt
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator==( optional<T> const & x, nullopt_t ) optional_noexcept
|
|
{
|
|
return (!x);
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator==( nullopt_t, optional<T> const & x ) optional_noexcept
|
|
{
|
|
return (!x);
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator!=( optional<T> const & x, nullopt_t ) optional_noexcept
|
|
{
|
|
return bool(x);
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator!=( nullopt_t, optional<T> const & x ) optional_noexcept
|
|
{
|
|
return bool(x);
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator<( optional<T> const &, nullopt_t ) optional_noexcept
|
|
{
|
|
return false;
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator<( nullopt_t, optional<T> const & x ) optional_noexcept
|
|
{
|
|
return bool(x);
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator<=( optional<T> const & x, nullopt_t ) optional_noexcept
|
|
{
|
|
return (!x);
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator<=( nullopt_t, optional<T> const & ) optional_noexcept
|
|
{
|
|
return true;
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator>( optional<T> const & x, nullopt_t ) optional_noexcept
|
|
{
|
|
return bool(x);
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator>( nullopt_t, optional<T> const & ) optional_noexcept
|
|
{
|
|
return false;
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator>=( optional<T> const &, nullopt_t ) optional_noexcept
|
|
{
|
|
return true;
|
|
}
|
|
|
|
template< typename T >
|
|
inline optional_constexpr bool operator>=( nullopt_t, optional<T> const & x ) optional_noexcept
|
|
{
|
|
return (!x);
|
|
}
|
|
|
|
// Comparison with T
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator==( optional<T> const & x, U const & v )
|
|
{
|
|
return bool(x) ? *x == v : false;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator==( U const & v, optional<T> const & x )
|
|
{
|
|
return bool(x) ? v == *x : false;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator!=( optional<T> const & x, U const & v )
|
|
{
|
|
return bool(x) ? *x != v : true;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator!=( U const & v, optional<T> const & x )
|
|
{
|
|
return bool(x) ? v != *x : true;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator<( optional<T> const & x, U const & v )
|
|
{
|
|
return bool(x) ? *x < v : true;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator<( U const & v, optional<T> const & x )
|
|
{
|
|
return bool(x) ? v < *x : false;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator<=( optional<T> const & x, U const & v )
|
|
{
|
|
return bool(x) ? *x <= v : true;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator<=( U const & v, optional<T> const & x )
|
|
{
|
|
return bool(x) ? v <= *x : false;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator>( optional<T> const & x, U const & v )
|
|
{
|
|
return bool(x) ? *x > v : false;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator>( U const & v, optional<T> const & x )
|
|
{
|
|
return bool(x) ? v > *x : true;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator>=( optional<T> const & x, U const & v )
|
|
{
|
|
return bool(x) ? *x >= v : false;
|
|
}
|
|
|
|
template< typename T, typename U >
|
|
inline optional_constexpr bool operator>=( U const & v, optional<T> const & x )
|
|
{
|
|
return bool(x) ? v >= *x : true;
|
|
}
|
|
|
|
// Specialized algorithms
|
|
|
|
template< typename T >
|
|
void swap( optional<T> & x, optional<T> & y )
|
|
#if optional_CPP11_OR_GREATER
|
|
noexcept( noexcept( x.swap(y) ) )
|
|
#endif
|
|
{
|
|
x.swap( y );
|
|
}
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
|
|
template< class T >
|
|
optional_constexpr optional< typename std::decay<T>::type > make_optional( T && v )
|
|
{
|
|
return optional< typename std::decay<T>::type >( std::forward<T>( v ) );
|
|
}
|
|
|
|
template< class T, class...Args >
|
|
optional_constexpr optional<T> make_optional( Args&&... args )
|
|
{
|
|
return optional<T>( in_place, std::forward<Args>(args)...);
|
|
}
|
|
|
|
template< class T, class U, class... Args >
|
|
optional_constexpr optional<T> make_optional( std::initializer_list<U> il, Args&&... args )
|
|
{
|
|
return optional<T>( in_place, il, std::forward<Args>(args)...);
|
|
}
|
|
|
|
#else
|
|
|
|
template< typename T >
|
|
optional<T> make_optional( T const & v )
|
|
{
|
|
return optional<T>( v );
|
|
}
|
|
|
|
#endif // optional_CPP11_OR_GREATER
|
|
|
|
} // namespace optional
|
|
|
|
using namespace optional_lite;
|
|
|
|
} // namespace nonstd
|
|
|
|
#if optional_CPP11_OR_GREATER
|
|
|
|
// specialize the std::hash algorithm:
|
|
|
|
namespace std {
|
|
|
|
template< class T >
|
|
struct hash< nonstd::optional<T> >
|
|
{
|
|
public:
|
|
std::size_t operator()( nonstd::optional<T> const & v ) const optional_noexcept
|
|
{
|
|
return bool( v ) ? hash<T>()( *v ) : 0;
|
|
}
|
|
};
|
|
|
|
} //namespace std
|
|
|
|
#endif // optional_CPP11_OR_GREATER
|
|
|
|
#ifdef __clang__
|
|
# pragma clang diagnostic pop
|
|
#elif defined __GNUC__
|
|
# pragma GCC diagnostic pop
|
|
#endif
|
|
|
|
#endif // have C++17 std::optional
|
|
|
|
#endif // NONSTD_OPTIONAL_LITE_HPP
|