8#ifndef SEN_CORE_BASE_RESULT_H
9#define SEN_CORE_BASE_RESULT_H
35 explicit Ok(T theVal)
noexcept(std::is_nothrow_move_constructible_v<T>): val(std::move(theVal)) {}
37 ~Ok() noexcept = default;
38 SEN_COPY_CONSTRUCT(Ok) = default;
39 SEN_MOVE_CONSTRUCT(Ok) = default;
40 SEN_COPY_ASSIGN(Ok) = default;
41 SEN_MOVE_ASSIGN(Ok) = default;
58 explicit Err(E theVal)
noexcept(std::is_nothrow_move_constructible_v<E>): val(std::move(theVal)) {}
60 ~Err() noexcept = default;
61 SEN_COPY_CONSTRUCT(Err) = default;
62 SEN_MOVE_CONSTRUCT(Err) = default;
63 SEN_COPY_ASSIGN(Err) = default;
64 SEN_MOVE_ASSIGN(Err) = default;
77using NonVoidT = std::enable_if_t<!std::is_void_v<U>, U>;
80void resultExpect(
bool value, std::string_view errorMsg = {})
noexcept;
133template <
typename T,
typename E>
136 static_assert(!::std::is_void_v<E>,
"void error type is not allowed");
145 Result(impl::Ok<T>&& ok)
noexcept: value_(std::in_place_type<T>, std::move(ok.val)) {}
149 Result(impl::Err<E>&& err)
noexcept: value_(std::in_place_type<E>, std::move(err.val)) {}
152 SEN_MOVE_CONSTRUCT(
Result) =
default;
153 SEN_COPY_CONSTRUCT(
Result) =
default;
154 SEN_MOVE_ASSIGN(
Result) =
default;
155 SEN_COPY_ASSIGN(
Result) =
default;
160 template <
typename U,
162 std::enable_if_t<std::conjunction_v<std::is_constructible<T, const U&>, std::is_constructible<E, const G&>>,
167 [](const
Result<U, G>& other)
171 return decltype(value_)(std::in_place_type<T>, other.getValue());
174 return decltype(value_)(std::in_place_type<E>, other.
getError());
180 template <
typename U,
182 std::enable_if_t<std::conjunction_v<std::is_constructible<T, U>, std::is_constructible<E, G>>,
bool> =
true>
190 return decltype(value_)(std::in_place_type<T>, std::move(other).getValue());
193 return decltype(value_)(std::in_place_type<E>, std::move(other).getError());
207 [[nodiscard]]
bool isOk() const noexcept {
return std::holds_alternative<T>(value_); }
213 [[nodiscard]]
bool isError() const noexcept {
return std::holds_alternative<E>(value_); }
219 explicit operator bool() const noexcept {
return isOk(); }
226 template <
typename U = T>
227 [[nodiscard]]
const impl::NonVoidT<U>&
getValueOr(
const U& defaultVal)
const noexcept;
236 template <
typename U = T>
237 [[nodiscard]]
const impl::NonVoidT<U>&
getValue() const&
239 impl::resultExpect(
isOk());
240 return std::get<T>(value_);
250 template <
typename U = T>
253 impl::resultExpect(
isOk());
254 return std::get<T>(std::move(value_));
267 return std::get<E>(value_);
272 template <
typename U = T>
273 [[nodiscard]]
const impl::NonVoidT<U>&
expect(std::string_view errorMsg = {})
const noexcept
275 std::ignore = errorMsg;
280 std::variant<E, T> value_;
291template <
typename T,
typename CleanT = std::decay_t<T>>
292impl::Ok<CleanT>
Ok(T&& val)
noexcept;
295template <
typename E,
typename CleanE = std::decay_t<E>>
296impl::Err<CleanE>
Err(E&& val)
noexcept;
299impl::Ok<void>
Ok() noexcept;
302impl::
Err<
void>
Err() noexcept;
310template <typename T, typename E>
312inline const impl::NonVoidT<U>&
Result<T, E>::
getValueOr(const U& defaultVal) const noexcept
314 if (
const auto* maybeVal = std::get_if<T>(&value_))
326 static_assert(!::std::is_void_v<E>,
"void error type is not allowed");
333 Result(impl::Ok<void>&& arg)
noexcept: ok_(
true)
338 template <
typename T>
345 : ok_(
false), error_(std::move(err.val))
357 bool operator==(const
Result& other) const noexcept {
return ok_ == other.ok_ && error_ == other.error_; }
362 [[nodiscard]]
bool isOk() const noexcept {
return ok_; }
366 explicit operator bool() const noexcept {
return isOk(); }
389 Result(impl::Ok<void>&& arg)
noexcept: ok_(
true)
394 Result(impl::Err<void>&& arg)
noexcept: ok_(
false)
407 bool operator==(const
Result& other) const noexcept {
return ok_ == other.ok_; }
412 [[nodiscard]]
bool isOk() const noexcept {
return ok_; }
416 explicit operator bool() const noexcept {
return isOk(); }
422template <
typename T,
typename CleanT>
423inline impl::Ok<CleanT>
Ok(T&& val)
noexcept
425 return impl::Ok<CleanT>(std::forward<T>(val));
428template <
typename E,
typename CleanE>
429inline impl::Err<CleanE>
Err(E&& val)
noexcept
431 return impl::Err<CleanE>(std::forward<E>(val));
434[[nodiscard]]
inline impl::Ok<void>
Ok() noexcept
439[[nodiscard]]
inline impl::Err<void>
Err() noexcept
Here we define a set of template meta-programming helpers to let the compiler take some decisions bas...
Result(impl::Ok< void > &&arg) noexcept
Definition result.h:333
Result(Result< T, E > &&other) noexcept
Definition result.h:339
void ValueType
Definition result.h:329
const E & getError() const noexcept
Definition result.h:368
Result(Result &&other) noexcept=default
bool operator!=(const Result &other) const noexcept
Definition result.h:359
Result(const Result &other) noexcept=default
E ErrorType
Definition result.h:330
~Result() noexcept=default
bool isError() const noexcept
Definition result.h:364
Result(impl::Err< E > &&err) noexcept
Definition result.h:344
bool isOk() const noexcept
Definition result.h:362
Result(const Result &other) noexcept=default
bool isError() const noexcept
Definition result.h:414
std::monostate ErrorType
Definition result.h:386
bool isOk() const noexcept
Definition result.h:412
Result(impl::Err< void > &&arg) noexcept
Definition result.h:394
bool operator!=(const Result &other) const noexcept
Definition result.h:409
Result(Result &&other) noexcept=default
void ValueType
Definition result.h:385
~Result() noexcept=default
Result(impl::Ok< void > &&arg) noexcept
Definition result.h:389
Result<T, E> is a template type that can be used to return and propagate errors. The intent is to rep...
Definition result.h:135
bool operator!=(const Result &other) const
Definition result.h:200
const impl::NonVoidT< U > & expect(std::string_view errorMsg={}) const noexcept
Extracts the value of the correct result, or terminates the program with a given error message.
Definition result.h:273
bool operator==(const Result &other) const
Definition result.h:199
bool isOk() const noexcept
Used to determine if the result is not an error.
Definition result.h:207
Result(Result< U, G > &&other)
Do a conversion construction from a compatible Result.
Definition result.h:184
const impl::NonVoidT< U > & getValueOr(const U &defaultVal) const noexcept
Used to determine the return value. If the result indicates an error this method will return defaultV...
Definition result.h:312
impl::NonVoidT< U > && getValue() &&
Used to move out the success value, given that there is no error.
Definition result.h:251
const impl::NonVoidT< U > & getValue() const &
Used to determine the success value, given that there is no error.
Definition result.h:237
T ValueType
Definition result.h:139
Result(impl::Ok< T > &&ok) noexcept
Construct a Result that indicates success and that carries a valid return value.
Definition result.h:145
Result(impl::Err< E > &&err) noexcept
Construct a Result that indicates failure and that carries an error value.
Definition result.h:149
E ErrorType
Definition result.h:140
Result(const Result< U, G > &other)
Do a conversion construction from a compatible Result.
Definition result.h:165
const E & getError() const
Used to determine the error value, given that there is an error.
Definition result.h:264
bool isError() const noexcept
Used to determine if the result is an error.
Definition result.h:213
impl::Err< CleanE > Err(E &&val) noexcept
Helper (syntactic sugar) to create Results that indicate error.
Definition result.h:429
impl::Err< void > Err() noexcept
If E is void, use the void specialization of Err.
Definition result.h:439
impl::Ok< void > Ok() noexcept
If T is void, use the void specialization of Ok.
Definition result.h:434
Result< void, std::monostate > BoolResult
True or false result.
Definition result.h:284