diff --git a/include/continuable/continuable-base.hpp b/include/continuable/continuable-base.hpp index de91679..4eb930b 100644 --- a/include/continuable/continuable-base.hpp +++ b/include/continuable/continuable-base.hpp @@ -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::value + // holds for the Annotation. + using materializer = detail::connection::materializer; + // 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 continuable_base(continuable_base&& 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( - std::move(*this).materialize(), std::forward(callback), + std::move(*this).finish(), std::forward(callback), std::forward(executor)); } @@ -267,7 +272,7 @@ public: template auto then(continuable_base&& 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( - std::move(*this).materialize(), std::forward(callback), + std::move(*this).finish(), std::forward(callback), std::forward(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(callback), std::forward(executor)); } @@ -390,7 +395,7 @@ public: /// \since 2.0.0 template auto apply(T&& transform) && { - return std::forward(transform)(std::move(*this).materialize()); + return std::forward(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::apply( - std::move(*this)); - } - Data&& consume_data() && { assert_acquired(); release(); diff --git a/include/continuable/detail/connection/connection.hpp b/include/continuable/detail/connection/connection.hpp index cf7bf55..13536f9 100644 --- a/include/continuable/detail/connection/connection.hpp +++ b/include/continuable/detail/connection/connection.hpp @@ -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)); + return std::forward(continuable).finish(); } }; diff --git a/include/continuable/detail/core/base.hpp b/include/continuable/detail/core/base.hpp index 63acdcc..5385bfb 100644 --- a/include/continuable/detail/core/base.hpp +++ b/include/continuable/detail/core/base.hpp @@ -82,16 +82,11 @@ struct attorney { static auto invoke_continuation(continuable_base&& continuation, Callback&& callback) noexcept { - auto materialized = std::move(continuation).materialize(); + auto materialized = std::move(continuation).finish(); materialized.release(); return materialized.data_(std::forward(callback)); } - template - static auto materialize(continuable_base&& continuation) { - return std::move(continuation).materialize(); - } - template static Data&& consume_data(continuable_base&& continuation) { @@ -167,8 +162,8 @@ template constexpr auto invoker_of(traits::identity>) { /// Get the hint of the unwrapped returned continuable - using Type = decltype(attorney::materialize( - std::declval>())); + using Type = + decltype(std::declval>().finish()); auto constexpr const hint = hints::hint_of(traits::identify{});