mirror of
https://github.com/TartanLlama/expected.git
synced 2025-08-03 19:04:29 +02:00
Merge branch 'master' of github.com:TartanLlama/expected
This commit is contained in:
@@ -88,7 +88,7 @@ Requires [Catch](https://github.com/philsquared/Catch) for testing. This is bund
|
|||||||
|
|
||||||
### Acknowledgements
|
### Acknowledgements
|
||||||
|
|
||||||
Thanks to [Kévin Alexandre Boissonneault](https://github.com/KABoissonneault) for various bug fixes.
|
Thanks to [Kévin Alexandre Boissonneault](https://github.com/KABoissonneault) and [Björn Fahller](https://github.com/rollbear) for various bug fixes.
|
||||||
|
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
@@ -368,6 +368,195 @@ TEST_CASE("And then extensions", "[extensions.and_then]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("or_else", "[extensions.or_else]") {
|
||||||
|
using eptr = std::unique_ptr<int>;
|
||||||
|
auto succeed = [](int a) { return tl::expected<int, int>(21 * 2); };
|
||||||
|
auto succeedptr = [](eptr e) { return tl::expected<int,eptr>(21*2);};
|
||||||
|
auto fail = [](int a) { return tl::expected<int,int>(tl::unexpect, 17);};
|
||||||
|
auto efail = [](eptr e) { *e = 17;return tl::expected<int,eptr>(tl::unexpect, std::move(e));};
|
||||||
|
auto failptr = [](eptr e) { return tl::expected<int,eptr>(tl::unexpect, std::move(e));};
|
||||||
|
auto failvoid = [](int) {};
|
||||||
|
auto failvoidptr = [](const eptr&) { /* don't consume */};
|
||||||
|
auto consumeptr = [](eptr) {};
|
||||||
|
auto make_u_int = [](int n) { return std::unique_ptr<int>(new int(n));};
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, int> e = 21;
|
||||||
|
auto ret = e.or_else(succeed);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tl::expected<int, int> e = 21;
|
||||||
|
auto ret = e.or_else(succeed);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, int> e = 21;
|
||||||
|
auto ret = std::move(e).or_else(succeed);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, eptr> e = 21;
|
||||||
|
auto ret = std::move(e).or_else(succeedptr);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tl::expected<int, int> e = 21;
|
||||||
|
auto ret = std::move(e).or_else(succeed);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, int> e = 21;
|
||||||
|
auto ret = e.or_else(fail);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tl::expected<int, int> e = 21;
|
||||||
|
auto ret = e.or_else(fail);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, int> e = 21;
|
||||||
|
auto ret = std::move(e).or_else(fail);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(ret == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, eptr> e = 21;
|
||||||
|
auto ret = std::move(e).or_else(efail);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(ret == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tl::expected<int, int> e = 21;
|
||||||
|
auto ret = std::move(e).or_else(fail);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = e.or_else(succeed);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = e.or_else(succeed);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = std::move(e).or_else(succeed);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, eptr> e(tl::unexpect, make_u_int(21));
|
||||||
|
auto ret = std::move(e).or_else(succeedptr);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = std::move(e).or_else(succeed);
|
||||||
|
REQUIRE(ret);
|
||||||
|
REQUIRE(*ret == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = e.or_else(fail);
|
||||||
|
REQUIRE(!ret);
|
||||||
|
REQUIRE(ret.error() == 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = e.or_else(failvoid);
|
||||||
|
REQUIRE(!ret);
|
||||||
|
REQUIRE(ret.error() == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = e.or_else(fail);
|
||||||
|
REQUIRE(!ret);
|
||||||
|
REQUIRE(ret.error() == 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = e.or_else(failvoid);
|
||||||
|
REQUIRE(!ret);
|
||||||
|
REQUIRE(ret.error() == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = std::move(e).or_else(fail);
|
||||||
|
REQUIRE(!ret);
|
||||||
|
REQUIRE(ret.error() == 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = std::move(e).or_else(failvoid);
|
||||||
|
REQUIRE(!ret);
|
||||||
|
REQUIRE(ret.error() == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, eptr> e(tl::unexpect, make_u_int(21));
|
||||||
|
auto ret = std::move(e).or_else(failvoidptr);
|
||||||
|
REQUIRE(!ret);
|
||||||
|
REQUIRE(*ret.error() == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
tl::expected<int, eptr> e(tl::unexpect, make_u_int(21));
|
||||||
|
auto ret = std::move(e).or_else(consumeptr);
|
||||||
|
REQUIRE(!ret);
|
||||||
|
REQUIRE(ret.error() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = std::move(e).or_else(fail);
|
||||||
|
REQUIRE(!ret);
|
||||||
|
REQUIRE(ret.error() == 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const tl::expected<int, int> e(tl::unexpect, 21);
|
||||||
|
auto ret = std::move(e).or_else(failvoid);
|
||||||
|
REQUIRE(!ret);
|
||||||
|
REQUIRE(ret.error() == 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
struct S {
|
struct S {
|
||||||
int x;
|
int x;
|
||||||
};
|
};
|
||||||
|
@@ -1369,11 +1369,11 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \brief Calls `f` if the expectd is in the unexpected state
|
/// \brief Calls `f` if the expectd is in the unexpected state
|
||||||
/// \requires `std::invoke_result_t<F>` must be void or convertible to
|
/// \requires `F` is invokable with `E`, and `std::invoke_result_t<F>`
|
||||||
/// `expcted<T,E>`.
|
/// must be void or convertible to `expcted<T,E>`.
|
||||||
/// \effects If `*this` has a value, returns `*this`.
|
/// \effects If `*this` has a value, returns `*this`.
|
||||||
/// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)` and returns
|
/// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)(E)` and returns
|
||||||
/// `std::nullopt`. Otherwise, returns `std::forward<F>(f)()`.
|
/// `std::nullopt`. Otherwise, returns `std::forward<F>(f)(E)`.
|
||||||
///
|
///
|
||||||
/// \group or_else
|
/// \group or_else
|
||||||
template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
|
template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & {
|
||||||
@@ -1388,10 +1388,11 @@ public:
|
|||||||
return or_else_impl(*this, std::forward<F>(f));
|
return or_else_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef TL_EXPECTED_NO_CONSTRR
|
||||||
template <class F> expected constexpr or_else(F &&f) const && {
|
template <class F> expected constexpr or_else(F &&f) const && {
|
||||||
return or_else_impl(std::move(*this), std::forward<F>(f));
|
return or_else_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
constexpr expected() = default;
|
constexpr expected() = default;
|
||||||
constexpr expected(const expected &rhs) = default;
|
constexpr expected(const expected &rhs) = default;
|
||||||
constexpr expected(expected &&rhs) = default;
|
constexpr expected(expected &&rhs) = default;
|
||||||
@@ -2009,31 +2010,51 @@ auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TL_EXPECTED_CXX14
|
||||||
template <class Exp, class F,
|
template <class Exp, class F,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
*std::declval<Exp>())),
|
std::declval<Exp>().error())),
|
||||||
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
|
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
|
||||||
constexpr detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
|
constexpr auto or_else_impl(Exp &&exp, F &&f) {
|
||||||
if (exp.has_value()) {
|
static_assert(detail::is_expected<Ret>::value, "F must return an expected");
|
||||||
return std::forward<Exp>(exp);
|
return exp.has_value()
|
||||||
}
|
? std::forward<Exp>(exp)
|
||||||
|
: detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
|
||||||
return detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Exp, class F,
|
template <class Exp, class F,
|
||||||
class Ret = decltype(detail::invoke(std::declval<F>(),
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
*std::declval<Exp>())),
|
std::declval<Exp>().error())),
|
||||||
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
|
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
|
||||||
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
|
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
|
||||||
if (exp.has_value()) {
|
return exp.has_value()
|
||||||
return std::forward<Exp>(exp);
|
? std::forward<Exp>(exp)
|
||||||
}
|
: (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()),
|
||||||
|
std::forward<Exp>(exp));
|
||||||
detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp));
|
}
|
||||||
return std::forward<Exp>(exp);
|
#else
|
||||||
|
template <class Exp, class F,
|
||||||
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
std::declval<Exp>().error())),
|
||||||
|
detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr>
|
||||||
|
auto or_else_impl(Exp &&exp, F &&f) -> Ret {
|
||||||
|
static_assert(detail::is_expected<Ret>::value, "F must return an expected");
|
||||||
|
return exp.has_value()
|
||||||
|
? std::forward<Exp>(exp)
|
||||||
|
: detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Exp, class F,
|
||||||
|
class Ret = decltype(detail::invoke(std::declval<F>(),
|
||||||
|
std::declval<Exp>().error())),
|
||||||
|
detail::enable_if_t<std::is_void<Ret>::value> * = nullptr>
|
||||||
|
detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
|
||||||
|
return exp.has_value()
|
||||||
|
? std::forward<Exp>(exp)
|
||||||
|
: (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()),
|
||||||
|
std::forward<Exp>(exp));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <class T, class E, class U, class F>
|
template <class T, class E, class U, class F>
|
||||||
|
Reference in New Issue
Block a user