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
template <typename Data, typename Annotation>
class continuable_base
: public detail::annotation_trait<Annotation>::template //
annotation_base<continuable_base<Data, Annotation>> {
class continuable_base {
/// \cond false
using ownership = detail::util::ownership;
using annotation_trait = detail::annotation_trait<Annotation>;
template <typename, typename>
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.
///

View File

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

View File

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

View File

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

View File

@ -124,25 +124,22 @@ auto connect(Strategy strategy, continuable_base<LData, LAnnotation>&& left,
template <typename Strategy>
struct connection_finalizer;
template <typename Strategy>
struct connection_annotation_trait {
/// Finalizes the connection logic of a given connection
template <typename Continuable>
struct annotation_base;
template <typename Data, typename Strategy>
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));
static auto finish(Continuable&& continuable) {
using continuable_t = traits::unrefcv_t<Continuable>;
using finalizer = connection_finalizer<Strategy>;
using finalizer = connection_finalizer<Strategy>;
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>(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 {

View File

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

View File

@ -761,8 +761,7 @@ struct chained_continuation<traits::identity<Args...>, 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<traits::identity<Args...>, HandleResults,
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
/// continuation:

View File

@ -32,6 +32,7 @@
#define CONTINUABLE_DETAIL_UTIL_HPP_INCLUDED
#include <cassert>
#include <cstdlib>
#include <tuple>
#include <type_traits>
#include <utility>
@ -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();