diff --git a/include/continuable/continuable-base.hpp b/include/continuable/continuable-base.hpp index e923baa..8d9cb86 100644 --- a/include/continuable/continuable-base.hpp +++ b/include/continuable/continuable-base.hpp @@ -90,13 +90,13 @@ using is_continuable = detail::base::is_continuable; /// /// \since 1.0.0 template -class continuable_base - : public detail::annotation_trait::template // - annotation_base> { +class continuable_base { /// \cond false using ownership = detail::util::ownership; + using annotation_trait = detail::annotation_trait; + template friend class continuable_base; friend struct detail::base::attorney; @@ -562,7 +562,6 @@ public: detail::base::finalize_continuation(std::move(*this)); } -#ifdef CONTINUABLE_HAS_DOXYGEN /// Materializes the continuation expression template and finishes /// the current applied strategy such that the resulting continuable /// will always be a concrete type and Continuable::is_concrete holds. @@ -587,8 +586,9 @@ public: /// on conversion. /// /// \since 4.0.0 - unspecified finish() &&; -#endif // CONTINUABLE_HAS_DOXYGEN + auto finish() && { + return annotation_trait::finish(std::move(*this)); + } /// Predicate to check whether the cti::continuable_base is frozen or not. /// diff --git a/include/continuable/detail/connection/connection-all.hpp b/include/continuable/detail/connection/connection-all.hpp index 164437f..b9d8d95 100644 --- a/include/continuable/detail/connection/connection-all.hpp +++ b/include/continuable/detail/connection/connection-all.hpp @@ -189,7 +189,8 @@ struct connection_finalizer { /// Specialization for a connection annotation template <> struct annotation_trait - : connection::connection_annotation_trait {}; + : connection::connection_annotation_trait< + connection::connection_strategy_all_tag> {}; } // namespace detail } // namespace cti diff --git a/include/continuable/detail/connection/connection-any.hpp b/include/continuable/detail/connection/connection-any.hpp index 3238a4f..5b09b75 100644 --- a/include/continuable/detail/connection/connection-any.hpp +++ b/include/continuable/detail/connection/connection-any.hpp @@ -193,10 +193,11 @@ struct connection_finalizer { }; } // namespace connection - /// Specialization for a connection annotation +/// Specialization for a connection annotation template <> struct annotation_trait - : connection::connection_annotation_trait {}; + : connection::connection_annotation_trait< + connection::connection_strategy_any_tag> {}; } // namespace detail } // namespace cti diff --git a/include/continuable/detail/connection/connection-seq.hpp b/include/continuable/detail/connection/connection-seq.hpp index 7736982..f9b07fe 100644 --- a/include/continuable/detail/connection/connection-seq.hpp +++ b/include/continuable/detail/connection/connection-seq.hpp @@ -164,7 +164,8 @@ struct connection_finalizer { /// Specialization for a connection annotation template <> struct annotation_trait - : connection::connection_annotation_trait {}; + : connection::connection_annotation_trait< + connection::connection_strategy_seq_tag> {}; } // namespace detail } // namespace cti diff --git a/include/continuable/detail/connection/connection.hpp b/include/continuable/detail/connection/connection.hpp index 025c23d..2dca809 100644 --- a/include/continuable/detail/connection/connection.hpp +++ b/include/continuable/detail/connection/connection.hpp @@ -124,25 +124,22 @@ auto connect(Strategy strategy, continuable_base&& left, template struct connection_finalizer; +template struct connection_annotation_trait { + /// Finalizes the connection logic of a given connection template - struct annotation_base; - template - struct annotation_base> { - /// Finalizes the connection logic of a given connection - auto finish() && { - using continuable_t = continuable_base; - auto&& continuation = std::move(*static_cast(this)); + static auto finish(Continuable&& continuable) { + using continuable_t = traits::unrefcv_t; - using finalizer = connection_finalizer; + using finalizer = connection_finalizer; - util::ownership ownership = base::attorney::ownership_of(continuation); - auto connection = base::attorney::consume(std::move(continuation)); + util::ownership ownership = base::attorney::ownership_of(continuable); + auto connection = + base::attorney::consume(std::forward(continuable)); - // Return a new continuable which - return finalizer::finalize(std::move(connection), std::move(ownership)); - } - }; + // Return a new continuable which + return finalizer::finalize(std::move(connection), std::move(ownership)); + } }; class prepare_continuables { diff --git a/include/continuable/detail/core/annotation.hpp b/include/continuable/detail/core/annotation.hpp index 29a8d1b..0255936 100644 --- a/include/continuable/detail/core/annotation.hpp +++ b/include/continuable/detail/core/annotation.hpp @@ -44,11 +44,9 @@ struct annotation_trait; template struct annotation_trait> { template - struct annotation_base { - Continuable&& finish() { - return std::move(*static_cast(this)); - } - }; + static Continuable&& finish(Continuable&& continuable) { + return std::forward(continuable); + } }; namespace hints { @@ -57,11 +55,9 @@ namespace hints { /// /// This is the overload taking an arbitrary amount of args template -struct from_args - : std::common_type> {}; +struct from_args : std::common_type> {}; template <> -struct from_args - : std::common_type> {}; +struct from_args : std::common_type> {}; } // namespace hints } // namespace detail } // namespace cti diff --git a/include/continuable/detail/core/base.hpp b/include/continuable/detail/core/base.hpp index 4a7d020..0db7e00 100644 --- a/include/continuable/detail/core/base.hpp +++ b/include/continuable/detail/core/base.hpp @@ -761,8 +761,7 @@ struct chained_continuation, HandleResults, if (is_ready) { // Invoke the proxy callback directly with the result to // avoid a potential type erasure. - // traits::unpack(std::move(proxy), - std::move(continuation_)(query_arg_t{}); + traits::unpack(std::move(proxy), std::move(continuation_)(query_arg_t{})); } else { // Invoke the continuation with a proxy callback. // The proxy callback is responsible for passing @@ -779,6 +778,48 @@ struct chained_continuation, HandleResults, util::unreachable(); } }; +// Specialization to unpack ready continuables directly +template +struct chained_continuation, HandleResults, + HandleErrors, ready_continuation, Callback, + Executor> { + ready_continuation continuation_; + Callback callback_; + Executor executor_; + + explicit chained_continuation(ready_continuation continuation, + Callback callback, Executor executor) + : continuation_(std::move(continuation)), callback_(std::move(callback)), + executor_(std::move(executor)) { + } + + chained_continuation() = delete; + ~chained_continuation() = default; + chained_continuation(chained_continuation const&) = delete; + chained_continuation(chained_continuation&&) = default; + chained_continuation& operator=(chained_continuation const&) = delete; + chained_continuation& operator=(chained_continuation&&) = default; + + template + void operator()(NextCallback&& next_callback) { + auto proxy = callbacks::make_callback, + HandleResults, HandleErrors>( + std::move(callback_), std::move(executor_), + std::forward(next_callback)); + + // Extract the result out of the ready continuable + traits::unpack(std::move(proxy), std::move(continuation_)(query_arg_t{})); + } + + bool operator()(is_ready_arg_t) const noexcept { + return false; + } + + std::tuple operator()(query_arg_t) { + util::unreachable(); + } +}; /// Chains a callback together with a continuation and returns a /// continuation: diff --git a/include/continuable/detail/utility/util.hpp b/include/continuable/detail/utility/util.hpp index 004660b..0600d7d 100644 --- a/include/continuable/detail/utility/util.hpp +++ b/include/continuable/detail/utility/util.hpp @@ -32,6 +32,7 @@ #define CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED #include +#include #include #include #include @@ -258,11 +259,12 @@ private: __builtin_unreachable(); #elif defined(__has_builtin) && __has_builtin(__builtin_unreachable) __builtin_unreachable(); +#else + std::abort(); #endif } -/// Causes the application to exit abnormally because we are -/// in an invalid state. +/// Causes the application to exit abnormally. [[noreturn]] inline void trap() { #if defined(_MSC_VER) __debugbreak();