29#include <system_error>
33#if defined(__has_include)
34# if __has_include(<version>)
36# elif __has_include(<experimental/version>)
37# include <experimental/version>
41#if defined(__cpp_lib_expected) && __cpp_lib_expected >= 202202L
43# define THREADSCHEDULE_HAS_STD_EXPECTED 1
44#elif (defined(__cplusplus) && __cplusplus >= 202302L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L)
46# define THREADSCHEDULE_HAS_STD_EXPECTED 1
48# define THREADSCHEDULE_HAS_STD_EXPECTED 0
58#ifdef __cpp_exceptions
59# define THREADSCHEDULE_EXPECTED_THROW(ex) throw ex
61# define THREADSCHEDULE_EXPECTED_THROW(ex) ::std::terminate()
67#if THREADSCHEDULE_HAS_STD_EXPECTED
69using unexpected = std::unexpected<E>;
70using unexpect_t = std::unexpect_t;
71inline constexpr unexpect_t
unexpect{};
73using bad_expected_access = std::bad_expected_access<E>;
74template <
typename T,
typename E = std::error_code>
75using expected = std::expected<T, E>;
110 [[nodiscard]]
auto what() const noexcept ->
char const*
override
112 return "bad expected access";
121class bad_expected_access :
public bad_expected_access<void>
125 explicit bad_expected_access(E e) : error_(std::move(e))
128 [[nodiscard]]
auto error() const& noexcept -> E const&
132 auto error() &
noexcept -> E&
136 [[nodiscard]]
auto error() const&& noexcept -> E const&&
138 return std::move(error_);
140 auto error() &&
noexcept -> E&&
142 return std::move(error_);
170 [[nodiscard]]
constexpr auto error() const& noexcept -> E const&
174 constexpr auto error() &
noexcept -> E&
178 constexpr auto error() &&
noexcept -> E&&
180 return std::move(error_);
213template <
typename T,
typename E = std::error_code>
222 template <
typename U = T,
typename std::enable_if_t<std::is_default_constructible_v<U>,
int> = 0>
225 new (&storage_.value_) T();
228 template <
typename U = T,
typename std::enable_if_t<!std::is_default_constructible_v<U>,
int> = 0>
234 new (&storage_.value_) T(other.storage_.value_);
236 new (&storage_.error_) E(other.storage_.error_);
240 std::is_nothrow_move_constructible_v<E>)
244 new (&storage_.value_) T(std::move(other.storage_.value_));
246 new (&storage_.error_) E(std::move(other.storage_.error_));
249 template <
typename U = T,
250 typename = std::enable_if_t<
251 !std::is_same_v<std::decay_t<U>,
expected> && !std::is_same_v<std::decay_t<U>, std::in_place_t> &&
252 !std::is_same_v<std::decay_t<U>,
unexpected<E>> && std::is_constructible_v<T, U>>>
253# if __cplusplus >= 202002L
254 constexpr explicit(!std::is_convertible_v<U, T>)
expected(U&&
value) : has_(true)
256 constexpr
expected(U&&
value, std::enable_if_t<std::is_convertible_v<U, T>, int> = 0) : has_(true)
258 new (&storage_.value_) T(std::forward<U>(
value));
261 template <
typename U = T,
262 typename = std::enable_if_t<!std::is_same_v<std::decay_t<U>,
expected> &&
263 !std::is_same_v<std::decay_t<U>, std::in_place_t> &&
265 std::is_constructible_v<T, U> && !std::is_convertible_v<U, T>>>
269 new (&storage_.value_) T(std::forward<U>(
value));
272 template <
typename... Args,
typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
273 constexpr explicit expected(std::in_place_t , Args&&... args) : has_(true)
275 new (&storage_.value_) T(std::forward<Args>(args)...);
280 new (&storage_.error_) E(ue.
error());
285 new (&storage_.error_) E(std::move(ue.error()));
288 template <
typename... Args>
291 new (&storage_.error_) E(std::forward<Args>(args)...);
305 std::is_nothrow_move_constructible_v<E>) ->
expected&
310 new (
this)
expected(std::move(other));
314 template <
typename U = T,
315 typename = std::enable_if_t<!std::is_same_v<std::decay_t<U>,
expected> && std::is_constructible_v<T, U>>>
320 storage_.value_.~T();
321 new (&storage_.value_) T(std::forward<U>(
value));
335 storage_.error_ = ue.error();
349 storage_.error_ = std::move(ue.error());
362 storage_.value_.~T();
364 storage_.error_.~E();
370 return &storage_.value_;
375 return &storage_.value_;
380 return storage_.value_;
385 return storage_.value_;
388 constexpr auto operator*() const&& noexcept -> T const&&
390 return std::move(storage_.value_);
395 return std::move(storage_.value_);
398 constexpr explicit operator bool() const noexcept
403 [[nodiscard]]
constexpr auto has_value() const noexcept ->
bool
408 [[nodiscard]]
constexpr auto value() const& -> T const&
412 return storage_.value_;
419 return storage_.value_;
422 [[nodiscard]]
constexpr auto value() const&& -> T const&&
426 return std::move(storage_.value_);
433 return std::move(storage_.value_);
436 [[nodiscard]]
constexpr auto error() const& noexcept -> E const&
438 return storage_.error_;
441 constexpr auto error() &
noexcept -> E&
443 return storage_.error_;
446 [[nodiscard]]
constexpr auto error() const&& noexcept -> E const&&
448 return std::move(storage_.error_);
451 constexpr auto error() &&
noexcept -> E&&
453 return std::move(storage_.error_);
456 template <
typename U>
457 constexpr auto value_or(U&& default_value)
const& -> T
459 return has_ ? storage_.value_ :
static_cast<T
>(std::forward<U>(default_value));
462 template <
typename U>
465 return has_ ? std::move(storage_.value_) :
static_cast<T
>(std::forward<U>(default_value));
469 template <
typename... Args>
473 new (
this)
expected(std::in_place, std::forward<Args>(args)...);
474 return storage_.value_;
478 constexpr void swap(
expected& other)
noexcept(std::is_nothrow_move_constructible_v<T> &&
479 std::is_nothrow_move_constructible_v<E> &&
480 std::is_nothrow_swappable_v<T> && std::is_nothrow_swappable_v<E>)
482 if (has_ && other.has_)
485 swap(storage_.value_, other.storage_.value_);
487 else if (!has_ && !other.has_)
490 swap(storage_.error_, other.storage_.error_);
496 new (&other)
expected(std::move(*
this));
498 new (
this)
expected(std::move(temp));
503 template <
typename F>
506 using U = std::invoke_result_t<F, T&>;
508 return std::invoke(std::forward<F>(f), storage_.value_);
509 return U(
unexpect, storage_.error_);
512 template <
typename F>
515 using U = std::invoke_result_t<F, T const&>;
517 return std::invoke(std::forward<F>(f), storage_.value_);
518 return U(
unexpect, storage_.error_);
521 template <
typename F>
524 using U = std::invoke_result_t<F, T&&>;
526 return std::invoke(std::forward<F>(f), std::move(storage_.value_));
527 return U(
unexpect, std::move(storage_.error_));
530 template <
typename F>
533 using U = std::invoke_result_t<F, T const&&>;
535 return std::invoke(std::forward<F>(f), std::move(storage_.value_));
536 return U(
unexpect, std::move(storage_.error_));
539 template <
typename F>
542 using U = std::invoke_result_t<F, E&>;
544 return U(storage_.value_);
545 return std::invoke(std::forward<F>(f), storage_.error_);
548 template <
typename F>
551 using U = std::invoke_result_t<F, E const&>;
553 return U(storage_.value_);
554 return std::invoke(std::forward<F>(f), storage_.error_);
557 template <
typename F>
560 using U = std::invoke_result_t<F, E&&>;
562 return U(std::move(storage_.value_));
563 return std::invoke(std::forward<F>(f), std::move(storage_.error_));
566 template <
typename F>
569 using U = std::invoke_result_t<F, E const&&>;
571 return U(std::move(storage_.value_));
572 return std::invoke(std::forward<F>(f), std::move(storage_.error_));
575 template <
typename F>
578 using U = std::remove_cv_t<std::invoke_result_t<F, T&>>;
580 return expected<U, E>(std::in_place, std::invoke(std::forward<F>(f), storage_.value_));
584 template <
typename F>
587 using U = std::remove_cv_t<std::invoke_result_t<F, T const&>>;
589 return expected<U, E>(std::in_place, std::invoke(std::forward<F>(f), storage_.value_));
593 template <
typename F>
596 using U = std::remove_cv_t<std::invoke_result_t<F, T&&>>;
598 return expected<U, E>(std::in_place, std::invoke(std::forward<F>(f), std::move(storage_.value_)));
602 template <
typename F>
605 using U = std::remove_cv_t<std::invoke_result_t<F, T const&&>>;
607 return expected<U, E>(std::in_place, std::invoke(std::forward<F>(f), std::move(storage_.value_)));
611 template <
typename F>
614 using G = std::remove_cv_t<std::invoke_result_t<F, E&>>;
620 template <
typename F>
623 using G = std::remove_cv_t<std::invoke_result_t<F, E const&>>;
629 template <
typename F>
632 using G = std::remove_cv_t<std::invoke_result_t<F, E&&>>;
638 template <
typename F>
641 using G = std::remove_cv_t<std::invoke_result_t<F, E const&&>>;
648 template <
typename T2,
typename E2>
651 if (lhs.has_value() != rhs.has_value())
655 return lhs.error() == rhs.error();
658 template <
typename T2,
typename E2>
661 return !(lhs == rhs);
664 template <
typename T2,
typename = std::enable_if_t<!std::is_same_v<expected, std::decay_t<T2>>>>
667 return lhs.has_value() && *lhs == rhs;
670 template <
typename T2,
typename = std::enable_if_t<!std::is_same_v<expected, std::decay_t<T2>>>>
673 return rhs.has_value() && lhs == *rhs;
676 template <
typename T2,
typename = std::enable_if_t<!std::is_same_v<expected, std::decay_t<T2>>>>
679 return !(lhs == rhs);
682 template <
typename T2,
typename = std::enable_if_t<!std::is_same_v<expected, std::decay_t<T2>>>>
685 return !(lhs == rhs);
688 template <
typename E2>
691 return !lhs.has_value() && lhs.error() == rhs.error();
694 template <
typename E2>
697 return !rhs.has_value() && lhs.error() == rhs.error();
700 template <
typename E2>
703 return !(lhs == rhs);
706 template <
typename E2>
709 return !(lhs == rhs);
749 template <
typename... Args>
751 : has_(false), error_(std::forward<Args>(args)...)
776 error_ = std::move(ue.error());
780 constexpr explicit operator bool() const noexcept
785 [[nodiscard]]
constexpr auto has_value() const noexcept ->
bool
796 [[nodiscard]]
constexpr auto error() const& noexcept -> E const&
801 constexpr auto error() &
noexcept -> E&
806 [[nodiscard]]
constexpr auto error() const&& noexcept -> E const&&
808 return std::move(error_);
811 constexpr auto error() &&
noexcept -> E&&
813 return std::move(error_);
821 constexpr void swap(
expected& other)
noexcept(std::is_nothrow_move_constructible_v<E> &&
822 std::is_nothrow_swappable_v<E>)
824 if (has_ && other.has_)
828 else if (!has_ && !other.has_)
831 swap(error_, other.error_);
835 std::swap(has_, other.has_);
836 std::swap(error_, other.error_);
841 template <
typename F>
844 using U = std::invoke_result_t<F>;
846 return std::invoke(std::forward<F>(f));
850 template <
typename F>
853 using U = std::invoke_result_t<F>;
855 return std::invoke(std::forward<F>(f));
859 template <
typename F>
862 using U = std::invoke_result_t<F>;
864 return std::invoke(std::forward<F>(f));
865 return U(
unexpect, std::move(error_));
868 template <
typename F>
871 using U = std::invoke_result_t<F>;
873 return std::invoke(std::forward<F>(f));
874 return U(
unexpect, std::move(error_));
877 template <
typename F>
880 using U = std::invoke_result_t<F, E&>;
883 return std::invoke(std::forward<F>(f), error_);
886 template <
typename F>
889 using U = std::invoke_result_t<F, E const&>;
892 return std::invoke(std::forward<F>(f), error_);
895 template <
typename F>
898 using U = std::invoke_result_t<F, E&&>;
901 return std::invoke(std::forward<F>(f), std::move(error_));
904 template <
typename F>
907 using U = std::invoke_result_t<F, E const&&>;
910 return std::invoke(std::forward<F>(f), std::move(error_));
913 template <
typename F>
916 using U = std::remove_cv_t<std::invoke_result_t<F>>;
918 return expected<U, E>(std::in_place, std::invoke(std::forward<F>(f)));
922 template <
typename F>
925 using U = std::remove_cv_t<std::invoke_result_t<F>>;
927 return expected<U, E>(std::in_place, std::invoke(std::forward<F>(f)));
931 template <
typename F>
934 using U = std::remove_cv_t<std::invoke_result_t<F>>;
936 return expected<U, E>(std::in_place, std::invoke(std::forward<F>(f)));
940 template <
typename F>
943 using U = std::remove_cv_t<std::invoke_result_t<F>>;
945 return expected<U, E>(std::in_place, std::invoke(std::forward<F>(f)));
949 template <
typename F>
952 using G = std::remove_cv_t<std::invoke_result_t<F, E&>>;
958 template <
typename F>
961 using G = std::remove_cv_t<std::invoke_result_t<F, E const&>>;
967 template <
typename F>
970 using G = std::remove_cv_t<std::invoke_result_t<F, E&&>>;
976 template <
typename F>
979 using G = std::remove_cv_t<std::invoke_result_t<F, E const&&>>;
986 template <
typename E2>
989 if (lhs.has_value() != rhs.has_value())
993 return lhs.error() == rhs.error();
996 template <
typename E2>
999 return !(lhs == rhs);
1002 template <
typename E2>
1005 return !lhs.has_value() && lhs.error() == rhs.error();
1008 template <
typename E2>
1011 return !rhs.has_value() && lhs.error() == rhs.error();
1014 template <
typename E2>
1017 return !(lhs == rhs);
1020 template <
typename E2>
1023 return !(lhs == rhs);
1034template <
typename T,
typename E>
constexpr auto or_else(F &&f) &
constexpr auto and_then(F &&f) &&
constexpr expected(unexpected< E > &&ue)
constexpr auto transform(F &&f) const &
constexpr friend auto operator!=(unexpected< E2 > const &lhs, expected const &rhs) -> bool
constexpr auto operator=(unexpected< E > const &ue) -> expected &
constexpr void swap(expected &other) noexcept(std::is_nothrow_move_constructible_v< E > &&std::is_nothrow_swappable_v< E >)
constexpr auto and_then(F &&f) const &
constexpr expected(expected const &other)=default
constexpr expected(unexpected< E > const &ue)
constexpr auto has_value() const noexcept -> bool
constexpr auto operator=(expected &&other) -> expected &=default
constexpr auto or_else(F &&f) &&
constexpr expected(unexpect_t, Args &&... args)
constexpr auto or_else(F &&f) const &&
constexpr auto and_then(F &&f) &
constexpr friend auto operator==(expected const &lhs, expected< void, E2 > const &rhs) -> bool
constexpr auto transform_error(F &&f) const &&
constexpr auto error() &&noexcept -> E &&
constexpr auto transform(F &&f) &&
constexpr auto error() const &&noexcept -> E const &&
constexpr auto error() const &noexcept -> E const &
constexpr auto transform_error(F &&f) &&
constexpr friend auto operator!=(expected const &lhs, expected< void, E2 > const &rhs) -> bool
constexpr auto transform(F &&f) &
constexpr auto transform(F &&f) const &&
constexpr void value() const
constexpr auto transform_error(F &&f) const &
unexpected< E > unexpected_type
constexpr expected(expected &&other)=default
constexpr auto operator=(unexpected< E > &&ue) -> expected &
constexpr auto or_else(F &&f) const &
constexpr auto operator=(expected const &other) -> expected &=default
constexpr friend auto operator==(expected const &lhs, unexpected< E2 > const &rhs) -> bool
constexpr auto and_then(F &&f) const &&
constexpr friend auto operator==(unexpected< E2 > const &lhs, expected const &rhs) -> bool
constexpr auto transform_error(F &&f) &
constexpr auto error() &noexcept -> E &
constexpr friend auto operator!=(expected const &lhs, unexpected< E2 > const &rhs) -> bool
A result type that holds either a value of type T or an error of type E.
constexpr friend auto operator==(expected const &lhs, const T2 &rhs) -> bool
constexpr auto or_else(F &&f) const &&
constexpr auto transform(F &&f) const &&
constexpr expected(expected const &other)
constexpr auto error() const &noexcept -> E const &
constexpr auto operator*() const &&noexcept -> T const &&
constexpr auto operator=(unexpected< E > const &ue) -> expected &
constexpr auto value() const &-> T const &
constexpr auto operator=(U &&value) -> expected &
constexpr expected()=delete
constexpr auto operator=(expected &&other) noexcept(std::is_nothrow_move_constructible_v< T > &&std::is_nothrow_move_constructible_v< E >) -> expected &
constexpr auto transform_error(F &&f) &&
constexpr auto operator*() &noexcept -> T &
constexpr friend auto operator!=(unexpected< E2 > const &lhs, expected const &rhs) -> bool
constexpr expected(expected &&other) noexcept(std::is_nothrow_move_constructible_v< T > &&std::is_nothrow_move_constructible_v< E >)
unexpected< E > unexpected_type
constexpr auto and_then(F &&f) &
constexpr auto or_else(F &&f) const &
constexpr auto value() &&-> T &&
constexpr auto operator->() const noexcept -> T const *
constexpr auto value_or(U &&default_value) const &-> T
constexpr expected(unexpect_t, Args &&... args)
constexpr expected(unexpected< E > const &ue)
constexpr auto or_else(F &&f) &&
constexpr friend auto operator!=(expected const &lhs, const T2 &rhs) -> bool
constexpr auto transform_error(F &&f) const &&
constexpr friend auto operator!=(expected const &lhs, expected< T2, E2 > const &rhs) -> bool
constexpr auto operator=(unexpected< E > &&ue) -> expected &
constexpr auto operator->() noexcept -> T *
constexpr auto and_then(F &&f) const &
constexpr auto transform(F &&f) const &
constexpr auto emplace(Args &&... args) -> T &
constexpr auto transform_error(F &&f) &
constexpr auto transform(F &&f) &
constexpr auto and_then(F &&f) &&
constexpr auto has_value() const noexcept -> bool
constexpr auto transform(F &&f) &&
constexpr auto error() const &&noexcept -> E const &&
constexpr friend auto operator==(const T2 &lhs, expected const &rhs) -> bool
constexpr auto error() &&noexcept -> E &&
constexpr auto value() &-> T &
constexpr friend auto operator!=(const T2 &lhs, expected const &rhs) -> bool
constexpr expected(std::in_place_t, Args &&... args)
constexpr auto value_or(U &&default_value) &&-> T
constexpr auto operator=(expected const &other) -> expected &
constexpr auto transform_error(F &&f) const &
constexpr expected(U &&value)
constexpr auto operator*() &&noexcept -> T &&
constexpr friend auto operator==(expected const &lhs, unexpected< E2 > const &rhs) -> bool
constexpr auto error() &noexcept -> E &
constexpr void swap(expected &other) noexcept(std::is_nothrow_move_constructible_v< T > &&std::is_nothrow_move_constructible_v< E > &&std::is_nothrow_swappable_v< T > &&std::is_nothrow_swappable_v< E >)
constexpr auto and_then(F &&f) const &&
constexpr auto value() const &&-> T const &&
constexpr expected(unexpected< E > &&ue)
constexpr friend auto operator==(unexpected< E2 > const &lhs, expected const &rhs) -> bool
constexpr friend auto operator==(expected const &lhs, expected< T2, E2 > const &rhs) -> bool
constexpr auto or_else(F &&f) &
constexpr friend auto operator!=(expected const &lhs, unexpected< E2 > const &rhs) -> bool
constexpr auto operator*() const &noexcept -> T const &
Exception thrown by expected::value() when the object is in the error state.
constexpr auto error() &&noexcept -> E &&
constexpr unexpected(E const &e)
constexpr unexpected(E &&e)
constexpr auto error() const &noexcept -> E const &
constexpr auto error() &noexcept -> E &
#define THREADSCHEDULE_EXPECTED_THROW(ex)
constexpr unexpect_t unexpect
constexpr void swap(expected< T, E > &lhs, expected< T, E > &rhs) noexcept(noexcept(lhs.swap(rhs)))
Tag type used to construct an expected in the error state.