2017-09-29 19:45:17 +01:00
///
// optional - An implementation of std::optional with extensions
// Written in 2017 by Simon Brand (@TartanLlama)
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to the
// public domain worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
2017-10-02 08:58:09 +01:00
// along with this software. If not, see
// <http://creativecommons.org/publicdomain/zero/1.0/>.
2017-09-29 19:45:17 +01:00
///
2017-10-24 09:01:24 +01:00
#ifndef TL_OPTIONAL_HPP
#define TL_OPTIONAL_HPP
2017-10-29 21:55:27 +00:00
#define TL_OPTIONAL_VERSION_MAJOR 0
#define TL_OPTIONAL_VERSION_MINOR 2
2017-10-02 08:58:09 +01:00
#include <exception>
#include <functional>
#include <new>
2017-09-29 19:45:17 +01:00
#include <type_traits>
2017-10-01 14:54:19 +01:00
#include <utility>
2017-09-29 19:45:17 +01:00
2017-10-21 22:21:49 +01:00
#if (defined(_MSC_VER) && _MSC_VER == 1900)
#define TL_OPTIONAL_MSVC2015
#endif
2017-11-01 20:01:46 +00:00
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
2017-10-21 22:21:49 +01:00
#define TL_OPTIONAL_GCC49
#endif
2017-11-01 20:01:46 +00:00
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && !defined(__clang__))
2017-10-25 09:30:54 +01:00
#define TL_OPTIONAL_GCC54
2017-10-24 15:59:38 +01:00
#endif
2017-11-01 20:01:46 +00:00
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
2017-11-01 20:24:11 +00:00
// GCC < 5 doesn't support overloading on const&& for member functions
2017-10-21 22:31:42 +01:00
#define TL_OPTIONAL_NO_CONSTRR
2017-11-01 20:24:11 +00:00
//GCC < 5 doesn't support some standard C++11 type traits
2017-11-01 19:46:46 +00:00
#define IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::has_trivial_copy_constructor<T>::value
#define IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign<T>::value
2017-11-01 20:24:11 +00:00
// This one will be different for GCC 5.7 if it's ever supported
2017-11-01 19:46:46 +00:00
#define IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value
#else
#define IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) std::is_trivially_copy_constructible<T>::value
#define IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable<T>::value
#define IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T>::value
#endif
2017-10-24 15:07:29 +01:00
#if __cplusplus > 201103L
#define TL_OPTIONAL_CXX14
#endif
2017-11-01 20:24:11 +00:00
// constexpr implies const in C++11, not C++14
2017-10-24 15:59:38 +01:00
#if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \
defined(TL_OPTIONAL_GCC49)) && \
2017-10-29 20:07:54 +00:00
!defined(TL_OPTIONAL_GCC54)
2017-10-21 09:33:16 +01:00
/// \exclude
2017-10-02 20:18:40 +01:00
#define TL_OPTIONAL_11_CONSTEXPR
#else
2017-10-21 09:33:16 +01:00
/// \exclude
2017-10-02 20:18:40 +01:00
#define TL_OPTIONAL_11_CONSTEXPR constexpr
#endif
2017-09-29 19:45:17 +01:00
namespace tl {
2017-10-21 19:04:41 +01:00
/// \brief Used to represent an optional with no data; essentially a bool
2017-10-02 12:03:52 +01:00
class monostate {};
2017-10-21 09:33:16 +01:00
/// \brief A tag type to tell optional to construct its value in-place
struct in_place_t {
explicit in_place_t () = default ;
};
/// \brief A tag to tell optional to construct its value in-place
static constexpr in_place_t in_place {};
template < class T > class optional ;
/// \exclude
2017-10-02 08:58:09 +01:00
namespace detail {
2017-10-21 22:55:58 +01:00
// C++14-style aliases for brevity
2017-10-02 08:58:09 +01:00
template < class T > using remove_const_t = typename std :: remove_const < T >:: type ;
template < class T >
using remove_reference_t = typename std :: remove_reference < T >:: type ;
template < class T > using decay_t = typename std :: decay < T >:: type ;
template < bool E , class T = void >
using enable_if_t = typename std :: enable_if < E , T >:: type ;
template < bool B , class T , class F >
using conditional_t = typename std :: conditional < B , T , F >:: type ;
2017-10-01 14:54:19 +01:00
2017-10-21 22:55:58 +01:00
// std::conjunction from C++17
2017-10-02 08:58:09 +01:00
template < class ... > struct conjunction : std :: true_type {};
template < class B > struct conjunction < B > : B {};
template < class B , class ... Bs >
struct conjunction < B , Bs ... >
: std :: conditional < bool ( B :: value ), conjunction < Bs ... > , B >:: type {};
2017-10-01 19:27:37 +01:00
2017-10-21 22:55:58 +01:00
// std::void_t from C++17
2017-10-02 08:58:09 +01:00
template < class ... > struct voider { using type = void ; };
template < class ... Ts > using void_t = typename voider < Ts ... >:: type ;
2017-10-02 12:03:52 +01:00
2017-10-21 22:55:58 +01:00
// Trait for checking if a type is a tl::optional
2017-10-02 12:03:52 +01:00
template < class T > struct is_optional_impl : std :: false_type {};
template < class T > struct is_optional_impl < optional < T >> : std :: true_type {};
template < class T > using is_optional = is_optional_impl < decay_t < T >> ;
2017-10-21 22:55:58 +01:00
// std::invoke from C++17
2017-10-02 12:03:52 +01:00
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
2017-10-17 13:08:31 +01:00
template < typename Fn , typename ... Args ,
typename = enable_if_t < std :: is_member_pointer < decay_t < Fn >> {} > ,
int = 0 >
2017-10-02 12:03:52 +01:00
constexpr auto invoke ( Fn && f , Args && ... args ) noexcept (
noexcept ( std :: mem_fn ( f )( std :: forward < Args > ( args )...)))
-> decltype ( std :: mem_fn ( f )( std :: forward < Args > ( args )...)) {
return std :: mem_fn ( f )( std :: forward < Args > ( args )...);
}
2017-10-17 13:08:31 +01:00
template < typename Fn , typename ... Args ,
typename = enable_if_t <! std :: is_member_pointer < decay_t < Fn >> {} >>
2017-10-02 12:03:52 +01:00
constexpr auto invoke ( Fn && f , Args && ... args ) noexcept (
noexcept ( std :: forward < Fn > ( f )( std :: forward < Args > ( args )...)))
-> decltype ( std :: forward < Fn > ( f )( std :: forward < Args > ( args )...)) {
return std :: forward < Fn > ( f )( std :: forward < Args > ( args )...);
}
2017-10-21 22:55:58 +01:00
// std::invoke_result from C++17
2017-10-02 12:03:52 +01:00
template < class F , class , class ... Us > struct invoke_result_impl ;
template < class F , class ... Us >
struct invoke_result_impl <
F , decltype ( invoke ( std :: declval < F > (), std :: declval < Us > ()...), void ()),
Us ... > {
using type = decltype ( invoke ( std :: declval < F > (), std :: declval < Us > ()...));
};
template < class F , class ... Us >
using invoke_result = invoke_result_impl < F , void , Us ... > ;
template < class F , class ... Us >
using invoke_result_t = typename invoke_result < F , Us ... >:: type ;
2017-10-21 22:55:58 +01:00
// Change void to tl::monostate
2017-10-02 12:03:52 +01:00
template < class U >
2017-10-02 14:00:56 +01:00
using fixup_void = conditional_t < std :: is_void < U >:: value , monostate , U > ;
2017-10-02 12:03:52 +01:00
2017-10-24 15:07:29 +01:00
template < class F , class U , class = invoke_result_t < F , U >>
using get_map_return = optional < fixup_void < invoke_result_t < F , U >>> ;
2017-10-02 12:03:52 +01:00
2017-10-21 22:55:58 +01:00
// Check if invoking F for some Us returns void
2017-10-24 15:07:29 +01:00
template < class F , class = void , class ... U > struct returns_void_impl ;
2017-10-06 10:03:12 +01:00
template < class F , class ... U >
2017-10-24 15:07:29 +01:00
struct returns_void_impl < F , void_t < invoke_result_t < F , U ... >> , U ... >
: std :: is_void < invoke_result_t < F , U ... >> {};
template < class F , class ... U >
using returns_void = returns_void_impl < F , void , U ... > ;
2017-10-02 14:00:56 +01:00
2017-10-06 10:03:12 +01:00
template < class T , class ... U >
using enable_if_ret_void = enable_if_t < returns_void < T && , U ... >:: value > ;
2017-10-02 14:00:56 +01:00
2017-10-06 10:03:12 +01:00
template < class T , class ... U >
using disable_if_ret_void = enable_if_t <! returns_void < T && , U ... >:: value > ;
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U >
using enable_forward_value =
detail :: enable_if_t < std :: is_constructible < T , U &&>:: value &&
! std :: is_same < detail :: decay_t < U > , in_place_t >:: value &&
! std :: is_same < optional < T > , detail :: decay_t < U >>:: value > ;
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U , class Other >
using enable_from_other = detail :: enable_if_t <
std :: is_constructible < T , Other >:: value &&
! std :: is_constructible < T , optional < U > &>:: value &&
! std :: is_constructible < T , optional < U > &&>:: value &&
! std :: is_constructible < T , const optional < U > &>:: value &&
! std :: is_constructible < T , const optional < U > &&>:: value &&
! std :: is_convertible < optional < U > & , T >:: value &&
! std :: is_convertible < optional < U > && , T >:: value &&
! std :: is_convertible < const optional < U > & , T >:: value &&
! std :: is_convertible < const optional < U > && , T >:: value > ;
2017-10-01 19:27:37 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U >
using enable_assign_forward = detail :: enable_if_t <
! std :: is_same < optional < T > , detail :: decay_t < U >>:: value &&
! detail :: conjunction < std :: is_scalar < T > ,
std :: is_same < T , detail :: decay_t < U >>>:: value &&
std :: is_constructible < T , U >:: value && std :: is_assignable < T & , U >:: value > ;
2017-10-01 19:27:37 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U , class Other >
using enable_assign_from_other = detail :: enable_if_t <
std :: is_constructible < T , Other >:: value &&
std :: is_assignable < T & , Other >:: value &&
! std :: is_constructible < T , optional < U > &>:: value &&
! std :: is_constructible < T , optional < U > &&>:: value &&
! std :: is_constructible < T , const optional < U > &>:: value &&
! std :: is_constructible < T , const optional < U > &&>:: value &&
! std :: is_convertible < optional < U > & , T >:: value &&
! std :: is_convertible < optional < U > && , T >:: value &&
! std :: is_convertible < const optional < U > & , T >:: value &&
! std :: is_convertible < const optional < U > && , T >:: value &&
! std :: is_assignable < T & , optional < U > &>:: value &&
! std :: is_assignable < T & , optional < U > &&>:: value &&
! std :: is_assignable < T & , const optional < U > &>:: value &&
! std :: is_assignable < T & , const optional < U > &&>:: value > ;
2017-10-01 14:54:19 +01:00
2017-10-17 11:54:57 +01:00
#ifdef _MSC_VER
// TODO make a version which works with MSVC
template < class T , class U = T > struct is_swappable : std :: true_type {};
template < class T , class U = T > struct is_nothrow_swappable : std :: true_type {};
#else
2017-10-02 08:58:09 +01:00
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
namespace swap_adl_tests {
// if swap ADL finds this then it would call std::swap otherwise (same
// signature)
struct tag {};
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
template < class T > tag swap ( T & , T & );
template < class T , std :: size_t N > tag swap ( T ( & a )[ N ], T ( & b )[ N ]);
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
// helper functions to test if an unqualified swap is possible, and if it
// becomes std::swap
template < class , class > std :: false_type can_swap (...) noexcept ( false );
template < class T , class U ,
class = decltype ( swap ( std :: declval < T &> (), std :: declval < U &> ())) >
std :: true_type can_swap ( int ) noexcept ( noexcept ( swap ( std :: declval < T &> (),
std :: declval < U &> ())));
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
template < class , class > std :: false_type uses_std (...);
template < class T , class U >
std :: is_same < decltype ( swap ( std :: declval < T &> (), std :: declval < U &> ())), tag >
uses_std ( int );
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T >
struct is_std_swap_noexcept
: std :: integral_constant < bool ,
std :: is_nothrow_move_constructible < T >:: value &&
std :: is_nothrow_move_assignable < T >:: value > {};
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T , std :: size_t N >
struct is_std_swap_noexcept < T [ N ] > : is_std_swap_noexcept < T > {};
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U >
struct is_adl_swap_noexcept
: std :: integral_constant < bool , noexcept ( can_swap < T , U > ( 0 )) > {};
2017-10-17 11:54:57 +01:00
} // namespace swap_adl_tests
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U = T >
struct is_swappable
: std :: integral_constant <
bool ,
decltype ( detail :: swap_adl_tests :: can_swap < T , U > ( 0 )) :: value &&
( ! decltype ( detail :: swap_adl_tests :: uses_std < T , U > ( 0 )) :: value ||
( std :: is_move_assignable < T >:: value &&
std :: is_move_constructible < T >:: value )) > {};
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T , std :: size_t N >
struct is_swappable < T [ N ], T [ N ] >
: std :: integral_constant <
bool ,
decltype ( detail :: swap_adl_tests :: can_swap < T [ N ], T [ N ] > ( 0 )) :: value &&
( ! decltype (
detail :: swap_adl_tests :: uses_std < T [ N ], T [ N ] > ( 0 )) :: value ||
is_swappable < T , T >:: value ) > {};
2017-10-02 08:57:21 +01:00
2017-10-02 08:58:09 +01:00
template < class T , class U = T >
struct is_nothrow_swappable
: std :: integral_constant <
bool ,
is_swappable < T , U >:: value &&
(( decltype ( detail :: swap_adl_tests :: uses_std < T , U > ( 0 )) :: value
&& detail :: swap_adl_tests :: is_std_swap_noexcept < T >:: value ) ||
( ! decltype ( detail :: swap_adl_tests :: uses_std < T , U > ( 0 )) :: value &&
detail :: swap_adl_tests :: is_adl_swap_noexcept < T ,
U >:: value )) > {
};
2017-10-11 19:18:08 +01:00
#endif
2017-11-01 20:24:11 +00:00
// The storage base manages the actual storage, and correctly propagates trivial destruction from T
// This case is for when T is trivially destructible
2017-10-21 19:04:41 +01:00
template < class T , bool = :: std :: is_trivially_destructible < T >:: value >
struct optional_storage_base {
2017-10-24 15:07:29 +01:00
TL_OPTIONAL_11_CONSTEXPR optional_storage_base () noexcept
: m_dummy (), m_has_value ( false ) {}
2017-10-21 19:04:41 +01:00
template < class ... U >
2017-11-01 15:43:58 +00:00
TL_OPTIONAL_11_CONSTEXPR optional_storage_base ( in_place_t , U && ... u )
2017-10-21 19:04:41 +01:00
: m_value ( std :: forward < U > ( u )...), m_has_value ( true ) {}
~ optional_storage_base () {
if ( m_has_value ) {
m_value . ~ T ();
m_has_value = false ;
}
}
struct dummy {};
union {
dummy m_dummy ;
T m_value ;
};
bool m_has_value ;
};
2017-11-01 20:24:11 +00:00
// This case is for when T is not trivially destructible
2017-10-21 19:04:41 +01:00
template < class T > struct optional_storage_base < T , true > {
2017-10-24 15:07:29 +01:00
TL_OPTIONAL_11_CONSTEXPR optional_storage_base () noexcept
2017-10-21 19:04:41 +01:00
: m_dummy (), m_has_value ( false ) {}
template < class ... U >
2017-11-01 15:43:58 +00:00
TL_OPTIONAL_11_CONSTEXPR optional_storage_base ( in_place_t , U && ... u )
2017-10-21 19:04:41 +01:00
: m_value ( std :: forward < U > ( u )...), m_has_value ( true ) {}
2017-11-01 20:24:11 +00:00
// No destructor, so this class is trivially destructible
2017-10-21 19:04:41 +01:00
struct dummy {};
union {
dummy m_dummy ;
T m_value ;
};
bool m_has_value = false ;
};
2017-10-24 15:07:29 +01:00
2017-11-01 20:24:11 +00:00
// This base class provides some handy member functions which can be used in further derived classes
2017-11-01 15:43:58 +00:00
template < class T > struct optional_operations_base : optional_storage_base < T > {
using optional_storage_base < T >:: optional_storage_base ;
2017-11-01 19:54:18 +00:00
void hard_reset () noexcept {
get (). ~ T ();
this -> m_has_value = false ;
2017-11-01 15:43:58 +00:00
}
template < class ... Args > void construct ( Args && ... args ) noexcept {
new ( std :: addressof ( this -> m_value )) T ( std :: forward < Args > ( args )...);
this -> m_has_value = true ;
}
template < class Opt > void assign ( Opt && rhs ) {
2017-11-01 19:54:18 +00:00
if ( this -> has_value ()) {
if ( rhs . has_value ()) {
2017-11-01 19:46:46 +00:00
this -> m_value = std :: forward < Opt > ( rhs ). get ();
} else {
this -> m_value . ~ T ();
this -> m_has_value = false ;
2017-11-01 15:43:58 +00:00
}
}
2017-11-01 19:46:46 +00:00
2017-11-01 19:54:18 +00:00
if ( rhs . has_value ()) {
2017-11-01 19:46:46 +00:00
construct ( std :: forward < Opt > ( rhs ). get ());
}
2017-11-01 15:43:58 +00:00
}
2017-11-01 19:54:18 +00:00
bool has_value () const { return this -> m_has_value ; }
2017-11-01 15:43:58 +00:00
TL_OPTIONAL_11_CONSTEXPR T & get () & { return this -> m_value ; }
TL_OPTIONAL_11_CONSTEXPR const T & get () const & { return this -> m_value ; }
TL_OPTIONAL_11_CONSTEXPR T && get () && { std :: move ( this -> m_value ); }
#ifndef TL_OPTIONAL_NO_CONSTRR
constexpr const T && get () const && { return std :: move ( this -> m_value ); }
#endif
};
2017-11-01 20:24:11 +00:00
// This class manages conditionally having a trivial copy constructor
// This specialization is for when T is trivially copy constructible
template < class T , bool = IS_TRIVIALLY_COPY_CONSTRUCTIBLE ( T ) >
2017-11-01 15:43:58 +00:00
struct optional_copy_base : optional_operations_base < T > {
using optional_operations_base < T >:: optional_operations_base ;
};
2017-11-01 20:24:11 +00:00
// This specialization is for when T is not trivially copy constructible
2017-11-01 15:43:58 +00:00
template < class T >
struct optional_copy_base < T , false > : optional_operations_base < T > {
using optional_operations_base < T >:: optional_operations_base ;
optional_copy_base () = default ;
optional_copy_base ( const optional_copy_base & rhs ) {
2017-11-01 19:54:18 +00:00
if ( rhs . has_value ()) {
2017-11-01 15:43:58 +00:00
this -> construct ( rhs . get ());
} else {
2017-11-01 20:06:03 +00:00
this -> m_has_value = false ;
2017-11-01 15:43:58 +00:00
}
}
optional_copy_base ( optional_copy_base && rhs ) = default ;
optional_copy_base & operator = ( const optional_copy_base & rhs ) = default ;
optional_copy_base & operator = ( optional_copy_base && rhs ) = default ;
};
2017-11-01 20:24:11 +00:00
// This class manages conditionally having a trivial move constructor
// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it doesn't implement an analogue to std::is_trivially_move_constructible. We have to make do with a non-trivial move constructor even if T is trivially move constructible
2017-11-01 19:46:46 +00:00
#ifndef TL_OPTIONAL_GCC49
2017-11-01 15:43:58 +00:00
template < class T , bool = std :: is_trivially_move_constructible < T >:: value >
struct optional_move_base : optional_copy_base < T > {
using optional_copy_base < T >:: optional_copy_base ;
};
2017-11-01 19:46:46 +00:00
#else
template < class T , bool = false >
struct optional_move_base ;
#endif
2017-11-01 15:43:58 +00:00
template < class T > struct optional_move_base < T , false > : optional_copy_base < T > {
using optional_copy_base < T >:: optional_copy_base ;
optional_move_base () = default ;
optional_move_base ( const optional_move_base & rhs ) = default ;
optional_move_base ( optional_move_base && rhs ) noexcept (
std :: is_nothrow_move_constructible < T >:: value ) {
2017-11-01 19:54:18 +00:00
if ( rhs . has_value ()) {
2017-11-01 15:43:58 +00:00
this -> construct ( std :: move ( rhs . get ()));
} else {
2017-11-01 20:06:03 +00:00
this -> m_has_value = false ;
2017-11-01 15:43:58 +00:00
}
}
optional_move_base & operator = ( const optional_move_base & rhs ) = default ;
optional_move_base & operator = ( optional_move_base && rhs ) = default ;
};
2017-11-01 20:24:11 +00:00
// This class manages conditionally having a trivial copy assignment operator
2017-11-01 19:46:46 +00:00
template < class T , bool = IS_TRIVIALLY_COPY_ASSIGNABLE ( T ) && IS_TRIVIALLY_COPY_CONSTRUCTIBLE ( T ) && IS_TRIVIALLY_DESTRUCTIBLE ( T ) >
2017-11-01 15:43:58 +00:00
struct optional_copy_assign_base : optional_move_base < T > {
using optional_move_base < T >:: optional_move_base ;
};
template < class T >
struct optional_copy_assign_base < T , false > : optional_move_base < T > {
using optional_move_base < T >:: optional_move_base ;
optional_copy_assign_base () = default ;
optional_copy_assign_base ( const optional_copy_assign_base & rhs ) = default ;
optional_copy_assign_base ( optional_copy_assign_base && rhs ) = default ;
optional_copy_assign_base & operator = ( const optional_copy_assign_base & rhs ) {
2017-11-01 19:46:46 +00:00
this -> assign ( rhs );
2017-11-01 15:43:58 +00:00
}
optional_copy_assign_base &
operator = ( optional_copy_assign_base && rhs ) = default ;
};
2017-11-01 19:46:46 +00:00
2017-11-01 20:24:11 +00:00
// This class manages conditionally having a trivial move assignment operator
// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it doesn't implement an analogue to std::is_trivially_move_assignable. We have to make do with a non-trivial move assignment operator even if T is trivially move assignable
2017-11-01 19:46:46 +00:00
#ifndef TL_OPTIONAL_GCC49
template < class T , bool = std :: is_trivially_destructible < T >:: value && std :: is_trivially_move_constructible < T >:: value && std :: is_trivially_move_assignable < T >:: value >
2017-11-01 15:43:58 +00:00
struct optional_move_assign_base : optional_copy_assign_base < T > {
using optional_copy_assign_base < T >:: optional_copy_assign_base ;
};
2017-11-01 19:46:46 +00:00
#else
template < class T , bool = false >
struct optional_move_assign_base ;
#endif
2017-11-01 15:43:58 +00:00
2017-11-01 19:46:46 +00:00
template < class T >
struct optional_move_assign_base < T , false > : optional_copy_assign_base < T > {
2017-11-01 15:43:58 +00:00
using optional_copy_assign_base < T >:: optional_copy_assign_base ;
optional_move_assign_base () = default ;
optional_move_assign_base ( const optional_move_assign_base & rhs ) = default ;
optional_move_assign_base ( optional_move_assign_base && rhs ) = default ;
optional_move_assign_base &
operator = ( const optional_move_assign_base & rhs ) noexcept (
std :: is_nothrow_move_constructible < T >:: value
&& std :: is_nothrow_move_assignable < T >:: value ) {
2017-11-01 19:46:46 +00:00
this -> assign ( std :: move ( rhs ));
2017-11-01 15:43:58 +00:00
}
optional_move_assign_base &
operator = ( optional_move_assign_base && rhs ) = default ;
};
2017-11-01 20:24:11 +00:00
// optional_delete_ctor_base will conditionally delete copy and move constructors depending on whether T is copy/move constructible
2017-11-01 15:43:58 +00:00
template < class T , bool EnableCopy = std :: is_copy_constructible < T >:: value ,
bool EnableMove = std :: is_move_constructible < T >:: value >
struct optional_delete_ctor_base {
optional_delete_ctor_base () = default ;
optional_delete_ctor_base ( const optional_delete_ctor_base & ) = default ;
optional_delete_ctor_base ( optional_delete_ctor_base && ) noexcept = default ;
optional_delete_ctor_base &
operator = ( const optional_delete_ctor_base & ) = default ;
optional_delete_ctor_base &
operator = ( optional_delete_ctor_base && ) noexcept = default ;
};
template < class T > struct optional_delete_ctor_base < T , true , false > {
optional_delete_ctor_base () = default ;
optional_delete_ctor_base ( const optional_delete_ctor_base & ) = default ;
optional_delete_ctor_base ( optional_delete_ctor_base && ) noexcept = delete ;
optional_delete_ctor_base &
operator = ( const optional_delete_ctor_base & ) = default ;
optional_delete_ctor_base &
operator = ( optional_delete_ctor_base && ) noexcept = default ;
};
template < class T > struct optional_delete_ctor_base < T , false , true > {
optional_delete_ctor_base () = default ;
optional_delete_ctor_base ( const optional_delete_ctor_base & ) = delete ;
optional_delete_ctor_base ( optional_delete_ctor_base && ) noexcept = default ;
optional_delete_ctor_base &
operator = ( const optional_delete_ctor_base & ) = default ;
optional_delete_ctor_base &
operator = ( optional_delete_ctor_base && ) noexcept = default ;
};
template < class T > struct optional_delete_ctor_base < T , false , false > {
optional_delete_ctor_base () = default ;
optional_delete_ctor_base ( const optional_delete_ctor_base & ) = delete ;
optional_delete_ctor_base ( optional_delete_ctor_base && ) noexcept = delete ;
optional_delete_ctor_base &
operator = ( const optional_delete_ctor_base & ) = default ;
optional_delete_ctor_base &
operator = ( optional_delete_ctor_base && ) noexcept = default ;
};
2017-11-01 20:24:11 +00:00
// optional_delete_assign_base will conditionally delete copy and move constructors depending on whether T is copy/move constructible + assignable
2017-11-01 15:43:58 +00:00
template < class T ,
bool EnableCopy = ( std :: is_copy_constructible < T >:: value &&
std :: is_copy_assignable < T >:: value ),
bool EnableMove = ( std :: is_move_constructible < T >:: value &&
std :: is_move_assignable < T >:: value ) >
struct optional_delete_assign_base {
optional_delete_assign_base () = default ;
optional_delete_assign_base ( const optional_delete_assign_base & ) = default ;
optional_delete_assign_base ( optional_delete_assign_base && ) noexcept =
default ;
optional_delete_assign_base &
operator = ( const optional_delete_assign_base & ) = default ;
optional_delete_assign_base &
operator = ( optional_delete_assign_base && ) noexcept = default ;
};
template < class T > struct optional_delete_assign_base < T , true , false > {
optional_delete_assign_base () = default ;
optional_delete_assign_base ( const optional_delete_assign_base & ) = default ;
optional_delete_assign_base ( optional_delete_assign_base && ) noexcept =
default ;
optional_delete_assign_base &
operator = ( const optional_delete_assign_base & ) = default ;
optional_delete_assign_base &
operator = ( optional_delete_assign_base && ) noexcept = delete ;
};
template < class T > struct optional_delete_assign_base < T , false , true > {
optional_delete_assign_base () = default ;
optional_delete_assign_base ( const optional_delete_assign_base & ) = default ;
optional_delete_assign_base ( optional_delete_assign_base && ) noexcept =
default ;
optional_delete_assign_base &
operator = ( const optional_delete_assign_base & ) = delete ;
optional_delete_assign_base &
operator = ( optional_delete_assign_base && ) noexcept = default ;
};
template < class T > struct optional_delete_assign_base < T , false , false > {
optional_delete_assign_base () = default ;
optional_delete_assign_base ( const optional_delete_assign_base & ) = default ;
optional_delete_assign_base ( optional_delete_assign_base && ) noexcept =
default ;
optional_delete_assign_base &
operator = ( const optional_delete_assign_base & ) = delete ;
optional_delete_assign_base &
operator = ( optional_delete_assign_base && ) noexcept = delete ;
};
2017-10-17 11:54:57 +01:00
} // namespace detail
2017-10-02 08:57:21 +01:00
2017-10-21 09:33:16 +01:00
/// \brief A tag type to represent an empty optional
2017-10-02 08:58:09 +01:00
struct nullopt_t {
struct do_not_use {};
constexpr explicit nullopt_t ( do_not_use , do_not_use ) noexcept {}
};
2017-10-21 09:33:16 +01:00
/// \brief Represents an empty optional
/// \synopsis static constexpr nullopt_t nullopt;
///
/// *Examples*:
/// ```
/// tl::optional<int> a = tl::nullopt;
/// void foo (tl::optional<int>);
/// foo(tl::nullopt); //pass an empty optional
/// ```
2017-10-02 08:58:09 +01:00
static constexpr nullopt_t nullopt { nullopt_t :: do_not_use {},
nullopt_t :: do_not_use {}};
2017-10-01 14:54:19 +01:00
2017-10-02 08:58:09 +01:00
class bad_optional_access : public std :: exception {
public :
bad_optional_access () = default ;
const char * what () const noexcept { return "Optional has no value" ; }
};
2017-09-29 19:45:17 +01:00
2017-10-24 15:07:29 +01:00
/// An optional object is an object that contains the storage for another object
/// and manages the lifetime of this contained object, if any. The contained
/// object may be initialized after the optional object has been initialized,
/// and may be destroyed before the optional object has been destroyed. The
/// initialization state of the contained object is tracked by the optional
/// object.
2017-11-01 15:43:58 +00:00
template < class T >
class optional : private detail :: optional_move_assign_base < T > ,
private detail :: optional_delete_ctor_base < T > ,
private detail :: optional_delete_assign_base < T > {
using base = detail :: optional_move_assign_base < T > ;
2017-10-21 19:04:41 +01:00
public :
2017-10-24 15:46:07 +01:00
// The different versions for C++14 and 11 are needed because deduced return
2017-11-01 20:24:11 +00:00
// types are not SFINAE-safe. This provides better support for things like generic lambdas. C.f.
2017-10-24 15:46:07 +01:00
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html
2017-10-29 20:07:54 +00:00
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && !defined(TL_EXPECTED_GCC54)
2017-10-24 15:32:22 +01:00
/// \group and_then
/// Carries out some operation which returns an optional on the stored object
/// if there is one. \requires `std::invoke(std::forward<F>(f), value())`
/// returns a `std::optional<U>` for some `U`. \returns Let `U` be the result
/// of `std::invoke(std::forward<F>(f), value())`. Returns a
/// `std::optional<U>`. The return value is empty if `*this` is empty,
/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
/// is returned. \group and_then \synopsis template <class F>\nconstexpr auto
/// and_then(F &&f) &;
template < class F > TL_OPTIONAL_11_CONSTEXPR auto and_then ( F && f ) & {
using result = detail :: invoke_result_t < F , T &> ;
static_assert ( detail :: is_optional < result >:: value ,
"F must return an optional" );
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), ** this )
: result ( nullopt );
}
/// \group and_then
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
template < class F > TL_OPTIONAL_11_CONSTEXPR auto and_then ( F && f ) && {
using result = detail :: invoke_result_t < F , T &&> ;
static_assert ( detail :: is_optional < result >:: value ,
"F must return an optional" );
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), std :: move ( ** this ))
: result ( nullopt );
}
/// \group and_then
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
template < class F > constexpr auto and_then ( F && f ) const & {
using result = detail :: invoke_result_t < F , const T &> ;
static_assert ( detail :: is_optional < result >:: value ,
"F must return an optional" );
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), ** this )
: result ( nullopt );
}
#ifndef TL_OPTIONAL_NO_CONSTRR
/// \group and_then
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
template < class F > constexpr auto and_then ( F && f ) const && {
using result = detail :: invoke_result_t < F , const T &&> ;
static_assert ( detail :: is_optional < result >:: value ,
"F must return an optional" );
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), std :: move ( ** this ))
: result ( nullopt );
}
#endif
#else
2017-10-21 19:04:41 +01:00
/// \group and_then
2017-10-24 15:07:29 +01:00
/// Carries out some operation which returns an optional on the stored object
/// if there is one. \requires `std::invoke(std::forward<F>(f), value())`
/// returns a `std::optional<U>` for some `U`. \returns Let `U` be the result
/// of `std::invoke(std::forward<F>(f), value())`. Returns a
/// `std::optional<U>`. The return value is empty if `*this` is empty,
/// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
/// is returned. \group and_then \synopsis template <class F>\nconstexpr auto
/// and_then(F &&f) &;
2017-10-21 19:04:41 +01:00
template < class F >
2017-10-24 15:32:22 +01:00
TL_OPTIONAL_11_CONSTEXPR detail :: invoke_result_t < F , T &> and_then ( F && f ) & {
using result = detail :: invoke_result_t < F , T &> ;
2017-10-21 19:04:41 +01:00
static_assert ( detail :: is_optional < result >:: value ,
"F must return an optional" );
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), ** this )
: result ( nullopt );
}
2017-10-21 19:41:18 +01:00
/// \group and_then
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
2017-10-21 19:04:41 +01:00
template < class F >
2017-10-24 15:32:22 +01:00
TL_OPTIONAL_11_CONSTEXPR detail :: invoke_result_t < F , T &&> and_then ( F && f ) && {
using result = detail :: invoke_result_t < F , T &&> ;
2017-10-21 19:04:41 +01:00
static_assert ( detail :: is_optional < result >:: value ,
"F must return an optional" );
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), std :: move ( ** this ))
: result ( nullopt );
}
/// \group and_then
2017-10-21 19:41:18 +01:00
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
2017-10-21 19:04:41 +01:00
template < class F >
2017-10-24 15:32:22 +01:00
constexpr detail :: invoke_result_t < F , const T &> and_then ( F && f ) const & {
using result = detail :: invoke_result_t < F , const T &> ;
2017-10-21 19:04:41 +01:00
static_assert ( detail :: is_optional < result >:: value ,
"F must return an optional" );
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), ** this )
: result ( nullopt );
}
2017-10-24 15:07:29 +01:00
#ifndef TL_OPTIONAL_NO_CONSTRR
2017-10-21 19:41:18 +01:00
/// \group and_then
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
2017-10-21 19:04:41 +01:00
template < class F >
2017-10-24 15:32:22 +01:00
constexpr detail :: invoke_result_t < F , const T &&> and_then ( F && f ) const && {
using result = detail :: invoke_result_t < F , const T &&> ;
2017-10-21 19:04:41 +01:00
static_assert ( detail :: is_optional < result >:: value ,
"F must return an optional" );
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), std :: move ( ** this ))
: result ( nullopt );
}
2017-10-24 15:07:29 +01:00
#endif
2017-10-24 15:32:22 +01:00
#endif
2017-10-21 19:04:41 +01:00
2017-10-29 20:07:54 +00:00
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && !defined(TL_EXPECTED_GCC54)
2017-10-21 19:04:41 +01:00
/// \brief Carries out some operation on the stored object if there is one.
2017-10-24 15:07:29 +01:00
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
/// value())`. Returns a `std::optional<U>`. The return value is empty if
/// `*this` is empty, otherwise an `optional<U>` is constructed from the
/// return value of `std::invoke(std::forward<F>(f), value())` and is
2017-11-01 20:24:11 +00:00
/// returned.
///
/// \group map
/// \synopsis template <class F> constexpr auto map(F &&f) &;
2017-10-24 15:55:40 +01:00
template < class F > TL_OPTIONAL_11_CONSTEXPR auto map ( F && f ) & {
2017-10-24 15:07:29 +01:00
return map_impl ( * this , std :: forward < F > ( f ));
2017-10-21 19:04:41 +01:00
}
2017-11-01 20:24:11 +00:00
/// \group map
/// \synopsis template <class F> constexpr auto map(F &&f) &&;
2017-10-24 15:55:40 +01:00
template < class F > TL_OPTIONAL_11_CONSTEXPR auto map ( F && f ) && {
2017-10-24 15:07:29 +01:00
return map_impl ( std :: move ( * this ), std :: forward < F > ( f ));
2017-10-21 19:04:41 +01:00
}
2017-11-01 20:24:11 +00:00
/// \group map
/// \synopsis template <class F> constexpr auto map(F &&f) const&;
2017-10-24 15:46:07 +01:00
template < class F > constexpr auto map ( F && f ) const & {
2017-10-24 15:07:29 +01:00
return map_impl ( * this , std :: forward < F > ( f ));
2017-10-21 19:04:41 +01:00
}
2017-11-01 20:24:11 +00:00
/// \group map
/// \synopsis template <class F> constexpr auto map(F &&f) const&&;
2017-10-24 15:46:07 +01:00
template < class F > constexpr auto map ( F && f ) const && {
2017-10-24 15:07:29 +01:00
return map_impl ( std :: move ( * this ), std :: forward < F > ( f ));
}
#else
/// \brief Carries out some operation on the stored object if there is one.
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
/// value())`. Returns a `std::optional<U>`. The return value is empty if
/// `*this` is empty, otherwise an `optional<U>` is constructed from the
/// return value of `std::invoke(std::forward<F>(f), value())` and is
2017-11-01 20:24:11 +00:00
/// returned.
///
/// \group map
/// \synopsis template <class F> auto map(F &&f) &;
2017-10-24 15:07:29 +01:00
template < class F >
2017-10-24 15:46:07 +01:00
TL_OPTIONAL_11_CONSTEXPR decltype ( map_impl ( std :: declval < optional &> (),
std :: declval < F &&> ()))
2017-10-24 15:07:29 +01:00
map ( F && f ) & {
return map_impl ( * this , std :: forward < F > ( f ));
2017-10-21 19:04:41 +01:00
}
2017-11-01 20:24:11 +00:00
/// \group map
/// \synopsis template <class F> auto map(F &&f) &&;
2017-10-24 15:07:29 +01:00
template < class F >
2017-10-24 15:46:07 +01:00
TL_OPTIONAL_11_CONSTEXPR decltype ( map_impl ( std :: declval < optional &&> (),
std :: declval < F &&> ()))
2017-10-24 15:07:29 +01:00
map ( F && f ) && {
return map_impl ( std :: move ( * this ), std :: forward < F > ( f ));
2017-10-21 19:04:41 +01:00
}
2017-11-01 20:24:11 +00:00
/// \group map
/// \synopsis template <class F> auto map(F &&f) const&;
2017-10-24 15:07:29 +01:00
template < class F >
2017-10-24 15:46:07 +01:00
constexpr decltype ( map_impl ( std :: declval < const optional &> (),
std :: declval < F &&> ()))
2017-10-24 15:07:29 +01:00
map ( F && f ) const & {
return map_impl ( * this , std :: forward < F > ( f ));
2017-10-21 19:04:41 +01:00
}
2017-10-24 15:07:29 +01:00
#ifndef TL_OPTIONAL_NO_CONSTRR
2017-11-01 20:24:11 +00:00
/// \group map
/// \synopsis template <class F> auto map(F &&f) const&&;
2017-10-24 15:07:29 +01:00
template < class F >
2017-10-24 15:46:07 +01:00
constexpr decltype ( map_impl ( std :: declval < const optional &&> (),
std :: declval < F &&> ()))
2017-10-24 15:07:29 +01:00
map ( F && f ) const && {
return map_impl ( std :: move ( * this ), std :: forward < F > ( f ));
2017-10-21 19:04:41 +01:00
}
2017-10-24 15:07:29 +01:00
#endif
#endif
2017-10-21 19:04:41 +01:00
/// \brief Calls `f` if the optional is empty
2017-10-24 15:07:29 +01:00
/// \requires `std::invoke_result_t<F>` must be void or convertible to
/// `optional<T>`. \effects If `*this` has a value, returns `*this`.
/// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns
2017-11-01 20:24:11 +00:00
/// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`.
///
/// \group or_else
2017-10-21 19:41:18 +01:00
/// \synopsis template <class F> optional<T> or_else (F &&f) &;
2017-10-21 19:04:41 +01:00
template < class F , detail :: enable_if_ret_void < F > * = nullptr >
2017-10-21 22:21:49 +01:00
optional < T > TL_OPTIONAL_11_CONSTEXPR or_else ( F && f ) & {
2017-10-21 19:04:41 +01:00
if ( has_value ())
return * this ;
std :: forward < F > ( f )();
return nullopt ;
}
/// \exclude
template < class F , detail :: disable_if_ret_void < F > * = nullptr >
2017-10-21 22:21:49 +01:00
optional < T > TL_OPTIONAL_11_CONSTEXPR or_else ( F && f ) & {
2017-10-21 19:04:41 +01:00
return has_value () ? * this : std :: forward < F > ( f )();
}
2017-10-21 19:41:18 +01:00
/// \group or_else
/// \synopsis template <class F> optional<T> or_else (F &&f) &&;
2017-10-21 19:04:41 +01:00
template < class F , detail :: enable_if_ret_void < F > * = nullptr >
optional < T > or_else ( F && f ) && {
if ( has_value ())
return std :: move ( * this );
std :: forward < F > ( f )();
return nullopt ;
}
/// \exclude
template < class F , detail :: disable_if_ret_void < F > * = nullptr >
2017-10-21 22:21:49 +01:00
optional < T > TL_OPTIONAL_11_CONSTEXPR or_else ( F && f ) && {
2017-10-21 19:04:41 +01:00
return has_value () ? std :: move ( * this ) : std :: forward < F > ( f )();
}
2017-10-21 19:41:18 +01:00
/// \group or_else
/// \synopsis template <class F> optional<T> or_else (F &&f) const &;
2017-10-21 19:04:41 +01:00
template < class F , detail :: enable_if_ret_void < F > * = nullptr >
optional < T > or_else ( F && f ) const & {
if ( has_value ())
return * this ;
std :: forward < F > ( f )();
return nullopt ;
}
2017-10-21 19:41:18 +01:00
/// \exclude
2017-10-21 19:04:41 +01:00
template < class F , detail :: disable_if_ret_void < F > * = nullptr >
2017-10-21 22:21:49 +01:00
optional < T > TL_OPTIONAL_11_CONSTEXPR or_else ( F && f ) const & {
2017-10-21 19:04:41 +01:00
return has_value () ? * this : std :: forward < F > ( f )();
}
2017-10-24 15:07:29 +01:00
#ifndef TL_OPTIONAL_NO_CONSTRR
2017-10-21 19:04:41 +01:00
/// \exclude
template < class F , detail :: enable_if_ret_void < F > * = nullptr >
optional < T > or_else ( F && f ) const && {
if ( has_value ())
return std :: move ( * this );
std :: forward < F > ( f )();
return nullopt ;
}
/// \exclude
template < class F , detail :: disable_if_ret_void < F > * = nullptr >
optional < T > or_else ( F && f ) const && {
return has_value () ? std :: move ( * this ) : std :: forward < F > ( f )();
}
2017-10-24 15:07:29 +01:00
#endif
2017-10-21 19:04:41 +01:00
2017-10-24 15:07:29 +01:00
/// \brief Maps the stored value with `f` if there is one, otherwise returns
2017-11-01 20:24:11 +00:00
/// `u`.
///
/// \details If there is a value stored, then `f` is called with `**this`
/// and the value is returned. Otherwise `u` is returned.
///
/// \group map_or
2017-10-21 19:04:41 +01:00
template < class F , class U > U map_or ( F && f , U && u ) & {
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), ** this )
: std :: forward < U > ( u );
}
2017-10-21 19:41:18 +01:00
/// \group map_or
2017-10-21 19:04:41 +01:00
template < class F , class U > U map_or ( F && f , U && u ) && {
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), std :: move ( ** this ))
: std :: forward < U > ( u );
}
/// \group map_or
template < class F , class U > U map_or ( F && f , U && u ) const & {
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), ** this )
: std :: forward < U > ( u );
}
2017-10-24 15:07:29 +01:00
#ifndef TL_OPTIONAL_NO_CONSTRR
2017-10-21 19:41:18 +01:00
/// \group map_or
2017-10-21 19:04:41 +01:00
template < class F , class U > U map_or ( F && f , U && u ) const && {
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), std :: move ( ** this ))
: std :: forward < U > ( u );
}
2017-10-24 15:07:29 +01:00
#endif
2017-10-21 19:04:41 +01:00
2017-10-24 15:07:29 +01:00
/// \brief Maps the stored value with `f` if there is one, otherwise calls `u`
2017-11-01 20:24:11 +00:00
/// and returns the result.
///
/// \details If there is a value stored, then `f` is
2017-10-24 15:07:29 +01:00
/// called with `**this` and the value is returned. Otherwise
2017-11-01 20:24:11 +00:00
/// `std::forward<U>(u)()` is returned.
///
/// \group map_or_else
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) &;
2017-10-21 20:08:43 +01:00
template < class F , class U >
detail :: invoke_result_t < U > map_or_else ( F && f , U && u ) & {
2017-10-21 19:04:41 +01:00
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), ** this )
: std :: forward < U > ( u )();
}
2017-10-21 19:41:18 +01:00
/// \group map_or_else
2017-10-21 20:08:43 +01:00
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) &&;
template < class F , class U >
detail :: invoke_result_t < U > map_or_else ( F && f , U && u ) && {
2017-10-21 19:04:41 +01:00
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), std :: move ( ** this ))
: std :: forward < U > ( u )();
}
/// \group map_or_else
2017-10-24 15:07:29 +01:00
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u)
/// const &;
2017-10-21 20:08:43 +01:00
template < class F , class U >
detail :: invoke_result_t < U > map_or_else ( F && f , U && u ) const & {
2017-10-21 19:04:41 +01:00
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), ** this )
: std :: forward < U > ( u )();
}
2017-10-24 15:07:29 +01:00
#ifndef TL_OPTIONAL_NO_CONSTRR
2017-10-21 19:41:18 +01:00
/// \group map_or_else
2017-11-01 20:24:11 +00:00
/// \synopsis template <class F, class U>\nauto map_or_else(F &&f, U &&u) const &&;
2017-10-21 20:08:43 +01:00
template < class F , class U >
detail :: invoke_result_t < U > map_or_else ( F && f , U && u ) const && {
2017-10-21 19:04:41 +01:00
return has_value () ? detail :: invoke ( std :: forward < F > ( f ), std :: move ( ** this ))
: std :: forward < U > ( u )();
}
2017-10-24 15:07:29 +01:00
#endif
2017-10-21 19:04:41 +01:00
2017-10-21 19:41:18 +01:00
/// \returns `u` if `*this` has a value, otherwise an empty optional.
2017-10-21 20:08:43 +01:00
template < class U >
2017-10-24 15:07:29 +01:00
constexpr optional < typename std :: decay < U >:: type > conjunction ( U && u ) const {
2017-10-21 20:08:43 +01:00
using result = optional < detail :: decay_t < U >> ;
return has_value () ? result { u } : result { nullopt };
2017-10-21 19:41:18 +01:00
}
/// \returns `rhs` if `*this` is empty, otherwise the current value.
/// \group disjunction
2017-10-24 15:07:29 +01:00
TL_OPTIONAL_11_CONSTEXPR optional disjunction ( const optional & rhs ) & {
2017-10-21 19:41:18 +01:00
return has_value () ? * this : rhs ;
}
/// \group disjunction
2017-10-24 15:07:29 +01:00
constexpr optional disjunction ( const optional & rhs ) const & {
2017-10-21 19:41:18 +01:00
return has_value () ? * this : rhs ;
}
/// \group disjunction
2017-10-24 15:07:29 +01:00
TL_OPTIONAL_11_CONSTEXPR optional disjunction ( const optional & rhs ) && {
2017-10-21 19:41:18 +01:00
return has_value () ? std :: move ( * this ) : rhs ;
}
2017-10-24 15:07:29 +01:00
#ifndef TL_OPTIONAL_NO_CONSTRR
2017-10-21 19:41:18 +01:00
/// \group disjunction
2017-10-24 15:07:29 +01:00
constexpr optional disjunction ( const optional & rhs ) const && {
2017-10-21 19:41:18 +01:00
return has_value () ? std :: move ( * this ) : rhs ;
}
2017-10-24 15:07:29 +01:00
#endif
2017-10-21 19:41:18 +01:00
/// \group disjunction
2017-10-24 15:07:29 +01:00
TL_OPTIONAL_11_CONSTEXPR optional disjunction ( optional && rhs ) & {
2017-10-21 19:41:18 +01:00
return has_value () ? * this : std :: move ( rhs );
}
/// \group disjunction
2017-10-24 15:07:29 +01:00
constexpr optional disjunction ( optional && rhs ) const & {
2017-10-21 19:41:18 +01:00
return has_value () ? * this : std :: move ( rhs );
}
/// \group disjunction
2017-10-24 15:07:29 +01:00
TL_OPTIONAL_11_CONSTEXPR optional disjunction ( optional && rhs ) && {
2017-10-21 19:41:18 +01:00
return has_value () ? std :: move ( * this ) : std :: move ( rhs );
}
2017-10-24 15:07:29 +01:00
#ifndef TL_OPTIONAL_NO_CONSTRR
2017-10-21 19:41:18 +01:00
/// \group disjunction
2017-10-24 15:07:29 +01:00
constexpr optional disjunction ( optional && rhs ) const && {
2017-10-21 19:41:18 +01:00
return has_value () ? std :: move ( * this ) : std :: move ( rhs );
}
2017-10-24 15:07:29 +01:00
#endif
2017-10-21 19:41:18 +01:00
/// Takes the value out of the optional, leaving it empty
/// \group take
optional take () & {
optional ret = * this ;
reset ();
return ret ;
}
/// \group take
optional take () const & {
optional ret = * this ;
reset ();
return ret ;
}
/// \group take
optional take () && {
optional ret = std :: move ( * this );
reset ();
return ret ;
}
2017-10-24 15:07:29 +01:00
#ifndef TL_OPTIONAL_NO_CONSTRR
2017-10-21 19:41:18 +01:00
/// \group take
optional take () const && {
optional ret = std :: move ( * this );
reset ();
return ret ;
}
2017-10-24 15:07:29 +01:00
#endif
2017-10-21 19:41:18 +01:00
2017-10-21 19:04:41 +01:00
using value_type = T ;
/// Constructs an optional that does not contain a value.
/// \group ctor_empty
constexpr optional () noexcept = default ;
/// \group ctor_empty
2017-10-21 21:01:45 +01:00
constexpr optional ( nullopt_t ) noexcept {}
2017-10-21 19:04:41 +01:00
/// Copy constructor
///
/// If `rhs` contains a value, the stored value is direct-initialized with it.
/// Otherwise, the constructed optional is empty.
2017-11-01 15:43:58 +00:00
TL_OPTIONAL_11_CONSTEXPR optional ( const optional & rhs ) = default ;
2017-10-21 19:04:41 +01:00
// TODO conditionally disable
/// Move constructor
///
/// If `rhs` contains a value, the stored value is direct-initialized with it.
/// Otherwise, the constructed optional is empty.
2017-11-01 19:03:45 +00:00
TL_OPTIONAL_11_CONSTEXPR optional ( optional && rhs ) = default ;
2017-10-21 19:04:41 +01:00
/// Constructs the stored value in-place using the given arguments.
/// \group in_place
2017-10-24 15:07:29 +01:00
/// \synopsis template <class... Args> constexpr explicit optional(in_place_t,
/// Args&&... args);
2017-10-21 19:04:41 +01:00
template < class ... Args >
constexpr explicit optional (
detail :: enable_if_t < std :: is_constructible < T , Args ... >:: value , in_place_t > ,
Args && ... args )
: base ( in_place , std :: forward < Args > ( args )...) {}
/// \group in_place
2017-10-24 15:07:29 +01:00
/// \synopsis template <class U, class... Args>\nconstexpr explicit
/// optional(in_place_t, std::initializer_list<U>&, Args&&... args);
2017-10-21 19:04:41 +01:00
template < class U , class ... Args >
TL_OPTIONAL_11_CONSTEXPR explicit optional (
detail :: enable_if_t < std :: is_constructible < T , std :: initializer_list < U > & ,
Args && ... >:: value ,
in_place_t > ,
std :: initializer_list < U > il , Args && ... args ) {
2017-11-01 19:54:18 +00:00
this -> construct ( il , std :: forward < Args > ( args )...);
2017-10-21 19:04:41 +01:00
}
/// Constructs the stored value with `u`.
/// \synopsis template <class U=T> constexpr optional(U &&u);
template <
class U = T ,
detail :: enable_if_t < std :: is_convertible < U && , T >:: value > * = nullptr ,
detail :: enable_forward_value < T , U > * = nullptr >
constexpr optional ( U && u ) : base ( in_place , std :: forward < U > ( u )) {}
/// \exclude
template <
class U = T ,
detail :: enable_if_t <! std :: is_convertible < U && , T >:: value > * = nullptr ,
detail :: enable_forward_value < T , U > * = nullptr >
constexpr explicit optional ( U && u ) : base ( in_place , std :: forward < U > ( u )) {}
/// Converting copy constructor.
/// \synopsis template <class U> optional(const optional<U> &rhs);
template <
class U , detail :: enable_from_other < T , U , const U &> * = nullptr ,
detail :: enable_if_t < std :: is_convertible < const U & , T >:: value > * = nullptr >
optional ( const optional < U > & rhs ) {
2017-11-01 19:54:18 +00:00
this -> construct ( * rhs );
2017-10-21 19:04:41 +01:00
}
/// \exclude
template < class U , detail :: enable_from_other < T , U , const U &> * = nullptr ,
detail :: enable_if_t <! std :: is_convertible < const U & , T >:: value > * =
nullptr >
explicit optional ( const optional < U > & rhs ) {
2017-11-01 19:54:18 +00:00
this -> construct ( * rhs );
2017-10-21 19:04:41 +01:00
}
/// Converting move constructor.
/// \synopsis template <class U> optional(optional<U> &&rhs);
template <
class U , detail :: enable_from_other < T , U , U &&> * = nullptr ,
detail :: enable_if_t < std :: is_convertible < U && , T >:: value > * = nullptr >
optional ( optional < U > && rhs ) {
2017-11-01 19:54:18 +00:00
this -> construct ( std :: move ( * rhs ));
2017-10-21 19:04:41 +01:00
}
/// \exclude
template <
class U , detail :: enable_from_other < T , U , U &&> * = nullptr ,
detail :: enable_if_t <! std :: is_convertible < U && , T >:: value > * = nullptr >
explicit optional ( optional < U > && rhs ) {
2017-11-01 19:54:18 +00:00
this -> construct ( std :: move ( * rhs ));
2017-10-21 19:04:41 +01:00
}
2017-10-21 19:41:18 +01:00
/// Destroys the stored value if there is one.
2017-10-21 19:04:41 +01:00
~ optional () = default ;
/// Assignment to empty.
///
/// Destroys the current value if there is one.
optional & operator = ( nullopt_t ) noexcept {
if ( has_value ()) {
this -> m_value . ~ T ();
this -> m_has_value = false ;
}
2017-10-21 21:38:17 +01:00
return * this ;
2017-10-21 19:04:41 +01:00
}
/// Copy assignment.
///
2017-10-24 15:07:29 +01:00
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
/// value in `*this`.
2017-11-01 15:43:58 +00:00
optional & operator = ( const optional & rhs ) = default ;
2017-10-21 19:04:41 +01:00
/// Move assignment.
///
2017-10-24 15:07:29 +01:00
/// Moves the value from `rhs` if there is one. Otherwise resets the stored
/// value in `*this`.
2017-11-01 19:03:45 +00:00
optional & operator = ( optional && rhs ) = default ;
2017-10-21 19:04:41 +01:00
// TODO conditionally delete, check exception guarantee
2017-10-24 15:07:29 +01:00
/// Assigns the stored value from `u`, destroying the old value if there was
/// one. \synopsis optional &operator=(U &&u);
2017-10-21 19:04:41 +01:00
template < class U = T , detail :: enable_assign_forward < T , U > * = nullptr >
optional & operator = ( U && u ) {
if ( has_value ()) {
this -> m_value = std :: forward < U > ( u );
} else {
2017-11-01 19:54:18 +00:00
this -> construct ( std :: forward < U > ( u ));
2017-10-21 19:04:41 +01:00
}
2017-10-21 21:29:29 +01:00
return * this ;
2017-10-21 19:04:41 +01:00
}
// TODO check exception guarantee
/// Converting copy assignment operator.
///
2017-10-24 15:07:29 +01:00
/// Copies the value from `rhs` if there is one. Otherwise resets the stored
/// value in `*this`. \synopsis optional &operator=(const optional<U> & rhs);
2017-10-21 19:04:41 +01:00
template < class U ,
detail :: enable_assign_from_other < T , U , const U &> * = nullptr >
optional & operator = ( const optional < U > & rhs ) {
if ( has_value ()) {
if ( rhs . has_value ()) {
2017-10-21 21:24:34 +01:00
this -> m_value = * rhs ;
2017-10-21 19:04:41 +01:00
} else {
2017-11-01 19:54:18 +00:00
this -> hard_reset ();
2017-10-21 19:04:41 +01:00
}
}
if ( rhs . has_value ()) {
2017-11-01 19:54:18 +00:00
this -> construct ( * rhs );
2017-10-21 19:04:41 +01:00
}
2017-10-21 21:29:29 +01:00
return * this ;
2017-10-21 19:04:41 +01:00
}
// TODO check exception guarantee
/// Converting move assignment operator.
///
2017-10-24 15:07:29 +01:00
/// Moves the value from `rhs` if there is one. Otherwise resets the stored
/// value in `*this`. \synopsis optional &operator=(optional<U> && rhs);
2017-10-21 19:04:41 +01:00
template < class U , detail :: enable_assign_from_other < T , U , U > * = nullptr >
optional & operator = ( optional < U > && rhs ) {
if ( has_value ()) {
if ( rhs . has_value ()) {
2017-10-21 21:24:34 +01:00
this -> m_value = std :: move ( * rhs );
2017-10-21 19:04:41 +01:00
} else {
2017-11-01 19:54:18 +00:00
this -> hard_reset ();
2017-10-21 19:04:41 +01:00
}
}
if ( rhs . has_value ()) {
2017-11-01 19:54:18 +00:00
this -> construct ( std :: move ( * rhs ));
2017-10-21 19:04:41 +01:00
}
2017-10-21 21:29:29 +01:00
return * this ;
2017-10-21 19:04:41 +01:00
}
/// Constructs the value in-place, destroying the current one if there is one.
/// \group emplace
template < class ... Args > T & emplace ( Args && ... args ) {
static_assert ( std :: is_constructible < T , Args && ... >:: value ,
"T must be constructible with Args" );
* this = nullopt ;
2017-11-01 15:43:58 +00:00
this -> construct ( std :: forward < Args > ( args )...);
2017-10-21 19:04:41 +01:00
}
/// \group emplace
2017-10-24 15:07:29 +01:00
/// \synopsis template <class U, class... Args>\nT&
/// emplace(std::initializer_list<U> il, Args &&... args);
2017-10-21 19:04:41 +01:00
template < class U , class ... Args >
detail :: enable_if_t <
std :: is_constructible < T , std :: initializer_list < U > & , Args && ... >:: value ,
T &>
emplace ( std :: initializer_list < U > il , Args && ... args ) {
* this = nullopt ;
2017-11-01 15:43:58 +00:00
this -> construct ( il , std :: forward < Args > ( args )...);
2017-10-21 19:04:41 +01:00
}
/// Swaps this optional with the other.
///
/// If neither optionals have a value, nothing happens.
/// If both have a value, the values are swapped.
2017-10-24 15:07:29 +01:00
/// If one has a value, it is moved to the other and the movee is left
/// valueless.
2017-10-21 19:04:41 +01:00
void
swap ( optional & rhs ) noexcept ( std :: is_nothrow_move_constructible < T >:: value
&& detail :: is_nothrow_swappable < T >:: value ) {
if ( has_value ()) {
if ( rhs . has_value ()) {
using std :: swap ;
swap ( ** this , * rhs );
} else {
2017-11-01 19:54:18 +00:00
new ( std :: addressof ( rhs . m_value )) T ( std :: move ( this -> m_value ));
2017-10-21 19:04:41 +01:00
this -> m_value . T ::~ T ();
}
} else if ( rhs . has_value ()) {
new ( std :: addressof ( this -> m_value )) T ( std :: move ( rhs . m_value ));
rhs . m_value . T ::~ T ();
}
}
/// \returns a pointer to the stored value
/// \requires a value is stored
/// \group pointer
/// \synopsis constexpr const T *operator->() const;
constexpr const T * operator -> () const {
return std :: addressof ( this -> m_value );
}
/// \group pointer
/// \synopsis constexpr T *operator->();
TL_OPTIONAL_11_CONSTEXPR T * operator -> () {
return std :: addressof ( this -> m_value );
}
/// \returns the stored value
/// \requires a value is stored
/// \group deref
/// \synopsis constexpr T &operator*();
TL_OPTIONAL_11_CONSTEXPR T & operator * () & { return this -> m_value ; }
/// \group deref
/// \synopsis constexpr const T &operator*() const;
constexpr const T & operator * () const & { return this -> m_value ; }
/// \exclude
TL_OPTIONAL_11_CONSTEXPR T && operator * () && {
return std :: move ( this -> m_value );
}
2017-10-24 15:07:29 +01:00
#ifndef TL_OPTIONAL_NO_CONSTRR
2017-10-21 19:04:41 +01:00
/// \exclude
constexpr const T && operator * () const && { return std :: move ( this -> m_value ); }
2017-10-24 15:07:29 +01:00
#endif
2017-10-21 19:04:41 +01:00
/// \returns whether or not the optional has a value
/// \group has_value
constexpr bool has_value () const noexcept { return this -> m_has_value ; }
/// \group has_value
constexpr explicit operator bool () const noexcept {
return this -> m_has_value ;
}
2017-10-24 15:07:29 +01:00
/// \returns the contained value if there is one, otherwise throws
/// [bad_optional_access] \group value \synopsis constexpr T &value();
2017-10-21 19:04:41 +01:00
TL_OPTIONAL_11_CONSTEXPR T & value () & {
if ( has_value ())
return this -> m_value ;
throw bad_optional_access ();
}
/// \group value
/// \synopsis constexpr const T &value() const;
TL_OPTIONAL_11_CONSTEXPR const T & value () const & {
if ( has_value ())
return this -> m_value ;
throw bad_optional_access ();
}
/// \exclude
TL_OPTIONAL_11_CONSTEXPR T && value () && {
if ( has_value ())
return std :: move ( this -> m_value );
throw bad_optional_access ();
}
2017-10-21 22:31:42 +01:00
2017-10-24 15:07:29 +01:00
#ifndef TL_OPTIONAL_NO_CONSTRR
2017-10-21 19:04:41 +01:00
/// \exclude
constexpr const T && value () const && {
if ( has_value ())
return std :: move ( this -> m_value );
throw bad_optional_access ();
}
2017-10-24 15:07:29 +01:00
#endif
2017-10-21 19:04:41 +01:00
/// \returns the stored value if there is one, otherwise returns `u`
/// \group value_or
template < class U > constexpr T value_or ( U && u ) const & {
static_assert ( std :: is_copy_constructible < T >:: value &&
std :: is_convertible < U && , T >:: value ,
"T must be copy constructible and convertible from U" );
return has_value () ? ** this : static_cast < T > ( std :: forward < U > ( u ));
}
/// \group value_or
template < class U > constexpr T value_or ( U && u ) && {
static_assert ( std :: is_move_constructible < T >:: value &&
std :: is_convertible < U && , T >:: value ,
"T must be move constructible and convertible from U" );
return has_value () ? ** this : static_cast < T > ( std :: forward < U > ( u ));
}
/// Destroys the stored value if one exists, making the optional empty
void reset () noexcept {
if ( has_value ()) {
this -> m_value . ~ T ();
this -> m_has_value = false ;
}
}
2017-11-01 15:43:58 +00:00
}; // namespace tl
2017-10-21 19:04:41 +01:00
2017-10-21 09:33:16 +01:00
/// \group relop
/// \brief Compares two optional objects
2017-10-24 15:07:29 +01:00
/// \details If both optionals contain a value, they are compared with `T`s
/// relational operators. Otherwise `lhs` and `rhs` are equal only if they are
/// both empty, and `lhs` is less than `rhs` only if `rhs` is empty and `lhs` is
/// not.
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator == ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return lhs . has_value () == rhs . has_value () &&
( ! lhs . has_value () || * lhs == * rhs );
}
2017-10-21 09:33:16 +01:00
/// \group relop
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator != ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return lhs . has_value () != rhs . has_value () ||
( lhs . has_value () && * lhs != * rhs );
}
2017-10-21 09:33:16 +01:00
/// \group relop
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator < ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return rhs . has_value () && ( ! lhs . has_value () || * lhs < * rhs );
}
2017-10-21 09:33:16 +01:00
/// \group relop
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator > ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return lhs . has_value () && ( ! rhs . has_value () || * lhs > * rhs );
}
2017-10-21 09:33:16 +01:00
/// \group relop
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator <= ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return ! lhs . has_value () || ( rhs . has_value () && * lhs <= * rhs );
}
2017-10-21 09:33:16 +01:00
/// \group relop
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator >= ( const optional < T > & lhs ,
const optional < U > & rhs ) {
return ! rhs . has_value () || ( lhs . has_value () && * lhs >= * rhs );
}
2017-09-29 19:45:17 +01:00
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
/// \brief Compares an optional to a `nullopt`
/// \details Equivalent to comparing the optional to an empty optional
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator == ( const optional < T > & lhs , nullopt_t ) noexcept {
return ! lhs . has_value ();
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator == ( nullopt_t , const optional < T > & rhs ) noexcept {
return ! rhs . has_value ();
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator != ( const optional < T > & lhs , nullopt_t ) noexcept {
return lhs . has_value ();
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator != ( nullopt_t , const optional < T > & rhs ) noexcept {
return rhs . has_value ();
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator < ( const optional < T > & , nullopt_t ) noexcept {
return false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator < ( nullopt_t , const optional < T > & rhs ) noexcept {
return rhs . has_value ();
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator <= ( const optional < T > & lhs , nullopt_t ) noexcept {
return ! lhs . has_value ();
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator <= ( nullopt_t , const optional < T > & ) noexcept {
return true ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator > ( const optional < T > & lhs , nullopt_t ) noexcept {
return lhs . has_value ();
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator > ( nullopt_t , const optional < T > & ) noexcept {
return false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator >= ( const optional < T > & , nullopt_t ) noexcept {
return true ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_nullopt
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr bool operator >= ( nullopt_t , const optional < T > & rhs ) noexcept {
return ! rhs . has_value ();
}
2017-09-29 19:45:17 +01:00
2017-10-21 09:33:16 +01:00
/// \group relop_t
/// \brief Compares the optional with a value.
2017-10-24 15:07:29 +01:00
/// \details If the optional has a value, it is compared with the other value
/// using `T`s relational operators. Otherwise, the optional is considered less
/// than the value.
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator == ( const optional < T > & lhs , const U & rhs ) {
return lhs . has_value () ? * lhs == rhs : false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator == ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value () ? lhs == * rhs : false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator != ( const optional < T > & lhs , const U & rhs ) {
2017-10-02 10:05:36 +01:00
return lhs . has_value () ? * lhs != rhs : true ;
2017-10-02 08:58:09 +01:00
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator != ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value () ? lhs != * rhs : true ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator < ( const optional < T > & lhs , const U & rhs ) {
2017-10-02 10:05:36 +01:00
return lhs . has_value () ? * lhs < rhs : true ;
2017-10-02 08:58:09 +01:00
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator < ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value () ? lhs < * rhs : false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator <= ( const optional < T > & lhs , const U & rhs ) {
2017-10-02 10:05:36 +01:00
return lhs . has_value () ? * lhs <= rhs : true ;
2017-10-02 08:58:09 +01:00
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator <= ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value () ? lhs <= * rhs : false ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator > ( const optional < T > & lhs , const U & rhs ) {
2017-10-02 10:05:36 +01:00
return lhs . has_value () ? * lhs > rhs : false ;
2017-10-02 08:58:09 +01:00
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator > ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value () ? lhs > * rhs : true ;
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator >= ( const optional < T > & lhs , const U & rhs ) {
2017-10-02 10:05:36 +01:00
return lhs . has_value () ? * lhs >= rhs : false ;
2017-10-02 08:58:09 +01:00
}
2017-10-21 09:33:16 +01:00
/// \group relop_t
2017-10-02 08:58:09 +01:00
template < class T , class U >
inline constexpr bool operator >= ( const U & lhs , const optional < T > & rhs ) {
return rhs . has_value () ? lhs >= * rhs : true ;
}
2017-09-29 19:45:17 +01:00
2017-10-21 09:33:16 +01:00
/// \synopsis template <class T>\nvoid swap(optional<T> &lhs, optional<T> &rhs);
2017-10-02 08:58:09 +01:00
template < class T ,
detail :: enable_if_t < std :: is_move_constructible < T >:: value > * = nullptr ,
detail :: enable_if_t < detail :: is_swappable < T >:: value > * = nullptr >
void swap ( optional < T > & lhs ,
optional < T > & rhs ) noexcept ( noexcept ( lhs . swap ( rhs ))) {
return lhs . swap ( rhs );
}
2017-09-29 19:45:17 +01:00
2017-10-02 08:58:09 +01:00
template < class T >
inline constexpr optional < detail :: decay_t < T >> make_optional ( T && v ) {
return optional < detail :: decay_t < T >> ( std :: forward < T > ( v ));
}
template < class T , class ... Args >
inline constexpr optional < T > make_optional ( Args && ... args ) {
return optional < T > ( in_place , std :: forward < Args > ( args )...);
}
template < class T , class U , class ... Args >
inline constexpr optional < T > make_optional ( std :: initializer_list < U > il ,
Args && ... args ) {
return optional < T > ( in_place , il , std :: forward < Args > ( args )...);
}
2017-10-21 19:04:41 +01:00
2017-10-21 20:57:56 +01:00
#if __cplusplus >= 201703L
template < class T > optional ( T ) -> optional < T > ;
#endif
2017-10-24 15:07:29 +01:00
/// \exclude
namespace detail {
#ifdef TL_OPTIONAL_CX14
template < class Opt , class F ,
class Ret = decltype ( detail :: invoke ( std :: declval < F > (),
* std :: declval < Opt > ())),
detail :: enable_if_t <! std :: is_void < Ret >:: value > * = nullptr >
2017-10-24 15:46:07 +01:00
constexpr auto map_impl ( Opt && opt , F && f ) {
2017-10-24 15:07:29 +01:00
return opt . has_value ()
? detail :: invoke ( std :: forward < F > ( f ), * std :: forward < Opt > ( opt ))
: optional < Ret > ( nullopt );
}
template < class Opt , class F ,
class Ret = decltype ( detail :: invoke ( std :: declval < F > (),
* std :: declval < Opt > ())),
detail :: enable_if_t < std :: is_void < Ret >:: value > * = nullptr >
auto map_impl ( Opt && opt , F && f ) {
if ( opt . has_value ()) {
detail :: invoke ( std :: forward < F > ( f ), * std :: forward < Opt > ( opt ));
return monostate {};
}
return optional < Ret > ( nullopt );
}
#else
template < class Opt , class F ,
class Ret = decltype ( detail :: invoke ( std :: declval < F > (),
* std :: declval < Opt > ())),
detail :: enable_if_t <! std :: is_void < Ret >:: value > * = nullptr >
2017-10-24 15:46:07 +01:00
constexpr auto map_impl ( Opt && opt , F && f ) -> optional < Ret > {
2017-10-24 15:07:29 +01:00
return opt . has_value ()
? detail :: invoke ( std :: forward < F > ( f ), * std :: forward < Opt > ( opt ))
: optional < Ret > ( nullopt );
}
template < class Opt , class F ,
class Ret = decltype ( detail :: invoke ( std :: declval < F > (),
* std :: declval < Opt > ())),
detail :: enable_if_t < std :: is_void < Ret >:: value > * = nullptr >
auto map_impl ( Opt && opt , F && f ) -> optional < monostate > {
if ( opt . has_value ()) {
detail :: invoke ( std :: forward < F > ( f ), * std :: forward < Opt > ( opt ));
return monostate {};
}
return nullopt ;
}
#endif
} // namespace detail
2017-10-17 11:54:57 +01:00
} // namespace tl
2017-09-29 19:45:17 +01:00
namespace std {
2017-10-02 08:58:09 +01:00
// TODO SFINAE
template < class T > struct hash < tl :: optional < T >> {
:: std :: size_t operator ()( const tl :: optional < T > & o ) const {
if ( ! o . has_value ())
return 0 ;
2017-09-29 19:45:17 +01:00
2017-10-21 09:33:16 +01:00
return std :: hash < tl :: detail :: remove_const_t < T >> ()( * o );
2017-10-02 08:58:09 +01:00
}
};
2017-10-17 11:54:57 +01:00
} // namespace std
2017-10-24 09:01:24 +01:00
#endif