5#include <initializer_list>
26 using std::runtime_error::runtime_error;
37template <
typename T,
typename tag>
38class value_container {
42 explicit value_container(T value)
noexcept(std::is_nothrow_move_constructible_v<T>)
43 : value_(std::move(value))
46 auto operator=(T value)
noexcept(std::is_nothrow_move_assignable_v<T>) -> value_container&
48 value_ = std::move(value);
52 [[nodiscard]]
constexpr auto get() noexcept -> T& {
return value_; }
53 [[nodiscard]]
constexpr auto get() const noexcept -> const T& {
return value_; }
55 [[nodiscard]]
constexpr auto operator==(
const value_container& other)
const noexcept ->
bool
57 return value_ == other.value_;
59 [[nodiscard]]
constexpr auto operator!=(
const value_container& other)
const noexcept ->
bool
61 return !(*
this == other);
74using ok = detail::value_container<T, detail::ok_tag>;
77using err = detail::value_container<E, detail::err_tag>;
91template <
typename T,
typename E>
93 using variant_t = std::variant<ok<T>,
err<E>>;
103 result(
const result&)
noexcept(std::is_nothrow_copy_constructible_v<variant_t>) =
default;
125 template <typename U, typename std::enable_if_t<
126 std::is_same_v<U,
ok<T>> || std::is_same_v<U,
err<E>>,
bool> = true>
128 constexpr
result(U in) noexcept(std::is_nothrow_move_constructible_v<U>)
129 : value_(std::move(in))
133 template <
typename U = T,
typename std::enable_if_t<!std::is_same_v<U, E>,
bool> = true>
136 : value_(
ok<T>{std::move(in)})
140 template <
typename U = E,
typename std::enable_if_t<!std::is_same_v<T, U>,
bool> = true>
143 : value_(
err<E>{std::move(in)})
161 template <
typename F>
165 static_assert(std::is_invocable_v<F>,
"f must be invocable");
166 static_assert(std::is_constructible_v<T, std::invoke_result_t<F>>,
167 "value_type must be constructible from the result of f");
170 return ok<T>{std::invoke(std::forward<F>(f))};
172 return err<E>{error_value};
189 template <
typename F>
192 std::is_nothrow_constructible_v<error_type>) ->
result
194 static_assert(std::is_default_constructible_v<error_type>,
195 "error_type must be default constructible");
214 template <
typename F,
typename OnError>
216 std::is_nothrow_invocable_v<OnError>&&
217 std::is_nothrow_constructible_v<result<T, E>, std::invoke_result_t<OnError>>) ->
result
219 static_assert(std::is_invocable_v<F>,
"f must be invocable");
220 static_assert(std::is_constructible_v<ok<T>, std::invoke_result_t<F>>,
221 "value_type must be constructible from the result of F");
222 static_assert(std::is_invocable_v<OnError>,
"on_error must be invocable");
225 return ok<T>{std::invoke(std::forward<F>(f))};
227 return {std::invoke(std::forward<OnError>(on_error))};
242 template <
typename U>
245 using param_t = std::decay_t<U>;
246 if constexpr (std::is_same_v<param_t, ok<T>> || std::is_same_v<param_t, err<E>>) {
247 value_ = std::move(in);
248 }
else if constexpr (std::is_same_v<param_t, T> || std::is_convertible_v<param_t, T>) {
249 value_ =
ok<T>{std::move(in)};
250 }
else if constexpr (std::is_same_v<param_t, E> || std::is_convertible_v<param_t, E>) {
251 value_ =
err<E>{std::move(in)};
252 }
else if constexpr (std::is_same_v<T, E>) {
254 "Since the value and error types are the same, use ok<T> or "
255 "err<E> instead of T or E for the assignment.");
271 [[nodiscard]]
constexpr auto is_value() const noexcept ->
bool
273 return std::holds_alternative<ok<T>>(value_);
285 [[nodiscard]]
constexpr auto is_error() const noexcept ->
bool
287 return std::holds_alternative<err<E>>(value_);
306 return std::get<ok<T>>(value_).get();
321 return expect(
"Called `unwrap` on a result that is an error.");
340 return std::get<err<E>>(value_).get();
355 return expect_error(
"Called `unwrap_error` on a result that is a value.");
373 return default_value;
375 return std::get<ok<T>>(value_).get();
391 static_assert(std::is_default_constructible_v<value_type>,
392 "The value type must be default constructible.");
410 template <
typename F>
414 return f(std::get<
err<E>>(value_).get());
416 return std::get<ok<T>>(value_).get();
431 template <
typename F>
432 [[nodiscard]]
constexpr auto map(F&& f)
const
436 return {std::get<err<E>>(value_).get()};
453 template <
typename F>
458 return {std::get<ok<T>>(value_).get()};
473 template <
typename F>
474 [[nodiscard]]
constexpr auto map_or(std::invoke_result_t<F, value_type> default_value,
475 F&& f)
const -> std::invoke_result_t<F, value_type>
478 return default_value;
480 return f(std::get<
ok<T>>(value_).get());
496 template <
typename F,
typename G>
497 [[nodiscard]]
constexpr auto map_or_else(G&& default_f, F&& f)
const
498 -> std::invoke_result_t<F, value_type>
501 return default_f(std::get<
err<E>>(value_).get());
503 return f(std::get<
ok<T>>(value_).get());
517 template <
typename U>
522 return {std::get<err<E>>(value_).get()};
538 template <
typename Op>
539 [[nodiscard]]
constexpr auto and_then(Op&& op)
const
543 return {std::get<err<E>>(value_).get()};
545 return {op(std::get<
ok<T>>(value_).get())};
559 template <
typename F>
564 return {std::get<ok<T>>(value_).get()};
580 template <
typename Op>
581 [[nodiscard]]
constexpr auto or_else(Op&& op)
const
585 return {std::get<ok<T>>(value_).get()};
587 return {op(std::get<
err<E>>(value_).get())};
592 return value_ == other.value_;
596 return !(*
this == other);
599 friend constexpr auto std::hash<result>::operator()(
const result& r)
const noexcept
623template <
typename F,
typename std::enable_if_t<std::is_invocable_v<F>,
bool> = true>
624[[nodiscard]]
static auto result_from_try(F&& f)
noexcept
643template <
typename T,
typename E>
648 return hash<std::variant<bricks::ok<T>,
bricks::err<E>>>{}(r.value_);
656template <
typename T,
typename tag>
657struct std::hash<
bricks::detail::value_container<T, tag>> {
658 [[nodiscard]]
constexpr auto operator()(
659 const bricks::detail::value_container<T, tag>& r)
const noexcept -> std::size_t
661 return hash<T>{}(r.get());
This is the type of the error thrown when accessing a bad result.
Definition result.hpp:24
A class to represent the result of an operation.
Definition result.hpp:92
static auto from_try_or_default(F &&f) noexcept(std::is_nothrow_invocable_v< decltype(result< T, E >::from_try_or< F >)> &&std::is_nothrow_constructible_v< error_type >) -> result
Construct a new result object from an operation that might throw.
Definition result.hpp:190
static auto from_try_or(F &&f, error_type error_value) noexcept(std::is_nothrow_constructible_v< err< E >, error_type >) -> result
Construct a new result object from an operation that might throw.
Definition result.hpp:162
constexpr auto is_value() const noexcept -> bool
Check if the result is a value.
Definition result.hpp:271
T value_type
The value type of the result.
Definition result.hpp:97
constexpr auto or_instead(const result< value_type, F > &res) const -> result< value_type, F >
Returns res if the result is an error, otherwise returns the value.
Definition result.hpp:560
constexpr auto map_or(std::invoke_result_t< F, value_type > default_value, F &&f) const -> std::invoke_result_t< F, value_type >
Returns the provided default (if an error) or applies a function to the contained value.
Definition result.hpp:474
constexpr auto map_error(F &&f) const -> result< value_type, std::invoke_result_t< F, error_type > >
Maps a result<T, E> to result<T, F> by applying a function to a contained error.
Definition result.hpp:454
constexpr auto unwrap() const -> value_type
Returns the value of the result.
Definition result.hpp:319
constexpr auto map(F &&f) const -> result< std::invoke_result_t< F, value_type >, error_type >
Maps a result<T, E> to result<U, E> by applying a function to a contained value.
Definition result.hpp:432
constexpr auto and_then(Op &&op) const -> result< typename std::invoke_result_t< Op, value_type >::value_type, error_type >
Calls op if the result is a value, otherwise returns the error.
Definition result.hpp:539
static auto from_try_or_else(F &&f, OnError &&on_error) noexcept(std::is_nothrow_invocable_v< OnError > &&std::is_nothrow_constructible_v< result< T, E >, std::invoke_result_t< OnError > >) -> result
Construct a new result from an operation that might throw or the result of a function.
Definition result.hpp:215
constexpr auto is_error() const noexcept -> bool
Check if the result is an error.
Definition result.hpp:285
constexpr auto expect_error(const std::string &msg) const -> error_type
Returns the error of the result.
Definition result.hpp:335
constexpr auto expect(const std::string &msg) const -> value_type
Returns the value of the result.
Definition result.hpp:301
constexpr auto or_else(Op &&op) const -> result< value_type, typename std::invoke_result_t< Op, error_type >::error_type >
Calls op if the result is an error, otherwise returns the value.
Definition result.hpp:581
constexpr auto operator==(const result &other) const noexcept -> bool
Definition result.hpp:590
E error_type
The error type of the result.
Definition result.hpp:99
constexpr auto operator!=(const result &other) const noexcept -> bool
Definition result.hpp:594
constexpr auto unwrap_error() const -> error_type
Returns the error of the result.
Definition result.hpp:353
auto operator=(const result &) noexcept(std::is_nothrow_copy_assignable_v< variant_t >) -> result &=default
constexpr auto unwrap_or_else(F &&f) const -> value_type
Returns the value of the result or the result of a function.
Definition result.hpp:411
constexpr auto unwrap_or_default() const noexcept -> value_type
Returns the value of the result or a default constructed value.
Definition result.hpp:389
constexpr result(error_type in) noexcept(std::is_nothrow_move_constructible_v< err< E > >)
Definition result.hpp:142
constexpr auto map_or_else(G &&default_f, F &&f) const -> std::invoke_result_t< F, value_type >
Maps the result<T, E> to U by applying fallback function default_f to a contained error,...
Definition result.hpp:497
constexpr auto unwrap_or(value_type default_value) const noexcept -> value_type
Returns the value of the result.
Definition result.hpp:370
result(result &&) noexcept=default
constexpr auto and_instead(const result< U, error_type > &res) const -> result< U, error_type >
Returns res if the result is a value, otherwise returns the error.
Definition result.hpp:518
constexpr auto operator=(U in) noexcept -> result &
Assign a value to the result.
Definition result.hpp:243
constexpr result(value_type in) noexcept(std::is_nothrow_move_constructible_v< ok< T > >)
Definition result.hpp:135
result(const result &) noexcept(std::is_nothrow_copy_constructible_v< variant_t >)=default
Definition algorithm.hpp:12
detail::value_container< T, detail::ok_tag > ok
Definition result.hpp:74
detail::value_container< E, detail::err_tag > err
Definition result.hpp:77
constexpr bool always_false_v
Helper variable template for static assertions.
Definition type_traits.hpp:34
constexpr auto operator()(const bricks::result< T, E > &r) const noexcept -> std::size_t
Definition result.hpp:645