This commit is contained in:
Denis Blank 2017-12-08 21:59:59 +01:00
parent 73a8da1b86
commit dbf73b6ac6
5 changed files with 100 additions and 84 deletions

View File

@ -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:

View File

@ -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...>) {

View File

@ -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

View File

@ -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

View File

@ -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) {