Expose finish() method in continuable_base which makes it possible

to materialize the continuable_base when using it as an expression template.
This commit is contained in:
Denis Blank 2018-11-24 14:26:51 +01:00
parent 0657445466
commit 6969a9e392
3 changed files with 44 additions and 22 deletions

View File

@ -96,6 +96,11 @@ class continuable_base {
friend class continuable_base;
friend struct detail::base::attorney;
// The materializer which is used when this continuable_base is an
// expression template such that is_connection_strategy<Annotation>::value
// holds for the Annotation.
using materializer = detail::connection::materializer<continuable_base>;
// The continuation type or intermediate result
Data data_;
// The transferable state which represents the validity of the object
@ -126,7 +131,7 @@ public:
/// the continuable by any object which is useful for type-erasure.
template <typename OData, typename OAnnotation>
continuable_base(continuable_base<OData, OAnnotation>&& other)
: continuable_base(std::move(other).materialize().consume_data()) {
: continuable_base(std::move(other).finish().consume_data()) {
}
/// \cond false
@ -241,7 +246,7 @@ public:
E&& executor = detail::types::this_thread_executor_tag{}) && {
return detail::base::chain_continuation<detail::base::handle_results::yes,
detail::base::handle_errors::no>(
std::move(*this).materialize(), std::forward<T>(callback),
std::move(*this).finish(), std::forward<T>(callback),
std::forward<E>(executor));
}
@ -267,7 +272,7 @@ public:
template <typename OData, typename OAnnotation>
auto then(continuable_base<OData, OAnnotation>&& continuation) && {
return std::move(*this).then(
detail::base::wrap_continuation(std::move(continuation).materialize()));
detail::base::wrap_continuation(std::move(continuation).finish()));
}
/// Main method of the continuable_base to catch exceptions and error codes
@ -314,7 +319,7 @@ public:
E&& executor = detail::types::this_thread_executor_tag{}) && {
return detail::base::chain_continuation<detail::base::handle_results::no,
detail::base::handle_errors::plain>(
std::move(*this).materialize(), std::forward<T>(callback),
std::move(*this).finish(), std::forward<T>(callback),
std::forward<E>(executor));
}
@ -375,7 +380,7 @@ public:
E&& executor = detail::types::this_thread_executor_tag{}) && {
return detail::base::chain_continuation<
detail::base::handle_results::yes,
detail::base::handle_errors::forward>(std::move(*this).materialize(),
detail::base::handle_errors::forward>(std::move(*this).finish(),
std::forward<T>(callback),
std::forward<E>(executor));
}
@ -390,7 +395,7 @@ public:
/// \since 2.0.0
template <typename T>
auto apply(T&& transform) && {
return std::forward<T>(transform)(std::move(*this).materialize());
return std::forward<T>(transform)(std::move(*this).finish());
}
/// The pipe operator | is an alias for the continuable::then method.
@ -585,6 +590,33 @@ public:
return std::move(*this);
}
/// Materializes the continuation expression template and finishes
/// the current applied strategy.
///
/// This can be used in the case where we are chaining continuations lazily
/// through a strategy, for instance when applying operators for
/// expressing connections and then want to return a materialized
/// continuable_base which uses the strategy respectively.
/// ```cpp
/// auto do_both() {
/// return (wait(10s) || wait_key_pressed(KEY_SPACE)).finish();
/// }
///
/// // Without a call to finish() this would lead to
/// // an unintended evaluation strategy:
/// do_both() || wait(5s);
/// ```
///
/// \note When using a type erased continuable_base such as
/// `continuable<...>` this method doesn't need to be called
/// since the continuable_base is materialized automatically
/// on conversion.
///
/// \since 4.0.0
auto finish() && {
return materializer::apply(std::move(*this));
}
/// \cond false
#ifdef CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
/// \endcond
@ -667,7 +699,7 @@ public:
///
/// \since 2.0.0
auto operator co_await() && {
return detail::awaiting::create_awaiter(std::move(*this).materialize());
return detail::awaiting::create_awaiter(std::move(*this).finish());
}
/// \cond false
#endif // CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
@ -678,11 +710,6 @@ private:
ownership_.release();
}
auto materialize() && {
return detail::connection::materializer<continuable_base>::apply(
std::move(*this));
}
Data&& consume_data() && {
assert_acquired();
release();

View File

@ -83,7 +83,7 @@ auto normalize(Strategy /*strategy*/,
// If the right continuation is a different strategy materialize it
// in order to keep the precedence in cases where: `c1 && (c2 || c3)`.
return std::make_tuple(base::attorney::materialize(std::move(continuation)));
return std::make_tuple(std::move(continuation).finish());
}
/// - The continuable is inside the current strategy state:
/// -> return the data of the tuple
@ -179,7 +179,7 @@ public:
// Materialize every continuable
// TODO Actually we would just need to consume the data here
return base::attorney::materialize(std::forward<Continuable>(continuable));
return std::forward<Continuable>(continuable).finish();
}
};

View File

@ -82,16 +82,11 @@ struct attorney {
static auto
invoke_continuation(continuable_base<Data, Annotation>&& continuation,
Callback&& callback) noexcept {
auto materialized = std::move(continuation).materialize();
auto materialized = std::move(continuation).finish();
materialized.release();
return materialized.data_(std::forward<Callback>(callback));
}
template <typename Data, typename Annotation>
static auto materialize(continuable_base<Data, Annotation>&& continuation) {
return std::move(continuation).materialize();
}
template <typename Data, typename Annotation>
static Data&&
consume_data(continuable_base<Data, Annotation>&& continuation) {
@ -167,8 +162,8 @@ template <typename Data, typename Annotation>
constexpr auto
invoker_of(traits::identity<continuable_base<Data, Annotation>>) {
/// Get the hint of the unwrapped returned continuable
using Type = decltype(attorney::materialize(
std::declval<continuable_base<Data, Annotation>>()));
using Type =
decltype(std::declval<continuable_base<Data, Annotation>>().finish());
auto constexpr const hint = hints::hint_of(traits::identify<Type>{});