Specialize the continuation chainer in case ready continuables are chained

This commit is contained in:
Denis Blank 2018-12-09 04:53:28 +01:00
parent 9ceee76647
commit 7273891a4c
8 changed files with 76 additions and 37 deletions

View File

@ -90,13 +90,13 @@ using is_continuable = detail::base::is_continuable<T>;
/// ///
/// \since 1.0.0 /// \since 1.0.0
template <typename Data, typename Annotation> template <typename Data, typename Annotation>
class continuable_base class continuable_base {
: public detail::annotation_trait<Annotation>::template //
annotation_base<continuable_base<Data, Annotation>> {
/// \cond false /// \cond false
using ownership = detail::util::ownership; using ownership = detail::util::ownership;
using annotation_trait = detail::annotation_trait<Annotation>;
template <typename, typename> template <typename, typename>
friend class continuable_base; friend class continuable_base;
friend struct detail::base::attorney; friend struct detail::base::attorney;
@ -562,7 +562,6 @@ public:
detail::base::finalize_continuation(std::move(*this)); detail::base::finalize_continuation(std::move(*this));
} }
#ifdef CONTINUABLE_HAS_DOXYGEN
/// Materializes the continuation expression template and finishes /// Materializes the continuation expression template and finishes
/// the current applied strategy such that the resulting continuable /// the current applied strategy such that the resulting continuable
/// will always be a concrete type and Continuable::is_concrete holds. /// will always be a concrete type and Continuable::is_concrete holds.
@ -587,8 +586,9 @@ public:
/// on conversion. /// on conversion.
/// ///
/// \since 4.0.0 /// \since 4.0.0
unspecified finish() &&; auto finish() && {
#endif // CONTINUABLE_HAS_DOXYGEN return annotation_trait::finish(std::move(*this));
}
/// Predicate to check whether the cti::continuable_base is frozen or not. /// Predicate to check whether the cti::continuable_base is frozen or not.
/// ///

View File

@ -189,7 +189,8 @@ struct connection_finalizer<connection_strategy_all_tag> {
/// Specialization for a connection annotation /// Specialization for a connection annotation
template <> template <>
struct annotation_trait<connection::connection_strategy_all_tag> struct annotation_trait<connection::connection_strategy_all_tag>
: connection::connection_annotation_trait {}; : connection::connection_annotation_trait<
connection::connection_strategy_all_tag> {};
} // namespace detail } // namespace detail
} // namespace cti } // namespace cti

View File

@ -193,10 +193,11 @@ struct connection_finalizer<connection_strategy_any_tag> {
}; };
} // namespace connection } // namespace connection
/// Specialization for a connection annotation /// Specialization for a connection annotation
template <> template <>
struct annotation_trait<connection::connection_strategy_any_tag> struct annotation_trait<connection::connection_strategy_any_tag>
: connection::connection_annotation_trait {}; : connection::connection_annotation_trait<
connection::connection_strategy_any_tag> {};
} // namespace detail } // namespace detail
} // namespace cti } // namespace cti

View File

@ -164,7 +164,8 @@ struct connection_finalizer<connection_strategy_seq_tag> {
/// Specialization for a connection annotation /// Specialization for a connection annotation
template <> template <>
struct annotation_trait<connection::connection_strategy_seq_tag> struct annotation_trait<connection::connection_strategy_seq_tag>
: connection::connection_annotation_trait {}; : connection::connection_annotation_trait<
connection::connection_strategy_seq_tag> {};
} // namespace detail } // namespace detail
} // namespace cti } // namespace cti

View File

@ -124,25 +124,22 @@ auto connect(Strategy strategy, continuable_base<LData, LAnnotation>&& left,
template <typename Strategy> template <typename Strategy>
struct connection_finalizer; struct connection_finalizer;
template <typename Strategy>
struct connection_annotation_trait { struct connection_annotation_trait {
/// Finalizes the connection logic of a given connection
template <typename Continuable> template <typename Continuable>
struct annotation_base; static auto finish(Continuable&& continuable) {
template <typename Data, typename Strategy> using continuable_t = traits::unrefcv_t<Continuable>;
struct annotation_base<continuable_base<Data, Strategy>> {
/// Finalizes the connection logic of a given connection
auto finish() && {
using continuable_t = continuable_base<Data, Strategy>;
auto&& continuation = std::move(*static_cast<continuable_t*>(this));
using finalizer = connection_finalizer<Strategy>; using finalizer = connection_finalizer<Strategy>;
util::ownership ownership = base::attorney::ownership_of(continuation); util::ownership ownership = base::attorney::ownership_of(continuable);
auto connection = base::attorney::consume(std::move(continuation)); auto connection =
base::attorney::consume(std::forward<Continuable>(continuable));
// Return a new continuable which // Return a new continuable which
return finalizer::finalize(std::move(connection), std::move(ownership)); return finalizer::finalize(std::move(connection), std::move(ownership));
} }
};
}; };
class prepare_continuables { class prepare_continuables {

View File

@ -44,11 +44,9 @@ struct annotation_trait;
template <typename... Args> template <typename... Args>
struct annotation_trait<traits::identity<Args...>> { struct annotation_trait<traits::identity<Args...>> {
template <typename Continuable> template <typename Continuable>
struct annotation_base { static Continuable&& finish(Continuable&& continuable) {
Continuable&& finish() { return std::forward<Continuable>(continuable);
return std::move(*static_cast<Continuable*>(this)); }
}
};
}; };
namespace hints { namespace hints {
@ -57,11 +55,9 @@ namespace hints {
/// ///
/// This is the overload taking an arbitrary amount of args /// This is the overload taking an arbitrary amount of args
template <typename... HintArgs> template <typename... HintArgs>
struct from_args struct from_args : std::common_type<traits::identity<HintArgs...>> {};
: std::common_type<traits::identity<HintArgs...>> {};
template <> template <>
struct from_args<void> struct from_args<void> : std::common_type<traits::identity<>> {};
: std::common_type<traits::identity<>> {};
} // namespace hints } // namespace hints
} // namespace detail } // namespace detail
} // namespace cti } // namespace cti

View File

@ -761,8 +761,7 @@ struct chained_continuation<traits::identity<Args...>, HandleResults,
if (is_ready) { if (is_ready) {
// Invoke the proxy callback directly with the result to // Invoke the proxy callback directly with the result to
// avoid a potential type erasure. // avoid a potential type erasure.
// traits::unpack(std::move(proxy), traits::unpack(std::move(proxy), std::move(continuation_)(query_arg_t{}));
std::move(continuation_)(query_arg_t{});
} else { } else {
// Invoke the continuation with a proxy callback. // Invoke the continuation with a proxy callback.
// The proxy callback is responsible for passing // The proxy callback is responsible for passing
@ -779,6 +778,48 @@ struct chained_continuation<traits::identity<Args...>, HandleResults,
util::unreachable(); util::unreachable();
} }
}; };
// Specialization to unpack ready continuables directly
template <typename... Args, handle_results HandleResults,
handle_errors HandleErrors, typename Callback, typename Executor>
struct chained_continuation<traits::identity<Args...>, HandleResults,
HandleErrors, ready_continuation<Args...>, Callback,
Executor> {
ready_continuation<Args...> continuation_;
Callback callback_;
Executor executor_;
explicit chained_continuation(ready_continuation<Args...> 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 <typename NextCallback>
void operator()(NextCallback&& next_callback) {
auto proxy = callbacks::make_callback<traits::identity<Args...>,
HandleResults, HandleErrors>(
std::move(callback_), std::move(executor_),
std::forward<decltype(next_callback)>(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<Args...> operator()(query_arg_t) {
util::unreachable();
}
};
/// Chains a callback together with a continuation and returns a /// Chains a callback together with a continuation and returns a
/// continuation: /// continuation:

View File

@ -32,6 +32,7 @@
#define CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED #define CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED
#include <cassert> #include <cassert>
#include <cstdlib>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@ -258,11 +259,12 @@ private:
__builtin_unreachable(); __builtin_unreachable();
#elif defined(__has_builtin) && __has_builtin(__builtin_unreachable) #elif defined(__has_builtin) && __has_builtin(__builtin_unreachable)
__builtin_unreachable(); __builtin_unreachable();
#else
std::abort();
#endif #endif
} }
/// Causes the application to exit abnormally because we are /// Causes the application to exit abnormally.
/// in an invalid state.
[[noreturn]] inline void trap() { [[noreturn]] inline void trap() {
#if defined(_MSC_VER) #if defined(_MSC_VER)
__debugbreak(); __debugbreak();