16 #ifndef SUMTY_OPTION_HPP
17 #define SUMTY_OPTION_HPP
19 #include "sumty/detail/fwd.hpp"
20 #include "sumty/detail/traits.hpp"
21 #include "sumty/detail/utils.hpp"
22 #include "sumty/exceptions.hpp"
23 #include "sumty/result.hpp"
24 #include "sumty/utils.hpp"
25 #include "sumty/variant.hpp"
30 #include <initializer_list>
32 #include <type_traits>
94 class option : variant<
void, T> {
96 [[nodiscard]]
constexpr variant<
void, T>& opt_() &
noexcept {
97 return *
static_cast<variant<
void, T>*>(
this);
100 [[nodiscard]]
constexpr const variant<
void, T>& opt_()
const&
noexcept {
101 return *
static_cast<
const variant<
void, T>*>(
this);
104 [[nodiscard]]
constexpr variant<
void, T>&& opt_() && {
105 return std::move(*
static_cast<variant<
void, T>*>(
this));
108 [[nodiscard]]
constexpr variant<
void, T>&& opt_()
const&& {
109 return std::move(*
static_cast<
const variant<
void, T>*>(
this));
114 using value_type =
typename detail::traits<T>::value_type;
115 using reference =
typename detail::traits<T>::reference;
116 using const_reference =
typename detail::traits<T>::const_reference;
117 using rvalue_reference =
typename detail::traits<T>::rvalue_reference;
118 using const_rvalue_reference =
typename detail::traits<T>::const_rvalue_reference;
119 using pointer =
typename detail::traits<T>::pointer;
120 using const_pointer =
typename detail::traits<T>::const_pointer;
122 using value_type = ...;
123 using reference = ...;
124 using const_reference = ...;
125 using rvalue_reference = ...;
126 using const_rvalue_reference = ...;
128 using const_pointer = ...;
175 CONDITIONALLY_NOEXCEPT;
202 CONDITIONALLY_NOEXCEPT;
295 template <
typename U>
304 if (ptr !=
nullptr) { opt_().
template emplace<1>(*ptr); }
332 template <
typename U>
344 if (other.has_value()) { opt_().
template emplace<1>(*other); }
372 template <
typename U>
384 if (other.has_value()) { opt_().
template emplace<1>(*std::move(other)); }
403 template <
typename... Args>
405 explicit(
sizeof...(
Args) == 0)
411 : variant<
void, T>(std::in_place_index<1>, std::forward<Args>(args)...) {
428 template <
typename U,
typename... Args>
430 std::initializer_list<U> init,
432 : variant<
void, T>(std::in_place_index<1>, init, std::forward<Args>(args)...) {}
460 template <
typename U>
472 : variant<
void, T>(std::in_place_index<1>, std::forward<U>(value)) {
487 CONDITIONALLY_NOEXCEPT;
535 CONDITIONALLY_NOEXCEPT;
587 CONDITIONALLY_NOEXCEPT;
614 opt_().
template emplace<0>();
642 opt_().
template emplace<0>();
668 opt_().
template emplace<0>();
697 template <
typename U>
706 if (opt_().index() == 1) {
707 opt_()[index<1>] = std::forward<U>(value);
709 opt_().
template emplace<1>(std::forward<U>(value));
738 template <
typename U>
744 if (ptr ==
nullptr) {
745 opt_().
template emplace<0>();
747 opt_().
template emplace<1>(*ptr);
776 template <
typename U>
796 constexpr option&
operator=(
const option<U>& value) {
797 if (value.has_value()) {
798 opt_().
template emplace<1>(*value);
800 opt_().
template emplace<0>();
829 template <
typename U>
850 if (value.has_value()) {
851 opt_().
template emplace<1>(*std::move(value));
853 opt_().
template emplace<0>();
882 constexpr operator bool()
const noexcept {
return opt_().index() != 0; }
907 template <
typename U>
918 if (opt_().index() == 0) {
921 return static_cast<U*>(&opt_()[index<1>]);
937 [[nodiscard]]
constexpr bool has_value()
const noexcept {
return opt_().index() != 0; }
951 [[nodiscard]]
constexpr bool is_some()
const noexcept {
return opt_().index() != 0; }
965 [[nodiscard]]
constexpr bool is_none()
const noexcept {
return opt_().index() == 0; }
980 [[nodiscard]]
constexpr reference
operator*() &
noexcept {
return opt_()[index<1>]; }
995 [[nodiscard]]
constexpr const_reference
operator*()
const&
noexcept {
996 return opt_()[index<1>];
1012 [[nodiscard]]
constexpr rvalue_reference
operator*() && {
1013 return std::move(*
this).opt_()[index<1>];
1029 [[nodiscard]]
constexpr const_rvalue_reference
operator*()
const&& {
1030 return std::move(*
this).opt_()[index<1>];
1046 [[nodiscard]]
constexpr pointer
operator->()
noexcept {
1047 return opt_().
template get_if<1>();
1063 [[nodiscard]]
constexpr const_pointer
operator->()
const noexcept {
1064 return opt_().
template get_if<1>();
1082 [[nodiscard]]
constexpr reference
value() & {
1084 return opt_()[index<1>];
1102 [[nodiscard]]
constexpr const_reference
value()
const& {
1104 return opt_()[index<1>];
1122 [[nodiscard]]
constexpr rvalue_reference
value() && {
1124 return std::move(*
this).opt_()[index<1>];
1142 [[nodiscard]]
constexpr rvalue_reference
value()
const&& {
1144 return std::move(*
this).opt_()[index<1>];
1165 template <
typename U>
1166 [[nodiscard]]
constexpr value_type
value_or(U&& default_value)
const& {
1167 if (opt_().index() != 0) {
1168 return opt_()[index<1>];
1170 return static_cast<value_type>(std::forward<U>(default_value));
1192 template <
typename U>
1193 [[nodiscard]]
constexpr value_type
value_or(U&& default_value) && {
1194 if (opt_().index() != 0) {
1195 return std::move(*
this).opt_()[index<1>];
1197 return static_cast<value_type>(std::forward<U>(default_value));
1225 template <
typename F>
1227 if (opt_().index() != 0) {
1228 return opt_()[index<1>];
1230 return static_cast<value_type>(invoke(std::forward<F>(f)));
1258 template <
typename F>
1260 if (opt_().index() != 0) {
1261 return std::move(*
this).opt_()[index<1>];
1263 return static_cast<value_type>(invoke(std::forward<F>(f)));
1282 [[nodiscard]]
constexpr reference
some() & {
return value(); }
1299 [[nodiscard]]
constexpr const_reference
some()
const& {
return value(); }
1316 [[nodiscard]]
constexpr rvalue_reference
some() && {
return std::move(*
this).value(); }
1333 [[nodiscard]]
constexpr rvalue_reference
some()
const&& {
1334 return std::move(*
this).value();
1355 template <
typename U>
1356 [[nodiscard]]
constexpr value_type
some_or(U&& default_value)
const& {
1357 return value_or(std::forward<U>(default_value));
1378 template <
typename U>
1379 [[nodiscard]]
constexpr value_type
some_or(U&& default_value) && {
1380 return std::move(*
this).value_or(std::forward<U>(default_value));
1407 template <
typename F>
1409 return value_or_else(std::forward<F>(f));
1436 template <
typename F>
1438 return std::move(*
this).value_or_else(std::forward<F>(f));
1472 template <
typename E>
1473 [[nodiscard]]
constexpr result<T, std::remove_cvref_t<E>>
ok_or(E&& err)
const& {
1474 if (opt_().index() != 0) {
1475 if constexpr (std::is_void_v<T>) {
1478 return opt_()[index<1>];
1481 return result<T, std::remove_cvref_t<E>>{in_place_error, std::forward<E>(err)};
1516 template <
typename E>
1517 [[nodiscard]]
constexpr result<T, std::remove_cvref_t<E>>
ok_or(E&& err) && {
1518 if (opt_().index() != 0) {
1519 if constexpr (std::is_void_v<T>) {
1522 return std::move(*
this).opt_()[index<1>];
1525 return result<T, std::remove_cvref_t<E>>{in_place_error, std::forward<E>(err)};
1555 template <
typename E>
1556 [[nodiscard]]
constexpr result<T, E>
ok_or(
const result<
never, E>& err)
const& {
1557 if (opt_().index() != 0) {
1558 if constexpr (std::is_void_v<T>) {
1561 return opt_()[index<1>];
1594 template <
typename E>
1595 [[nodiscard]]
constexpr result<T, E>
ok_or(
const result<
never, E>& err) && {
1596 if (opt_().index() != 0) {
1597 if constexpr (std::is_void_v<T>) {
1600 return std::move(*
this).opt_()[index<1>];
1631 template <
typename E>
1632 [[nodiscard]]
constexpr result<T, E>
ok_or(result<
never, E>&& err)
const& {
1633 if (opt_().index() != 0) {
1634 if constexpr (std::is_void_v<T>) {
1637 return opt_()[index<1>];
1640 return std::move(err);
1668 template <
typename E>
1669 [[nodiscard]]
constexpr result<T, E>
ok_or(result<
never, E>&& err) && {
1670 if (opt_().index() != 0) {
1671 if constexpr (std::is_void_v<T>) {
1674 return std::move(*
this).opt_()[index<1>];
1677 return std::move(err);
1710 template <
typename F>
1711 [[nodiscard]]
constexpr result<T, std::invoke_result_t<F>>
ok_or_else(F&& f)
const& {
1712 if (opt_().index() != 0) {
1713 if constexpr (std::is_void_v<T>) {
1716 return opt_()[index<1>];
1719 return result<T, std::invoke_result_t<F>>(in_place_error,
1720 invoke(std::forward<F>(f)));
1753 template <
typename F>
1754 [[nodiscard]]
constexpr result<T, std::invoke_result_t<F>>
ok_or_else(F&& f) && {
1755 if (opt_().index() != 0) {
1756 if constexpr (std::is_void_v<T>) {
1759 return std::move(*
this).opt_()[index<1>];
1762 return result<T, std::invoke_result_t<F>>(in_place_error,
1763 invoke(std::forward<F>(f)));
1798 template <
typename U>
1799 [[nodiscard]]
constexpr result<std::remove_cvref_t<U>, T>
error_or(U&& value)
const& {
1800 if (opt_().index() != 0) {
1801 if constexpr (std::is_void_v<T>) {
1802 return result<std::remove_cvref_t<U>, T>{in_place_error};
1804 return result<std::remove_cvref_t<U>, T>{in_place_error, opt_()[index<1>]};
1807 return result<std::remove_cvref_t<U>, T>{std::in_place, std::forward<U>(value)};
1842 template <
typename U>
1843 [[nodiscard]]
constexpr result<std::remove_cvref_t<U>, T>
error_or(U&& value) && {
1844 if (opt_().index() != 0) {
1845 if constexpr (std::is_void_v<T>) {
1846 return result<std::remove_cvref_t<U>, T>{in_place_error};
1848 return result<std::remove_cvref_t<U>, T>{in_place_error,
1849 std::move(*
this).opt_()[index<1>]};
1852 return result<std::remove_cvref_t<U>, T>{std::in_place, std::forward<U>(value)};
1882 template <
typename U>
1883 [[nodiscard]]
constexpr result<U, T>
error_or(
const result<U,
never>& value)
const& {
1884 if (opt_().index() != 0) {
1885 if constexpr (std::is_void_v<T>) {
1886 return result<U, T>{in_place_error};
1888 return result<U, T>{in_place_error, opt_()[index<1>]};
1921 template <
typename U>
1922 [[nodiscard]]
constexpr result<U, T>
error_or(
const result<U,
never>& value) && {
1923 if (opt_().index() != 0) {
1924 if constexpr (std::is_void_v<T>) {
1925 return result<U, T>{in_place_error};
1927 return result<U, T>{in_place_error, std::move(*
this).opt_()[index<1>]};
1958 template <
typename U>
1959 [[nodiscard]]
constexpr result<U, T>
error_or(result<U,
never>&& value)
const& {
1960 if (opt_().index() != 0) {
1961 if constexpr (std::is_void_v<T>) {
1962 return result<U, T>{in_place_error};
1964 return result<U, T>{in_place_error, opt_()[index<1>]};
1967 return std::move(value);
1995 template <
typename U>
1997 if (opt_().index() != 0) {
1998 if constexpr (std::is_void_v<T>) {
1999 return result<U, T>{in_place_error};
2001 return result<U, T>{in_place_error, std::move(*
this).opt_()[index<1>]};
2004 return std::move(value);
2037 template <
typename F>
2038 [[nodiscard]]
constexpr result<std::invoke_result_t<F>, T>
error_or_else(F&& f)
const& {
2039 if (opt_().index() != 0) {
2040 if constexpr (std::is_void_v<T>) {
2041 return result<std::invoke_result_t<F>, T>{in_place_error};
2043 return result<std::invoke_result_t<F>, T>{in_place_error, opt_()[index<1>]};
2046 return result<std::invoke_result_t<F>, T>{std::in_place,
2047 invoke(std::forward<F>(f))};
2084 template <
typename F>
2085 [[nodiscard]]
constexpr result<std::invoke_result_t<F>, T>
error_or_else(F&& f) && {
2086 if (opt_().index() != 0) {
2087 if constexpr (std::is_void_v<T>) {
2088 return result<std::invoke_result_t<F>, T>{in_place_error};
2090 return result<std::invoke_result_t<F>, T>{
2091 in_place_error, std::move(*
this).opt_()[index<1>]};
2094 return result<std::invoke_result_t<F>, T>{std::in_place,
2095 invoke(std::forward<F>(f))};
2117 [[nodiscard]]
constexpr option<reference>
ref()
noexcept {
2118 if (opt_().index() != 0) {
2119 return option<reference>{std::in_place, opt_()[index<1>]};
2121 return option<reference>{};
2143 [[nodiscard]]
constexpr option<const_reference>
ref()
const noexcept {
2144 if (opt_().index() != 0) {
2145 return option<const_reference>{std::in_place, opt_()[index<1>]};
2147 return option<const_reference>{};
2169 [[nodiscard]]
constexpr option<const_reference>
cref()
const noexcept {
return ref(); }
2209 template <
typename F>
2215 if constexpr (std::is_void_v<reference>) {
2216 if (opt_().index() != 0) {
2217 return std::invoke(std::forward<F>(f), void_v);
2219 return std::remove_cvref_t<std::invoke_result_t<F,
void_t>>{};
2222 if (opt_().index() != 0) {
2223 return std::invoke(std::forward<F>(f), opt_()[index<1>]);
2225 return std::remove_cvref_t<std::invoke_result_t<F, reference>>{};
2268 template <
typename F>
2274 if constexpr (std::is_void_v<const_reference>) {
2275 if (opt_().index() != 0) {
2276 return std::invoke(std::forward<F>(f), void_v);
2278 return std::remove_cvref_t<std::invoke_result_t<F,
void_t>>{};
2281 if (opt_().index() != 0) {
2282 return std::invoke(std::forward<F>(f), opt_()[index<1>]);
2284 return std::remove_cvref_t<std::invoke_result_t<F, const_reference>>{};
2327 template <
typename F>
2333 if constexpr (std::is_void_v<rvalue_reference>) {
2334 if (opt_().index() != 0) {
2335 return std::invoke(std::forward<F>(f), void_v);
2337 return std::remove_cvref_t<std::invoke_result_t<F,
void_t>>{};
2340 if (opt_().index() != 0) {
2341 return std::invoke(std::forward<F>(f), std::move(*
this).opt_()[index<1>]);
2343 return std::remove_cvref_t<std::invoke_result_t<F, rvalue_reference>>{};
2386 template <
typename F>
2392 if constexpr (std::is_void_v<const_rvalue_reference>) {
2393 if (opt_().index() != 0) {
2394 return std::invoke(std::forward<F>(f), void_v);
2396 return std::remove_cvref_t<std::invoke_result_t<F,
void_t>>{};
2399 if (opt_().index() != 0) {
2400 return std::invoke(std::forward<F>(f), std::move(*
this).opt_()[index<1>]);
2402 return std::remove_cvref_t<
2403 std::invoke_result_t<F, const_rvalue_reference>>{};
2442 template <
typename F>
2444 if constexpr (std::is_void_v<reference>) {
2445 using res_t = std::invoke_result_t<F,
void_t>;
2446 if (opt_().index() != 0) {
2447 if constexpr (std::is_void_v<res_t>) {
2448 std::invoke(std::forward<F>(f), void_v);
2449 return option<res_t>{std::in_place};
2451 return option<res_t>{std::in_place,
2452 std::invoke(std::forward<F>(f), void_v)};
2455 return option<res_t>{};
2458 using res_t = std::invoke_result_t<F, reference>;
2459 if (opt_().index() != 0) {
2460 if constexpr (std::is_void_v<res_t>) {
2461 std::invoke(std::forward<F>(f), opt_()[index<1>]);
2462 return option<res_t>{std::in_place};
2464 return option<res_t>{std::in_place,
2465 std::invoke(std::forward<F>(f), opt_()[index<1>])};
2468 return option<res_t>{};
2507 template <
typename F>
2509 if constexpr (std::is_void_v<const_reference>) {
2510 using res_t = std::invoke_result_t<F,
void_t>;
2511 if (opt_().index() != 0) {
2512 if constexpr (std::is_void_v<res_t>) {
2513 std::invoke(std::forward<F>(f), void_v);
2514 return option<res_t>{std::in_place};
2516 return option<res_t>{std::in_place,
2517 std::invoke(std::forward<F>(f), void_v)};
2520 return option<res_t>{};
2523 using res_t = std::invoke_result_t<F, const_reference>;
2524 if (opt_().index() != 0) {
2525 if constexpr (std::is_void_v<res_t>) {
2526 std::invoke(std::forward<F>(f), opt_()[index<1>]);
2527 return option<res_t>{std::in_place};
2529 return option<res_t>{std::in_place,
2530 std::invoke(std::forward<F>(f), opt_()[index<1>])};
2533 return option<res_t>{};
2572 template <
typename F>
2574 if constexpr (std::is_void_v<rvalue_reference>) {
2575 using res_t = std::invoke_result_t<F,
void_t>;
2576 if (opt_().index() != 0) {
2577 if constexpr (std::is_void_v<res_t>) {
2578 std::invoke(std::forward<F>(f), void_v);
2579 return option<res_t>{std::in_place};
2581 return option<res_t>{std::in_place,
2582 std::invoke(std::forward<F>(f), void_v)};
2585 return option<res_t>{};
2588 using res_t = std::invoke_result_t<F, rvalue_reference>;
2589 if (opt_().index() != 0) {
2590 if constexpr (std::is_void_v<res_t>) {
2591 std::invoke(std::forward<F>(f), std::move(*
this).opt_()[index<1>]);
2592 return option<res_t>{std::in_place};
2594 return option<res_t>{
2596 std::invoke(std::forward<F>(f), std::move(*
this).opt_()[index<1>])};
2599 return option<res_t>{};
2638 template <
typename F>
2640 if constexpr (std::is_void_v<const_rvalue_reference>) {
2641 using res_t = std::invoke_result_t<F,
void_t>;
2642 if (opt_().index() != 0) {
2643 if constexpr (std::is_void_v<res_t>) {
2644 std::invoke(std::forward<F>(f), void_v);
2645 return option<res_t>{std::in_place};
2647 return option<res_t>{std::in_place,
2648 std::invoke(std::forward<F>(f), void_v)};
2651 return option<res_t>{};
2654 using res_t = std::invoke_result_t<F, const_rvalue_reference>;
2655 if (opt_().index() != 0) {
2656 if constexpr (std::is_void_v<res_t>) {
2657 std::invoke(std::forward<F>(f), std::move(*
this).opt_()[index<1>]);
2658 return option<res_t>{std::in_place};
2660 return option<res_t>{
2662 std::invoke(std::forward<F>(f), std::move(*
this).opt_()[index<1>])};
2665 return option<res_t>{};
2703 template <
typename F>
2705 return transform(std::forward<F>(f));
2741 template <
typename F>
2742 constexpr auto map(F&& f)
const& {
2743 return transform(std::forward<F>(f));
2779 template <
typename F>
2780 constexpr auto map(F&& f) && {
2781 return std::move(*
this).transform(std::forward<F>(f));
2817 template <
typename F>
2818 constexpr auto map(F&& f)
const&& {
2819 return std::move(*
this).transform(std::forward<F>(f));
2844 template <
typename F>
2846 if (opt_().index() != 0) {
2849 return std::invoke(std::forward<F>(f));
2875 template <
typename F>
2877 if (opt_().index() != 0) {
2878 return std::move(*
this);
2880 return std::invoke(std::forward<F>(f));
2918 return value_or_else([]() -> T {
return none; });
2955 return std::move(*
this).value_or_else([]() -> T {
return none; });
2989 if constexpr (detail::is_option_v<T>) {
2990 return flatten().flatten_all();
3027 if constexpr (detail::is_option_v<T>) {
3028 return std::move(*
this).flatten().flatten_all();
3030 return std::move(*
this);
3062 template <
typename Pred>
3063 constexpr option
filter(Pred&& pred)
const& {
3064 if constexpr (std::is_void_v<T>) {
3065 if (
is_some() && std::invoke(std::forward<Pred>(pred), void_v)) {
3071 if (
is_some() && std::invoke(std::forward<Pred>(pred), opt_()[index<1>])) {
3113 template <
typename Pred>
3115 if constexpr (std::is_void_v<T>) {
3116 if (
is_some() && std::invoke(std::forward<Pred>(pred), void_v)) {
3117 return std::move(*
this);
3122 if (
is_some() && std::invoke(std::forward<Pred>(pred), opt_()[index<1>])) {
3123 return std::move(*
this);
3167 using ret_t = result<option<
typename T::value_type>,
typename T::error_type>;
3169 if (opt_()[index<1>].is_ok()) {
3170 return ret_t{in_place, *opt_()[index<1>]};
3172 return ret_t{in_place_error, opt_()[index<1>].error()};
3175 return ret_t{in_place, none};
3216 using ret_t = result<option<
typename T::value_type>,
typename T::error_type>;
3218 if (opt_()[index<1>].is_ok()) {
3219 return ret_t{in_place, *std::move(*
this).opt_()[index<1>]};
3221 return ret_t{in_place_error, std::move(*
this).opt_()[index<1>].error()};
3224 return ret_t{in_place, none};
3256 template <
typename V>
3264 return opt_().visit(std::forward<V>(visitor));
3295 template <
typename V>
3303 return opt_().visit(std::forward<V>(visitor));
3334 template <
typename V>
3342 return std::move(*
this).opt_().visit(std::forward<V>(visitor));
3373 template <
typename V>
3381 return std::move(*
this).opt_().visit(std::forward<V>(visitor));
3435 template <
typename V>
3443 return opt_().visit(std::forward<V>(visitor));
3497 template <
typename V>
3505 return opt_().visit(std::forward<V>(visitor));
3559 template <
typename V>
3567 return std::move(*
this).opt_().visit(std::forward<V>(visitor));
3621 template <
typename V>
3629 return std::move(*
this).opt_().visit(std::forward<V>(visitor));
3663 opt_().swap(other.opt_());
3683 constexpr void reset()
noexcept { opt_().
template emplace<0>(); }
3706 template <
typename... Args>
3708 opt_().
template emplace<1>(std::forward<Args>(args)...);
3709 return opt_()[index<1>];
3737 template <size_t IDX,
typename T>
3740 typename detail::traits<detail::select_t<IDX,
void, T>>::
reference
3745 if constexpr (IDX == 0) {
3748 static_assert(IDX == 1,
"Invalid get index for sumty::option");
3777 template <size_t IDX,
typename T>
3780 typename detail::traits<detail::select_t<IDX,
void, T>>::
const_reference
3785 if constexpr (IDX == 0) {
3788 static_assert(IDX == 1,
"Invalid get index for sumty::option");
3817 template <size_t IDX,
typename T>
3825 if constexpr (IDX == 0) {
3828 static_assert(IDX == 1,
"Invalid get index for sumty::option");
3829 return std::move(opt).value();
3857 template <size_t IDX,
typename T>
3865 if constexpr (IDX == 0) {
3868 static_assert(IDX == 1,
"Invalid get index for sumty::option");
3869 return std::move(opt).value();
3900 template <
typename T,
typename U>
3911 if constexpr (std::is_void_v<T>) {
3914 static_assert(std::is_same_v<T, U>,
"Invalid get type for sumty::option");
3946 template <
typename T,
typename U>
3957 if constexpr (std::is_void_v<T>) {
3960 static_assert(std::is_same_v<T, U>,
"Invalid get type for sumty::option");
3992 template <
typename T,
typename U>
4003 if constexpr (std::is_void_v<T>) {
4006 static_assert(std::is_same_v<T, U>,
"Invalid get type for sumty::option");
4007 return std::move(opt).value();
4038 template <
typename T,
typename U>
4049 if constexpr (std::is_void_v<T>) {
4052 static_assert(std::is_same_v<T, U>,
"Invalid get type for sumty::option");
4053 return std::move(opt).value();
4072 template <
typename T,
typename U>
4073 constexpr bool operator==(
const option<T>& lhs,
const option<U>& rhs) {
4074 if (lhs.has_value()) {
4075 return rhs.has_value() && *lhs == *rhs;
4077 return !rhs.has_value();
4096 template <
typename T,
typename U>
4097 constexpr bool operator!=(
const option<T>& lhs,
const option<U>& rhs) {
4098 if (lhs.has_value()) {
4099 return !rhs.has_value() || *lhs != *rhs;
4101 return rhs.has_value();
4121 template <
typename T,
typename U>
4122 constexpr bool operator<(
const option<T>& lhs,
const option<U>& rhs) {
4123 return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
4142 template <
typename T,
typename U>
4143 constexpr bool operator>(
const option<T>& lhs,
const option<U>& rhs) {
4144 return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
4164 template <
typename T,
typename U>
4165 constexpr bool operator<=(
const option<T>& lhs,
const option<U>& rhs) {
4166 return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
4186 template <
typename T,
typename U>
4187 constexpr bool operator>=(
const option<T>& lhs,
const option<U>& rhs) {
4188 return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
4208 template <
typename T,
typename U>
4214 std::compare_three_way_result_t<std::remove_cvref_t<T>, std::remove_cvref_t<U>>
4218 operator<=>(
const option<T>& lhs,
const option<U>& rhs) {
4219 if (lhs.has_value() && rhs.has_value()) {
4220 return *lhs <=> *rhs;
4222 return lhs.has_value() <=> rhs.has_value();
4242 template <
typename T,
typename U>
4243 constexpr bool operator==(
const option<T>& lhs,
const U& rhs) {
4244 return lhs.has_value() && *lhs == rhs;
4263 template <
typename T,
typename U>
4264 constexpr bool operator==(
const U& lhs,
const option<T>& rhs) {
4265 return rhs.has_value() && lhs == *rhs;
4284 template <
typename T,
typename U>
4285 constexpr bool operator!=(
const option<T>& lhs,
const U& rhs) {
4286 return !lhs.has_value() || *lhs != rhs;
4305 template <
typename T,
typename U>
4306 constexpr bool operator!=(
const U& lhs,
const option<T>& rhs) {
4307 return !rhs.has_value() || lhs != *rhs;
4326 template <
typename T,
typename U>
4327 constexpr bool operator<(
const option<T>& lhs,
const U& rhs) {
4328 return !lhs.has_value() || *lhs < rhs;
4347 template <
typename T,
typename U>
4348 constexpr bool operator<(
const U& lhs,
const option<T>& rhs) {
4349 return rhs.has_value() && lhs < *rhs;
4368 template <
typename T,
typename U>
4369 constexpr bool operator>(
const option<T>& lhs,
const U& rhs) {
4370 return !lhs.has_value() && *lhs > rhs;
4389 template <
typename T,
typename U>
4390 constexpr bool operator>(
const U& lhs,
const option<T>& rhs) {
4391 return !rhs.has_value() || lhs > *lhs;
4410 template <
typename T,
typename U>
4411 constexpr bool operator<=(
const option<T>& lhs,
const U& rhs) {
4412 return !lhs.has_value() || *lhs <= rhs;
4431 template <
typename T,
typename U>
4432 constexpr bool operator<=(
const U& lhs,
const option<T>& rhs) {
4433 return rhs.has_value() && lhs <= *rhs;
4452 template <
typename T,
typename U>
4453 constexpr bool operator>=(
const option<T>& lhs,
const U& rhs) {
4454 return lhs.has_value() && *lhs >= rhs;
4473 template <
typename T,
typename U>
4474 constexpr bool operator>=(
const U& lhs,
const option<T>& rhs) {
4475 return !rhs.has_value() || lhs >= *rhs;
4495 template <
typename T,
typename U>
4501 std::compare_three_way_result_t<std::remove_cvref_t<T>, std::remove_cvref_t<U>>
4505 operator<=>(
const option<T>& lhs,
const U& rhs)
4510 if (lhs.has_value()) {
4511 return *lhs <=> rhs;
4513 return std::strong_ordering::less;
4531 template <
typename T>
4533 return !lhs.has_value();
4550 template <
typename T>
4552 return !rhs.has_value();
4569 template <
typename T>
4571 return lhs.has_value();
4588 template <
typename T>
4590 return rhs.has_value();
4607 template <
typename T>
4627 template <
typename T>
4629 return rhs.has_value();
4646 template <
typename T>
4648 return lhs.has_value();
4665 template <
typename T>
4685 template <
typename T>
4687 return !lhs.has_value();
4704 template <
typename T>
4724 template <
typename T>
4744 template <
typename T>
4746 return !rhs.has_value();
4765 template <
typename T>
4766 constexpr std::strong_ordering operator<=>(
const option<T>& lhs,
4767 [[maybe_unused]]
none_t rhs) {
4768 return lhs.has_value() <=>
false;
4785 template <
typename T>
4787 return !lhs.has_value();
4804 template <
typename T>
4806 return !rhs.has_value();
4823 template <
typename T>
4825 return lhs.has_value();
4842 template <
typename T>
4844 return rhs.has_value();
4861 template <
typename T>
4881 template <
typename T>
4883 return rhs.has_value();
4900 template <
typename T>
4902 return lhs.has_value();
4919 template <
typename T>
4939 template <
typename T>
4941 return !lhs.has_value();
4958 template <
typename T>
4978 template <
typename T>
4998 template <
typename T>
5000 return !rhs.has_value();
5019 template <
typename T>
5020 constexpr std::strong_ordering operator<=>(
const option<T>& lhs,
5021 [[maybe_unused]] std::nullopt_t rhs) {
5022 return lhs.has_value() <=>
false;
5043 template <
typename T>
5048 return !lhs.has_value();
5069 template <
typename T>
5074 return !rhs.has_value();
5095 template <
typename T>
5100 return lhs.has_value();
5121 template <
typename T>
5126 return rhs.has_value();
5147 template <
typename T>
5174 template <
typename T>
5179 return rhs.has_value();
5200 template <
typename T>
5205 return lhs.has_value();
5226 template <
typename T>
5253 template <
typename T>
5258 return !lhs.has_value();
5279 template <
typename T>
5306 template <
typename T>
5333 template <
typename T>
5338 return !rhs.has_value();
5361 template <
typename T>
5363 requires(std::is_lvalue_reference_v<
typename option<T>::value_type>)
5365 constexpr std::strong_ordering operator<=>(
const option<T>& lhs,
5366 [[maybe_unused]] std::nullptr_t rhs) {
5367 return lhs.has_value() <=>
false;
5391 template <
typename T,
typename U>
5395 constexpr bool operator==(
const option<T>& lhs,
const U* rhs) {
5396 return &*lhs == rhs;
5420 template <
typename T,
typename U>
5424 constexpr bool operator!=(
const option<T>& lhs,
const U* rhs) {
5425 return &*lhs != rhs;
5450 template <
typename T,
typename U>
5454 constexpr bool operator<(
const option<T>& lhs,
const U* rhs) {
5480 template <
typename T,
typename U>
5484 constexpr bool operator>(
const option<T>& lhs,
const U* rhs) {
5510 template <
typename T,
typename U>
5514 constexpr bool operator<=(
const option<T>& lhs,
const U* rhs) {
5515 return &*lhs <= rhs;
5540 template <
typename T,
typename U>
5544 constexpr bool operator>=(
const option<T>& lhs,
const U* rhs) {
5545 return &*lhs >= rhs;
5569 template <
typename T,
typename U>
5573 constexpr bool operator==(
const U* lhs,
const option<T>& rhs) {
5574 return lhs == &*rhs;
5598 template <
typename T,
typename U>
5602 constexpr bool operator!=(
const U* lhs,
const option<T>& rhs) {
5603 return lhs != &*rhs;
5628 template <
typename T,
typename U>
5632 constexpr bool operator<(
const U* lhs,
const option<T>& rhs) {
5658 template <
typename T,
typename U>
5662 constexpr bool operator>(
const U* lhs,
const option<T>& rhs) {
5688 template <
typename T,
typename U>
5692 constexpr bool operator<=(
const U* lhs,
const option<T>& rhs) {
5693 return lhs <= &*rhs;
5718 template <
typename T,
typename U>
5722 constexpr bool operator>=(
const U* lhs,
const option<T>& rhs) {
5723 return lhs >= &*rhs;
5750 template <
typename T,
typename U>
5754 constexpr auto operator<=>(
const option<T>& lhs,
const U* rhs) {
5755 return &*lhs <=> rhs;
5786 template <
typename T,
typename... Args>
5787 constexpr option<T>
some(Args&&... args) {
5788 return option<T>{std::in_place, std::forward<Args>(args)...};
5810 template <
typename T,
typename U,
typename... Args>
5811 constexpr option<T>
some(std::initializer_list<U> ilist, Args&&... args) {
5812 return option<T>{std::in_place, ilist, std::forward<Args>(args)...};
5840 template <
typename T>
5841 constexpr void swap(option<T>& a, option<T>& b)
5843 noexcept(
noexcept(
a.
swap(
b)))