mirror of
https://github.com/Naios/continuable.git
synced 2025-12-07 01:06:44 +08:00
more
This commit is contained in:
parent
73a8da1b86
commit
dbf73b6ac6
@ -44,6 +44,10 @@
|
|||||||
#include <continuable/detail/types.hpp>
|
#include <continuable/detail/types.hpp>
|
||||||
#include <continuable/detail/util.hpp>
|
#include <continuable/detail/util.hpp>
|
||||||
|
|
||||||
|
#if defined(CONTINUABLE_WITH_EXCEPTIONS)
|
||||||
|
#include <exception>
|
||||||
|
#endif // CONTINUABLE_WITH_EXCEPTIONS
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
namespace awaiting {
|
namespace awaiting {
|
||||||
@ -131,12 +135,18 @@ public:
|
|||||||
.done();
|
.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
void await_resume() {
|
auto await_resume() noexcept(false) {
|
||||||
if (result_) {
|
if (result_) {
|
||||||
return result_.get_value();
|
// When the result was resolved return it
|
||||||
} else {
|
trait_t::unwrap(std::move(result_));
|
||||||
throw result_.get_error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONTINUABLE_WITH_EXCEPTIONS)
|
||||||
|
std::rethrow_exception(result_.get_error());
|
||||||
|
#else // CONTINUABLE_WITH_EXCEPTIONS
|
||||||
|
// Returning error types in await isn't supported as of now
|
||||||
|
util::trap();
|
||||||
|
#endif // CONTINUABLE_WITH_EXCEPTIONS
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -35,17 +35,17 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#if !defined(CONTINUABLE_WITH_CUSTOM_ERROR_TYPE) && \
|
|
||||||
!defined(CONTINUABLE_WITH_NO_EXCEPTIONS)
|
|
||||||
#include <exception>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <continuable/continuable-api.hpp>
|
#include <continuable/continuable-api.hpp>
|
||||||
|
#include <continuable/detail/features.hpp>
|
||||||
#include <continuable/detail/hints.hpp>
|
#include <continuable/detail/hints.hpp>
|
||||||
#include <continuable/detail/traits.hpp>
|
#include <continuable/detail/traits.hpp>
|
||||||
#include <continuable/detail/types.hpp>
|
#include <continuable/detail/types.hpp>
|
||||||
#include <continuable/detail/util.hpp>
|
#include <continuable/detail/util.hpp>
|
||||||
|
|
||||||
|
#if defined(CONTINUABLE_WITH_EXCEPTIONS)
|
||||||
|
#include <exception>
|
||||||
|
#endif // CONTINUABLE_WITH_EXCEPTIONS
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
/// The namespace `base` provides the low level API for working
|
/// The namespace `base` provides the low level API for working
|
||||||
@ -151,8 +151,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !defined(CONTINUABLE_WITH_CUSTOM_ERROR_TYPE) && \
|
#if defined(CONTINUABLE_WITH_EXCEPTIONS)
|
||||||
!defined(CONTINUABLE_WITH_NO_EXCEPTIONS)
|
|
||||||
#define CONTINUABLE_BLOCK_TRY_BEGIN try {
|
#define CONTINUABLE_BLOCK_TRY_BEGIN try {
|
||||||
#define CONTINUABLE_BLOCK_TRY_END \
|
#define CONTINUABLE_BLOCK_TRY_END \
|
||||||
} \
|
} \
|
||||||
@ -161,10 +160,10 @@ public:
|
|||||||
types::dispatch_error_tag{}, std::current_exception()); \
|
types::dispatch_error_tag{}, std::current_exception()); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else // CONTINUABLE_WITH_EXCEPTIONS
|
||||||
#define CONTINUABLE_BLOCK_TRY_BEGIN {
|
#define CONTINUABLE_BLOCK_TRY_BEGIN {
|
||||||
#define CONTINUABLE_BLOCK_TRY_END }
|
#define CONTINUABLE_BLOCK_TRY_END }
|
||||||
#endif
|
#endif // CONTINUABLE_WITH_EXCEPTIONS
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
constexpr auto make_invoker(T&& invoke, hints::signature_hint_tag<Args...>) {
|
constexpr auto make_invoker(T&& invoke, hints::signature_hint_tag<Args...>) {
|
||||||
|
|||||||
@ -52,8 +52,46 @@ using storage_of_t = //
|
|||||||
? sizeof(types::error_type)
|
? sizeof(types::error_type)
|
||||||
: sizeof(T))>;
|
: sizeof(T))>;
|
||||||
|
|
||||||
|
template <typename Base>
|
||||||
|
struct expected_move_base {
|
||||||
|
constexpr expected_move_base() = default;
|
||||||
|
|
||||||
|
expected_move_base(expected_move_base const&) = default;
|
||||||
|
explicit expected_move_base(expected_move_base&& right) {
|
||||||
|
Base& me = *static_cast<Base*>(this);
|
||||||
|
Base& other = *static_cast<Base*>(&right);
|
||||||
|
assert(!other.is_empty());
|
||||||
|
|
||||||
|
#ifndef _NDEBUG
|
||||||
|
me.set(slot_t::empty);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
other.visit([&](auto&& value) {
|
||||||
|
// ...
|
||||||
|
me.init(std::move(value));
|
||||||
|
});
|
||||||
|
me.set(other.get());
|
||||||
|
other.destroy();
|
||||||
|
}
|
||||||
|
expected_move_base& operator=(expected_move_base const&) = default;
|
||||||
|
expected_move_base& operator=(expected_move_base&& right) {
|
||||||
|
Base& me = *static_cast<Base*>(this);
|
||||||
|
Base& other = *static_cast<Base*>(&right);
|
||||||
|
assert(!other.is_empty());
|
||||||
|
|
||||||
|
me.weak_destroy();
|
||||||
|
|
||||||
|
other.visit([&](auto&& value) {
|
||||||
|
// ...
|
||||||
|
me.init(std::move(value));
|
||||||
|
});
|
||||||
|
me.set(other.get());
|
||||||
|
other.destroy();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
template <typename Base, bool IsCopyable /*= true*/>
|
template <typename Base, bool IsCopyable /*= true*/>
|
||||||
struct expected_copy_base {
|
struct expected_copy_base : expected_move_base<Base> {
|
||||||
constexpr expected_copy_base() = default;
|
constexpr expected_copy_base() = default;
|
||||||
|
|
||||||
expected_copy_base(expected_copy_base&&) = default;
|
expected_copy_base(expected_copy_base&&) = default;
|
||||||
@ -62,6 +100,7 @@ struct expected_copy_base {
|
|||||||
{
|
{
|
||||||
Base& me = *static_cast<Base*>(this);
|
Base& me = *static_cast<Base*>(this);
|
||||||
Base const& other = *static_cast<Base const*>(&right);
|
Base const& other = *static_cast<Base const*>(&right);
|
||||||
|
assert(!other->is_empty());
|
||||||
|
|
||||||
#ifndef _NDEBUG
|
#ifndef _NDEBUG
|
||||||
me.set(slot_t::empty);
|
me.set(slot_t::empty);
|
||||||
@ -79,6 +118,7 @@ struct expected_copy_base {
|
|||||||
{
|
{
|
||||||
Base& me = *static_cast<Base*>(this);
|
Base& me = *static_cast<Base*>(this);
|
||||||
Base const& other = *static_cast<Base const*>(&right);
|
Base const& other = *static_cast<Base const*>(&right);
|
||||||
|
assert(!other.is_empty());
|
||||||
|
|
||||||
me.weak_destroy();
|
me.weak_destroy();
|
||||||
|
|
||||||
@ -91,7 +131,7 @@ struct expected_copy_base {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <typename Base /*, bool IsCopyable = false*/>
|
template <typename Base /*, bool IsCopyable = false*/>
|
||||||
struct expected_copy_base<Base, false> {
|
struct expected_copy_base<Base, false> : expected_move_base<Base> {
|
||||||
constexpr expected_copy_base() = default;
|
constexpr expected_copy_base() = default;
|
||||||
|
|
||||||
expected_copy_base(expected_copy_base const&) = default;
|
expected_copy_base(expected_copy_base const&) = default;
|
||||||
@ -99,40 +139,6 @@ struct expected_copy_base<Base, false> {
|
|||||||
expected_copy_base& operator=(expected_copy_base const&) = default;
|
expected_copy_base& operator=(expected_copy_base const&) = default;
|
||||||
expected_copy_base& operator=(expected_copy_base&& right) = delete;
|
expected_copy_base& operator=(expected_copy_base&& right) = delete;
|
||||||
};
|
};
|
||||||
template <typename Base>
|
|
||||||
struct expected_move_base {
|
|
||||||
constexpr expected_move_base() = default;
|
|
||||||
|
|
||||||
expected_move_base(expected_move_base const&) = default;
|
|
||||||
explicit expected_move_base(expected_move_base&& right) {
|
|
||||||
Base& me = *static_cast<Base*>(this);
|
|
||||||
Base& other = *static_cast<Base*>(&right);
|
|
||||||
|
|
||||||
#ifndef _NDEBUG
|
|
||||||
me.set(slot_t::empty);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
other.visit([&](auto&& value) {
|
|
||||||
// ...
|
|
||||||
me.init(std::move(value));
|
|
||||||
});
|
|
||||||
me.set(other.consume());
|
|
||||||
}
|
|
||||||
expected_move_base& operator=(expected_move_base const&) = default;
|
|
||||||
expected_move_base& operator=(expected_move_base&& right) {
|
|
||||||
Base& me = *static_cast<Base*>(this);
|
|
||||||
Base& other = *static_cast<Base*>(&right);
|
|
||||||
|
|
||||||
me.weak_destroy();
|
|
||||||
|
|
||||||
other.visit([&](auto&& value) {
|
|
||||||
// ...
|
|
||||||
me.init(std::move(value));
|
|
||||||
});
|
|
||||||
me.set(other.consume());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
/// A class similar to the one in the expected proposal,
|
/// A class similar to the one in the expected proposal,
|
||||||
@ -140,8 +146,7 @@ struct expected_move_base {
|
|||||||
/// exceptions are used.
|
/// exceptions are used.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class expected
|
class expected
|
||||||
: detail::expected_move_base<expected<T>>,
|
: detail::expected_copy_base<
|
||||||
detail::expected_copy_base<
|
|
||||||
expected<T>, std::is_copy_constructible<types::error_type>::value &&
|
expected<T>, std::is_copy_constructible<types::error_type>::value &&
|
||||||
std::is_copy_constructible<T>::value> {
|
std::is_copy_constructible<T>::value> {
|
||||||
|
|
||||||
@ -153,7 +158,7 @@ class expected
|
|||||||
friend struct detail::expected_copy_base;
|
friend struct detail::expected_copy_base;
|
||||||
|
|
||||||
detail::storage_of_t<T> storage_;
|
detail::storage_of_t<T> storage_;
|
||||||
detail::slot_t slot_ = detail::slot_t::empty;
|
detail::slot_t slot_;
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
expected(V&& value, detail::slot_t const slot) {
|
expected(V&& value, detail::slot_t const slot) {
|
||||||
@ -163,7 +168,13 @@ class expected
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
expected() = default;
|
constexpr expected() : slot_(detail::slot_t::empty) {
|
||||||
|
}
|
||||||
|
|
||||||
|
expected(expected const&) = default;
|
||||||
|
expected(expected&&) = default;
|
||||||
|
expected& operator=(expected const&) = default;
|
||||||
|
expected& operator=(expected&&) = default;
|
||||||
|
|
||||||
explicit expected(T value) //
|
explicit expected(T value) //
|
||||||
: expected(std::move(value), detail::slot_t::value) {
|
: expected(std::move(value), detail::slot_t::value) {
|
||||||
@ -181,18 +192,13 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
expected(expected const&) = default;
|
|
||||||
expected(expected&& right) = default;
|
|
||||||
expected& operator=(expected const&) = default;
|
|
||||||
expected& operator=(expected&& right) = default;
|
|
||||||
|
|
||||||
bool is_value() const noexcept {
|
bool is_value() const noexcept {
|
||||||
assert(!is_empty());
|
assert(!is_empty());
|
||||||
return slot_ == detail::slot_t::value;
|
return is(detail::slot_t::value);
|
||||||
}
|
}
|
||||||
bool is_exception() const noexcept {
|
bool is_exception() const noexcept {
|
||||||
assert(!is_empty());
|
assert(!is_empty());
|
||||||
return slot_ == detail::slot_t::error;
|
return is(detail::slot_t::error);
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit constexpr operator bool() const noexcept {
|
explicit constexpr operator bool() const noexcept {
|
||||||
@ -261,7 +267,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_empty() const noexcept {
|
bool is_empty() const noexcept {
|
||||||
return slot_ == detail::slot_t::empty;
|
return is(detail::slot_t::empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
@ -308,11 +314,6 @@ private:
|
|||||||
void set(detail::slot_t const slot) {
|
void set(detail::slot_t const slot) {
|
||||||
slot_ = slot;
|
slot_ = slot;
|
||||||
}
|
}
|
||||||
detail::slot_t consume() {
|
|
||||||
auto const current = get();
|
|
||||||
destroy();
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} // namespace util
|
} // namespace util
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|||||||
@ -47,6 +47,14 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif // CONTINUABLE_WITH_NO_EXCEPTIONS
|
#endif // CONTINUABLE_WITH_NO_EXCEPTIONS
|
||||||
|
|
||||||
|
/// Define CONTINUABLE_WITH_EXCEPTIONS when exceptions are used
|
||||||
|
#if !defined(CONTINUABLE_WITH_CUSTOM_ERROR_TYPE) && \
|
||||||
|
!defined(CONTINUABLE_WITH_NO_EXCEPTIONS)
|
||||||
|
#define CONTINUABLE_WITH_EXCEPTIONS 1
|
||||||
|
#else
|
||||||
|
#undef CONTINUABLE_WITH_EXCEPTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
/// TODO Enable this
|
/// TODO Enable this
|
||||||
#undef CONTINUABLE_HAS_CXX17_CONSTEXPR_IF
|
#undef CONTINUABLE_HAS_CXX17_CONSTEXPR_IF
|
||||||
/// TODO Enable this
|
/// TODO Enable this
|
||||||
|
|||||||
@ -106,27 +106,25 @@ TYPED_TEST(expected_all_tests, is_move_constructible) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(expected_all_tests, is_move_assignable) {
|
TYPED_TEST(expected_all_tests, is_value_move_assignable) {
|
||||||
{
|
TypeParam old(this->supply(CANARY));
|
||||||
TypeParam old(this->supply(CANARY));
|
TypeParam e;
|
||||||
TypeParam e;
|
e = std::move(old);
|
||||||
e = std::move(old);
|
|
||||||
|
|
||||||
EXPECT_TRUE(bool(e));
|
EXPECT_TRUE(bool(e));
|
||||||
EXPECT_EQ(this->get(*e), CANARY);
|
EXPECT_EQ(this->get(*e), CANARY);
|
||||||
EXPECT_TRUE(e.is_value());
|
EXPECT_TRUE(e.is_value());
|
||||||
EXPECT_FALSE(e.is_exception());
|
EXPECT_FALSE(e.is_exception());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
TYPED_TEST(expected_all_tests, is_error_move_assignable) {
|
||||||
TypeParam old(error_type{});
|
TypeParam old(error_type{});
|
||||||
TypeParam e;
|
TypeParam e;
|
||||||
e = std::move(old);
|
e = std::move(old);
|
||||||
|
|
||||||
EXPECT_FALSE(bool(e));
|
EXPECT_FALSE(bool(e));
|
||||||
EXPECT_FALSE(e.is_value());
|
EXPECT_FALSE(e.is_value());
|
||||||
EXPECT_TRUE(e.is_exception());
|
EXPECT_TRUE(e.is_exception());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(expected_all_tests, is_value_assignable) {
|
TYPED_TEST(expected_all_tests, is_value_assignable) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user