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 class continuable_base;
friend struct detail::base::attorney; 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 // The continuation type or intermediate result
Data data_; Data data_;
// The transferable state which represents the validity of the object // 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. /// the continuable by any object which is useful for type-erasure.
template <typename OData, typename OAnnotation> template <typename OData, typename OAnnotation>
continuable_base(continuable_base<OData, OAnnotation>&& other) 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 /// \cond false
@ -241,7 +246,7 @@ public:
E&& executor = detail::types::this_thread_executor_tag{}) && { E&& executor = detail::types::this_thread_executor_tag{}) && {
return detail::base::chain_continuation<detail::base::handle_results::yes, return detail::base::chain_continuation<detail::base::handle_results::yes,
detail::base::handle_errors::no>( 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)); std::forward<E>(executor));
} }
@ -267,7 +272,7 @@ public:
template <typename OData, typename OAnnotation> template <typename OData, typename OAnnotation>
auto then(continuable_base<OData, OAnnotation>&& continuation) && { auto then(continuable_base<OData, OAnnotation>&& continuation) && {
return std::move(*this).then( 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 /// 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{}) && { E&& executor = detail::types::this_thread_executor_tag{}) && {
return detail::base::chain_continuation<detail::base::handle_results::no, return detail::base::chain_continuation<detail::base::handle_results::no,
detail::base::handle_errors::plain>( 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)); std::forward<E>(executor));
} }
@ -375,7 +380,7 @@ public:
E&& executor = detail::types::this_thread_executor_tag{}) && { E&& executor = detail::types::this_thread_executor_tag{}) && {
return detail::base::chain_continuation< return detail::base::chain_continuation<
detail::base::handle_results::yes, 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<T>(callback),
std::forward<E>(executor)); std::forward<E>(executor));
} }
@ -390,7 +395,7 @@ public:
/// \since 2.0.0 /// \since 2.0.0
template <typename T> template <typename T>
auto apply(T&& transform) && { 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. /// The pipe operator | is an alias for the continuable::then method.
@ -585,6 +590,33 @@ public:
return std::move(*this); 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 /// \cond false
#ifdef CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE #ifdef CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
/// \endcond /// \endcond
@ -667,7 +699,7 @@ public:
/// ///
/// \since 2.0.0 /// \since 2.0.0
auto operator co_await() && { auto operator co_await() && {
return detail::awaiting::create_awaiter(std::move(*this).materialize()); return detail::awaiting::create_awaiter(std::move(*this).finish());
} }
/// \cond false /// \cond false
#endif // CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE #endif // CONTINUABLE_HAS_EXPERIMENTAL_COROUTINE
@ -678,11 +710,6 @@ private:
ownership_.release(); ownership_.release();
} }
auto materialize() && {
return detail::connection::materializer<continuable_base>::apply(
std::move(*this));
}
Data&& consume_data() && { Data&& consume_data() && {
assert_acquired(); assert_acquired();
release(); release();

View File

@ -83,7 +83,7 @@ auto normalize(Strategy /*strategy*/,
// If the right continuation is a different strategy materialize it // If the right continuation is a different strategy materialize it
// in order to keep the precedence in cases where: `c1 && (c2 || c3)`. // 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: /// - The continuable is inside the current strategy state:
/// -> return the data of the tuple /// -> return the data of the tuple
@ -179,7 +179,7 @@ public:
// Materialize every continuable // Materialize every continuable
// TODO Actually we would just need to consume the data here // 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 static auto
invoke_continuation(continuable_base<Data, Annotation>&& continuation, invoke_continuation(continuable_base<Data, Annotation>&& continuation,
Callback&& callback) noexcept { Callback&& callback) noexcept {
auto materialized = std::move(continuation).materialize(); auto materialized = std::move(continuation).finish();
materialized.release(); materialized.release();
return materialized.data_(std::forward<Callback>(callback)); 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> template <typename Data, typename Annotation>
static Data&& static Data&&
consume_data(continuable_base<Data, Annotation>&& continuation) { consume_data(continuable_base<Data, Annotation>&& continuation) {
@ -167,8 +162,8 @@ template <typename Data, typename Annotation>
constexpr auto constexpr auto
invoker_of(traits::identity<continuable_base<Data, Annotation>>) { invoker_of(traits::identity<continuable_base<Data, Annotation>>) {
/// Get the hint of the unwrapped returned continuable /// Get the hint of the unwrapped returned continuable
using Type = decltype(attorney::materialize( using Type =
std::declval<continuable_base<Data, Annotation>>())); decltype(std::declval<continuable_base<Data, Annotation>>().finish());
auto constexpr const hint = hints::hint_of(traits::identify<Type>{}); auto constexpr const hint = hints::hint_of(traits::identify<Type>{});