///
// 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
// along with this software. If not, see
// .
///
#include
#include
#include
#include
#include
#if __cplusplus == 201103L
#define TL_OPTIONAL_11_CONSTEXPR
#else
#define TL_OPTIONAL_11_CONSTEXPR constexpr
#endif
namespace tl {
template class optional;
class monostate {};
namespace detail {
template using remove_cv_t = typename std::remove_cv::type;
template using remove_const_t = typename std::remove_const::type;
template
using remove_volatile_t = typename std::remove_volatile::type;
template using add_cv_t = typename std::add_cv::type;
template using add_const_t = typename std::add_const::type;
template using add_volatile_t = typename std::add_volatile::type;
template
using remove_reference_t = typename std::remove_reference::type;
template
using add_lvalue_reference_t = typename std::add_lvalue_reference::type;
template
using add_rvalue_reference_t = typename std::add_rvalue_reference::type;
template
using remove_pointer_t = typename std::remove_pointer::type;
template using add_pointer_t = typename std::add_pointer::type;
template using make_signed_t = typename std::make_signed::type;
template using make_unsigned_t = typename std::make_unsigned::type;
template using remove_extent_t = typename std::remove_extent::type;
template
using remove_all_extents_t = typename std::remove_all_extents::type;
template
using aligned_storage_t = typename std::aligned_storage::type;
template
using aligned_union_t = typename std::aligned_union::type;
template using decay_t = typename std::decay::type;
template
using enable_if_t = typename std::enable_if::type;
template
using conditional_t = typename std::conditional::type;
template
using common_type_t = typename std::common_type::type;
template
using underlying_type_t = typename std::underlying_type::type;
template using result_of_t = typename std::result_of::type;
template struct conjunction : std::true_type {};
template struct conjunction : B {};
template
struct conjunction
: std::conditional, B>::type {};
template struct voider { using type = void; };
template using void_t = typename voider::type;
template struct is_optional_impl : std::false_type {};
template struct is_optional_impl> : std::true_type {};
template using is_optional = is_optional_impl>;
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
template >{}, int> = 0>
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
noexcept(std::mem_fn(f)(std::forward(args)...)))
-> decltype(std::mem_fn(f)(std::forward(args)...)) {
return std::mem_fn(f)(std::forward(args)...);
}
template >{}, int> = 0>
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
noexcept(std::forward(f)(std::forward(args)...)))
-> decltype(std::forward(f)(std::forward(args)...)) {
return std::forward(f)(std::forward(args)...);
}
template struct invoke_result_impl;
template
struct invoke_result_impl<
F, decltype(invoke(std::declval(), std::declval()...), void()),
Us...> {
using type = decltype(invoke(std::declval(), std::declval()...));
};
template
using invoke_result = invoke_result_impl;
template
using invoke_result_t = typename invoke_result::type;
template
using fixup_void = conditional_t::value, monostate, U>;
template struct get_invoke_optional_ret {
using type = invoke_result_t<
conditional_t::value,
typename remove_reference_t::value_type &,
typename remove_reference_t::value_type &&>,
U...>;
};
template
using get_invoke_ret = typename conditional_t::value,
get_invoke_optional_ret,
invoke_result>::type;
template
using get_map_return = optional>>;
template
using returns_void = std::is_void>;
template
using disable_if_optional = enable_if_t::value>;
template
using enable_if_optional = enable_if_t::value>;
template
using enable_if_ret_void = enable_if_t::value>;
template
using disable_if_ret_void = enable_if_t::value>;
}
struct in_place_t {
explicit in_place_t() = default;
};
static constexpr in_place_t in_place{};
// [optional.optional], class template optional
template class optional;
namespace detail {
template
using enable_forward_value =
detail::enable_if_t::value &&
!std::is_same, in_place_t>::value &&
!std::is_same, detail::decay_t>::value>;
template
using enable_from_other = detail::enable_if_t<
std::is_constructible::value &&
!std::is_constructible &>::value &&
!std::is_constructible &&>::value &&
!std::is_constructible &>::value &&
!std::is_constructible &&>::value &&
!std::is_convertible &, T>::value &&
!std::is_convertible &&, T>::value &&
!std::is_convertible &, T>::value &&
!std::is_convertible &&, T>::value>;
template
using enable_assign_forward = detail::enable_if_t<
!std::is_same, detail::decay_t>::value &&
!detail::conjunction,
std::is_same>>::value &&
std::is_constructible::value && std::is_assignable::value>;
template
using enable_assign_from_other = detail::enable_if_t<
std::is_constructible::value &&
std::is_assignable::value &&
!std::is_constructible &>::value &&
!std::is_constructible &&>::value &&
!std::is_constructible &>::value &&
!std::is_constructible &&>::value &&
!std::is_convertible &, T>::value &&
!std::is_convertible &&, T>::value &&
!std::is_convertible &, T>::value &&
!std::is_convertible &&, T>::value &&
!std::is_assignable &>::value &&
!std::is_assignable &&>::value &&
!std::is_assignable &>::value &&
!std::is_assignable &&>::value>;
// 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 {};
template tag swap(T &, T &);
template tag swap(T (&a)[N], T (&b)[N]);
// helper functions to test if an unqualified swap is possible, and if it
// becomes std::swap
template std::false_type can_swap(...) noexcept(false);
template (), std::declval()))>
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(),
std::declval())));
template std::false_type uses_std(...);
template
std::is_same(), std::declval())), tag>
uses_std(int);
template
struct is_std_swap_noexcept
: std::integral_constant::value &&
std::is_nothrow_move_assignable::value> {};
template
struct is_std_swap_noexcept : is_std_swap_noexcept {};
template
struct is_adl_swap_noexcept
: std::integral_constant(0))> {};
}
#ifdef _MSC_VER
// TODO make a version which works with MSVC
template
struct is_swappable : std::true_type{};
template
struct is_nothrow_swappable : std::true_type{};
#else
template
struct is_swappable
: std::integral_constant<
bool,
decltype(detail::swap_adl_tests::can_swap(0))::value &&
(!decltype(detail::swap_adl_tests::uses_std(0))::value ||
(std::is_move_assignable::value &&
std::is_move_constructible::value))> {};
template
struct is_swappable
: std::integral_constant<
bool,
decltype(detail::swap_adl_tests::can_swap(0))::value &&
(!decltype(
detail::swap_adl_tests::uses_std(0))::value ||
is_swappable::value)> {};
template
struct is_nothrow_swappable
: std::integral_constant<
bool,
is_swappable::value &&
((decltype(detail::swap_adl_tests::uses_std(0))::value
&&detail::swap_adl_tests::is_std_swap_noexcept::value) ||
(!decltype(detail::swap_adl_tests::uses_std(0))::value &&
detail::swap_adl_tests::is_adl_swap_noexcept::value))> {
};
#endif
}
// [optional.nullopt], no-value state indicator
struct nullopt_t {
struct do_not_use {};
constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {}
};
static constexpr nullopt_t nullopt{nullopt_t::do_not_use{},
nullopt_t::do_not_use{}};
// [optional.bad.access], class bad_optional_access
class bad_optional_access : public std::exception {
public:
bad_optional_access() = default;
const char *what() const noexcept { return "Optional has no value"; }
};
// [optional.relops], relational operators
template
inline constexpr bool operator==(const optional &lhs,
const optional &rhs) {
return lhs.has_value() == rhs.has_value() &&
(!lhs.has_value() || *lhs == *rhs);
}
template
inline constexpr bool operator!=(const optional &lhs,
const optional &rhs) {
return lhs.has_value() != rhs.has_value() ||
(lhs.has_value() && *lhs != *rhs);
}
template
inline constexpr bool operator<(const optional &lhs,
const optional &rhs) {
return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
}
template
inline constexpr bool operator>(const optional &lhs,
const optional &rhs) {
return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
}
template
inline constexpr bool operator<=(const optional &lhs,
const optional &rhs) {
return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
}
template
inline constexpr bool operator>=(const optional &lhs,
const optional &rhs) {
return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
}
// [optional.nullops], comparison with nullopt
template
inline constexpr bool operator==(const optional &lhs, nullopt_t) noexcept {
return !lhs.has_value();
}
template
inline constexpr bool operator==(nullopt_t, const optional &rhs) noexcept {
return !rhs.has_value();
}
template
inline constexpr bool operator!=(const optional &lhs, nullopt_t) noexcept {
return lhs.has_value();
}
template
inline constexpr bool operator!=(nullopt_t, const optional &rhs) noexcept {
return rhs.has_value();
}
template
inline constexpr bool operator<(const optional &, nullopt_t) noexcept {
return false;
}
template
inline constexpr bool operator<(nullopt_t, const optional &rhs) noexcept {
return rhs.has_value();
}
template
inline constexpr bool operator<=(const optional &lhs, nullopt_t) noexcept {
return !lhs.has_value();
}
template
inline constexpr bool operator<=(nullopt_t, const optional &) noexcept {
return true;
}
template
inline constexpr bool operator>(const optional &lhs, nullopt_t) noexcept {
return lhs.has_value();
}
template
inline constexpr bool operator>(nullopt_t, const optional &) noexcept {
return false;
}
template
inline constexpr bool operator>=(const optional &, nullopt_t) noexcept {
return true;
}
template
inline constexpr bool operator>=(nullopt_t, const optional &rhs) noexcept {
return !rhs.has_value();
}
// [optional.comp_with_t], comparison with T
template
inline constexpr bool operator==(const optional &lhs, const U &rhs) {
return lhs.has_value() ? *lhs == rhs : false;
}
template
inline constexpr bool operator==(const U &lhs, const optional &rhs) {
return rhs.has_value() ? lhs == *rhs : false;
}
template
inline constexpr bool operator!=(const optional &lhs, const U &rhs) {
return lhs.has_value() ? *lhs != rhs : true;
}
template
inline constexpr bool operator!=(const U &lhs, const optional &rhs) {
return rhs.has_value() ? lhs != *rhs : true;
}
template
inline constexpr bool operator<(const optional &lhs, const U &rhs) {
return lhs.has_value() ? *lhs < rhs : true;
}
template
inline constexpr bool operator<(const U &lhs, const optional &rhs) {
return rhs.has_value() ? lhs < *rhs : false;
}
template
inline constexpr bool operator<=(const optional &lhs, const U &rhs) {
return lhs.has_value() ? *lhs <= rhs : true;
}
template
inline constexpr bool operator<=(const U &lhs, const optional &rhs) {
return rhs.has_value() ? lhs <= *rhs : false;
}
template
inline constexpr bool operator>(const optional &lhs, const U &rhs) {
return lhs.has_value() ? *lhs > rhs : false;
}
template
inline constexpr bool operator>(const U &lhs, const optional &rhs) {
return rhs.has_value() ? lhs > *rhs : true;
}
template
inline constexpr bool operator>=(const optional &lhs, const U &rhs) {
return lhs.has_value() ? *lhs >= rhs : false;
}
template
inline constexpr bool operator>=(const U &lhs, const optional &rhs) {
return rhs.has_value() ? lhs >= *rhs : true;
}
// [optional.specalg], specialized algorithms
template ::value> * = nullptr,
detail::enable_if_t::value> * = nullptr>
void swap(optional &lhs,
optional &rhs) noexcept(noexcept(lhs.swap(rhs))) {
return lhs.swap(rhs);
}
template
inline constexpr optional> make_optional(T &&v) {
return optional