143#ifndef CPP_RESULT_HAS_STATEMENT_EXPR
144#if defined(__GNUC__) || defined(__clang__)
145#define CPP_RESULT_HAS_STATEMENT_EXPR 1
147#define CPP_RESULT_HAS_STATEMENT_EXPR 0
151#ifndef CPP_RESULT_FEATURE_ALL
152#define CPP_RESULT_FEATURE_ALL 1
154#ifndef CPP_RESULT_FEATURE_UNWRAP
155#define CPP_RESULT_FEATURE_UNWRAP CPP_RESULT_FEATURE_ALL
157#ifndef CPP_RESULT_FEATURE_MAP
158#define CPP_RESULT_FEATURE_MAP CPP_RESULT_FEATURE_ALL
160#ifndef CPP_RESULT_FEATURE_ANDOR
161#define CPP_RESULT_FEATURE_ANDOR CPP_RESULT_FEATURE_ALL
163#ifndef CPP_RESULT_FEATURE_INSPECT
164#define CPP_RESULT_FEATURE_INSPECT CPP_RESULT_FEATURE_ALL
166#ifndef CPP_RESULT_FEATURE_CONTAINS
167#define CPP_RESULT_FEATURE_CONTAINS CPP_RESULT_FEATURE_ALL
169#ifndef CPP_RESULT_FEATURE_FLATTEN
170#define CPP_RESULT_FEATURE_FLATTEN CPP_RESULT_FEATURE_ALL
172#ifndef CPP_RESULT_FEATURE_OPTIONAL
173#define CPP_RESULT_FEATURE_OPTIONAL CPP_RESULT_FEATURE_ALL
197#if CPP_RESULT_HAS_STATEMENT_EXPR
200 auto &&__res = (expr); \
201 using __res_type = std::decay_t<decltype(__res)>; \
202 if (__res.is_err()) \
203 return __res_type::Err(__res.unwrap_err()); \
204 std::move(__res.unwrap()); \
227#define TRY_ASSIGN(name, expr) \
228 auto &&__res_##name = (expr); \
229 using __res_type_##name = std::decay_t<decltype(__res_##name)>; \
230 if (__res_##name.is_err()) \
231 return __res_type_##name::Err(__res_##name.unwrap_err()); \
232 auto &name = __res_##name.unwrap()
236#if CPP_RESULT_FEATURE_OPTIONAL
239#include <type_traits>
242#define EXPECT_OR_ABORT(cond, msg) \
245 std::fputs(msg, stderr); \
246 std::fputc('\n', stderr); \
266template <
typename T,
typename E>
class [[nodiscard]]
Result {
267 static_assert(!std::is_reference_v<T> && !std::is_reference_v<E>,
268 "Result<T,E> does not support reference types");
304 constexpr bool is_ok() const noexcept {
return is_ok_; }
313 constexpr bool is_err() const noexcept {
return !is_ok_; }
315#if CPP_RESULT_FEATURE_UNWRAP
328 inline const T &
unwrap() const noexcept {
359 return is_ok_ ? data_.value : default_value;
370 template <
typename F>
372 return is_ok_ ? data_.value : std::forward<F>(func)();
386 noexcept(std::is_nothrow_default_constructible_v<T>) {
403 const T &
expect(
const char *msg)
const noexcept {
433 template <
typename Pred>
435 noexcept(
noexcept(pred(std::declval<T>()))) {
436 return is_ok_ && pred(data_.value);
448 template <
typename Pred>
450 noexcept(
noexcept(pred(std::declval<E>()))) {
451 return !is_ok_ && pred(data_.error);
455#if CPP_RESULT_FEATURE_MAP
464 template <
typename F,
typename U = std::invoke_result_t<F, T>>
479 template <
typename F,
typename E2 = std::invoke_result_t<F, E>>
481 noexcept(
noexcept(func(std::declval<E>()))) {
494 template <
typename U,
typename F> U
map_or(U default_value, F &&func)
const {
495 return is_ok_ ? func(data_.value) : default_value;
507 template <
typename D,
typename F>
509 return is_ok_ ? func(data_.value) : default_fn();
513#if CPP_RESULT_FEATURE_ANDOR
524 template <
typename F,
typename R =
typename std::invoke_result_t<F, T>>
525 R
and_then(F &&func)
const noexcept(
noexcept(func(std::declval<T>()))) {
527 return func(data_.value);
528 return R::Err(data_.error);
539 template <
typename R2>
auto and_(R2 &&res)
const {
541 return std::forward<R2>(res);
553 template <
typename R2>
auto or_(R2 &&res)
const {
555 return std::forward<R2>(res);
566 template <
typename F>
auto or_else(F &&op)
const {
573#if CPP_RESULT_FEATURE_INSPECT
581 template <
typename F>
583 noexcept(
noexcept(func(std::declval<const T &>()))) {
596 template <
typename F>
598 noexcept(
noexcept(func(std::declval<const E &>()))) {
605#if CPP_RESULT_FEATURE_CONTAINS
613 bool contains(
const T &value)
const {
return is_ok_ && data_.value == value; }
623 return !is_ok_ && data_.error == error;
627#if CPP_RESULT_FEATURE_FLATTEN
637 using Inner =
decltype(data_.value);
640 return Inner::Err(data_.error);
644#if CPP_RESULT_FEATURE_OPTIONAL
653 std::optional<T>
ok()
const {
654 return is_ok_ ? std::optional<T>(data_.value) : std::nullopt;
665 std::optional<E>
err()
const {
666 return !is_ok_ ? std::optional<E>(data_.error) : std::nullopt;
673 Result(
Result &&other)
noexcept(std::is_nothrow_move_constructible_v<T> &&
674 std::is_nothrow_move_constructible_v<E>)
675 : is_ok_(other.is_ok_) {
677 new (&data_.value) T(std::move(other.data_.value));
679 new (&data_.error) E(std::move(other.data_.error));
684 std::is_nothrow_move_assignable_v<E>) {
685 if (
this != &other) {
687 is_ok_ = other.is_ok_;
689 new (&data_.value) T(std::move(other.data_.value));
691 new (&data_.error) E(std::move(other.data_.error));
698 std::is_nothrow_copy_constructible_v<T> &&
699 std::is_nothrow_copy_constructible_v<E>)
700 : is_ok_(other.is_ok_) {
702 new (&data_.value) T(other.data_.value);
704 new (&data_.error) E(other.data_.error);
708 std::is_nothrow_copy_assignable_v<T> &&
709 std::is_nothrow_copy_assignable_v<E>) {
710 if (
this != &other) {
712 is_ok_ = other.is_ok_;
714 new (&data_.value) T(other.data_.value);
716 new (&data_.error) E(other.data_.error);
730 explicit Result(T val) noexcept : is_ok_(
true) {
731 new (&data_.value) T(std::move(val));
734 explicit Result(E err) noexcept : is_ok_(
false) {
735 new (&data_.error) E(std::move(err));
738 void destroy() noexcept { is_ok_ ? data_.value.~T() : data_.error.~E(); }
756template <
typename E>
class [[nodiscard]]
Result<void, E> {
757 static_assert(!std::is_reference_v<E>,
758 "Result<void,E> does not support reference types");
787 inline bool is_ok() const noexcept {
return is_ok_; }
796 inline bool is_err() const noexcept {
return !is_ok_; }
834 template <
typename F,
typename U = std::invoke_result_t<F>>
849 template <
typename F,
typename E2 = std::invoke_result_t<F, E>>
851 noexcept(
noexcept(func(std::declval<E>()))) {
868 template <
typename F,
typename R = std::invoke_result_t<F>>
869 R
and_then(F &&func)
const noexcept(
noexcept(func())) {
872 return R::Err(error_);
908 template <
typename F>
922 template <
typename F>
924 noexcept(
noexcept(func(std::declval<const E &>()))) {
939 template <
typename Pred>
941 noexcept(
noexcept(pred(std::declval<E>()))) {
942 return !is_ok_ && pred(error_);
955 std::optional<E>
err()
const {
970 template <
typename R2>
auto and_(R2 &&res)
const {
972 return std::forward<R2>(res);
985 template <
typename R2>
auto or_(R2 &&res)
const {
987 return std::forward<R2>(res);
999 template <
typename U,
typename F> U
map_or(U default_value, F &&func)
const {
1000 return is_ok_ ? func() : default_value;
1012 template <
typename D,
typename F>
1014 return is_ok_ ? func() : default_fn();
1024 bool contains_err(
const E &error)
const {
return !is_ok_ && error_ == error; }
1028 : is_ok_(other.is_ok_) {
1030 new (&error_) E(std::move(other.error_));
1035 if (
this != &other) {
1036 is_ok_ = other.is_ok_;
1038 new (&error_) E(std::move(other.error_));
1044 Result(
const Result &other)
noexcept(std::is_nothrow_copy_constructible_v<E>)
1045 : is_ok_(other.is_ok_) {
1047 new (&error_) E(other.error_);
1051 std::is_nothrow_copy_assignable_v<E>) {
1052 if (
this != &other) {
1053 is_ok_ = other.is_ok_;
1055 new (&error_) E(other.error_);
1064 Result() noexcept : is_ok_(true) {}
1065 explicit Result(E err) noexcept : is_ok_(
false) {
1066 new (&error_) E(std::move(err));
Result(const Result &other) noexcept(std::is_nothrow_copy_constructible_v< E >)
Definition result.hpp:1044
bool contains_err(const E &error) const
Returns true if the result is Err and contains the given error.
Definition result.hpp:1024
bool is_err() const noexcept
Returns true if the result is Err.
Definition result.hpp:796
const E & unwrap_err() const noexcept
Definition result.hpp:821
Result & operator=(Result &&other) noexcept(std::is_nothrow_move_assignable_v< E >)
Definition result.hpp:1034
Result< U, E > map(F &&func) const noexcept(noexcept(func()))
Returns unit type if Ok, else returns error.
Definition result.hpp:835
bool is_err_and(Pred &&pred) const noexcept(noexcept(pred(std::declval< E >())))
Returns true if the result is Err and the predicate returns true for the error.
Definition result.hpp:940
bool is_ok() const noexcept
Returns true if the result is Ok.
Definition result.hpp:787
auto and_(R2 &&res) const
Returns res if the result is Ok, otherwise returns self.
Definition result.hpp:970
E & expect_err(const char msg[]) noexcept
Unwraps the error or aborts with a custom message if Ok.
Definition result.hpp:891
Result(Result &&other) noexcept(std::is_nothrow_move_constructible_v< E >)
Definition result.hpp:1027
const E & expect_err(const char msg[]) const noexcept
Definition result.hpp:896
const Result & inspect_err(F &&func) const noexcept(noexcept(func(std::declval< const E & >())))
Calls func(error) if Err, returns self.
Definition result.hpp:923
R and_then(F &&func) const noexcept(noexcept(func()))
Chains another result-producing function if Ok, else propagates Err.
Definition result.hpp:869
U map_or(U default_value, F &&func) const
Applies a function if Ok, else returns default_value.
Definition result.hpp:999
std::optional< E > err() const
Converts the Result into a std::optional<E> (Err value or std::nullopt).
Definition result.hpp:955
auto or_(R2 &&res) const
Returns res if the result is Err, otherwise returns self.
Definition result.hpp:985
const Result & inspect(F &&func) const noexcept(noexcept(func()))
Calls func() if Ok, returns self.
Definition result.hpp:909
static Result Ok() noexcept
Construct an Ok result.
Definition result.hpp:768
void unwrap() noexcept
Unwraps the value. Aborts if Err.
Definition result.hpp:805
auto map_or_else(D &&default_fn, F &&func) const
Applies a function if Ok, else computes a default with another function.
Definition result.hpp:1013
Result & operator=(const Result &other) noexcept(std::is_nothrow_copy_assignable_v< E >)
Definition result.hpp:1050
E & unwrap_err() noexcept
Unwraps the error. Aborts if Ok.
Definition result.hpp:817
Result< void, E2 > map_err(F &&func) const noexcept(noexcept(func(std::declval< E >())))
Maps the error if Err, else propagates Ok.
Definition result.hpp:850
void expect(const char msg[]) const noexcept
Unwraps the value or aborts with a custom message if Err.
Definition result.hpp:882
static Result Err(E err) noexcept
Construct an Err result.
Definition result.hpp:778
Result<T, E> - Holds either a value (Ok) or an error (Err).
Definition result.hpp:266
Result< T, E2 > map_err(F &&func) const noexcept(noexcept(func(std::declval< E >())))
Maps the error if Err, else propagates Ok.
Definition result.hpp:480
const E & expect_err(const char *msg) const noexcept
Definition result.hpp:419
T unwrap_or_default() const noexcept(std::is_nothrow_default_constructible_v< T >)
Returns the value if Ok, else returns a default-constructed value. Requires T to be default-construct...
Definition result.hpp:385
Result(const Result &other) noexcept(std::is_nothrow_copy_constructible_v< T > &&std::is_nothrow_copy_constructible_v< E >)
Definition result.hpp:697
auto map_or_else(D &&default_fn, F &&func) const
Applies a function to the value if Ok, else computes a default with another function.
Definition result.hpp:508
constexpr bool is_ok() const noexcept
Returns true if the result is Ok.
Definition result.hpp:304
T unwrap_or(T default_value) const noexcept
Returns value if Ok, else returns default_value.
Definition result.hpp:358
~Result()
Definition result.hpp:670
Result & operator=(Result &&other) noexcept(std::is_nothrow_move_assignable_v< T > &&std::is_nothrow_move_assignable_v< E >)
Definition result.hpp:683
bool contains(const T &value) const
Returns true if the result is Ok and contains the given value.
Definition result.hpp:613
T & expect(const char *msg) noexcept
Unwraps the value or aborts with a custom message if Err.
Definition result.hpp:399
bool is_err_and(Pred &&pred) const noexcept(noexcept(pred(std::declval< E >())))
Returns true if the result is Err and the predicate returns true for the error.
Definition result.hpp:449
auto and_(R2 &&res) const
Returns res if the result is Ok, otherwise returns self.
Definition result.hpp:539
auto or_else(F &&op) const
Calls op if the result is Err, otherwise returns self.
Definition result.hpp:566
auto flatten() const
Flattens a Result<Result<U, E>, E> into Result<U, E>.
Definition result.hpp:636
const Result & inspect(F &&func) const noexcept(noexcept(func(std::declval< const T & >())))
Calls func(value) if Ok, returns self.
Definition result.hpp:582
Result< U, E > map(F &&func) const noexcept(noexcept(func(std::declval< T >())))
Maps the value if Ok, else propagates Err.
Definition result.hpp:465
U map_or(U default_value, F &&func) const
Applies a function to the value if Ok, else returns default_value.
Definition result.hpp:494
const T & unwrap() const noexcept
Definition result.hpp:328
bool is_ok_and(Pred &&pred) const noexcept(noexcept(pred(std::declval< T >())))
Returns true if the result is Ok and the predicate returns true for the value.
Definition result.hpp:434
const T & expect(const char *msg) const noexcept
Definition result.hpp:403
R and_then(F &&func) const noexcept(noexcept(func(std::declval< T >())))
Chains another result-producing function if Ok, else propagates Err.
Definition result.hpp:525
std::optional< T > ok() const
Returns the value as std::optional if Ok, otherwise std::nullopt.
Definition result.hpp:653
auto or_(R2 &&res) const
Returns res if the result is Err, otherwise returns self.
Definition result.hpp:553
Result & operator=(const Result &other) noexcept(std::is_nothrow_copy_assignable_v< T > &&std::is_nothrow_copy_assignable_v< E >)
Definition result.hpp:707
E & unwrap_err() noexcept
Unwraps the error. Aborts if Ok.
Definition result.hpp:341
T & unwrap() noexcept
Unwraps the value. Aborts if Err.
Definition result.hpp:324
Result(Result &&other) noexcept(std::is_nothrow_move_constructible_v< T > &&std::is_nothrow_move_constructible_v< E >)
Definition result.hpp:673
T unwrap_or_else(F &&func) const noexcept(noexcept(func()))
Returns value if Ok, else calls func().
Definition result.hpp:371
const Result & inspect_err(F &&func) const noexcept(noexcept(func(std::declval< const E & >())))
Calls func(error) if Err, returns self.
Definition result.hpp:597
static Result Err(E err) noexcept
Construct an Err result.
Definition result.hpp:295
const E & unwrap_err() const noexcept
Definition result.hpp:345
static Result Ok(T val) noexcept
Construct an Ok result.
Definition result.hpp:282
bool contains_err(const E &error) const
Returns true if the result is Err and contains the given error.
Definition result.hpp:622
constexpr bool is_err() const noexcept
Returns true if the result is Err.
Definition result.hpp:313
E & expect_err(const char *msg) noexcept
Unwraps the error or aborts with a custom message if Ok.
Definition result.hpp:415
std::optional< E > err() const
Returns the error as std::optional if Err, otherwise std::nullopt.
Definition result.hpp:665
Definition result.hpp:251
Result< T, E > Err(E err)
Definition result.hpp:1073
Result< void, E > Ok()
Definition result.hpp:1076
#define EXPECT_OR_ABORT(cond, msg)
Definition result.hpp:242