Lift connection logic up from all and any to a unified function

This commit is contained in:
Denis Blank 2018-02-26 18:55:06 +01:00
parent fb4a34b328
commit b3a4a3d359
5 changed files with 115 additions and 75 deletions

View File

@ -608,8 +608,7 @@ private:
OAnnotation>::value>* = nullptr>
static auto
materializeImpl(continuable_base<OData, OAnnotation>&& continuable) {
using finalizer = detail::composition::composition_finalizer<OAnnotation>;
return finalizer::finalize(std::move(continuable));
return detail::composition::finalize_composition(std::move(continuable));
}
Data&& consume_data() && {

View File

@ -35,6 +35,7 @@
#include <type_traits>
#include <utility>
#include <continuable/continuable-traverse.hpp>
#include <continuable/detail/base.hpp>
#include <continuable/detail/traits.hpp>
#include <continuable/detail/types.hpp>
@ -126,11 +127,46 @@ auto connect(Strategy strategy, continuable_base<LData, LAnnotation>&& left,
return base::attorney::create(std::move(data), strategy, ownership_);
}
/// All strategies should specialize this class in order to provide
/// a finalize static method.
/// All strategies should specialize this class in order to provide:
/// - A finalize static method that creates the callable object which
/// is invoked with the callback to call when the composition is finished.
/// - A static method hint that returns the new signature hint.
template <typename Strategy>
struct composition_finalizer;
struct aggregate_ownership {
util::ownership& ownership_;
template <typename Continuable,
std::enable_if_t<base::is_continuable<
std::decay_t<Continuable>>::value>* = nullptr>
auto operator()(Continuable const& continuable) noexcept {
util::ownership other = base::attorney::ownership_of(continuable);
/*if (!other.is_default())*/ { ownership_ |= other; }
}
};
// Merges the ownership of all continuables involved into the strategy
/*if (ownership.is_acquired() || !ownership.is_frozen()) {
traverse_pack(aggregate_ownership{ownership}, composition);
}*/
/// Finalizes the any logic of a given composition
template <typename Data, typename Strategy>
auto finalize_composition(continuable_base<Data, Strategy>&& continuation) {
using finalizer = composition_finalizer<Strategy>;
util::ownership ownership = base::attorney::ownership_of(continuation);
auto composition = base::attorney::consume_data(std::move(continuation));
// Retrieve the new signature hint
constexpr auto const signature =
finalizer::template hint<decltype(composition)>();
// Return a new continuable which
return base::attorney::create(finalizer::finalize(std::move(composition)),
signature, std::move(ownership));
}
} // namespace composition
} // namespace detail
} // namespace cti

View File

@ -172,59 +172,55 @@ struct entry_merger {
/// Finalizes the all logic of a given composition
template <>
struct composition_finalizer<composition_strategy_all_tag> {
template <typename Composition>
static constexpr auto hint() {
return decltype(
traits::unpack(std::declval<Composition>(), all::entry_merger{})){};
}
/// Finalizes the all logic of a given composition
template <typename Continuable>
static auto finalize(Continuable&& continuation) {
template <typename Composition>
static auto finalize(Composition&& composition) {
return [composition = std::forward<Composition>(composition)](
auto&& callback) mutable {
auto ownership_ = base::attorney::ownership_of(continuation);
// We mark the current 2-dimensional position through a pair:
// std::pair<size_constant<?>, size_constant<?>>
// ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
// Continuation pos Result pos
constexpr auto const begin = std::make_pair(
traits::size_constant_of<0>(), traits::size_constant_of<0>());
constexpr auto const pack = traits::identify<decltype(composition)>{};
constexpr auto const end = traits::pack_size_of(pack);
auto const condition = [=](auto pos) { return pos.first < end; };
auto composition =
base::attorney::consume_data(std::forward<Continuable>(continuation));
constexpr auto const signature = hint<Composition>();
// Merge all signature hints together
constexpr auto const signature =
traits::unpack(composition, all::entry_merger{});
// Create the result submitter which caches all results and invokes
// the final callback upon completion.
auto submitter = all::make_all_result_submitter(
std::forward<decltype(callback)>(callback), end, signature);
return base::attorney::create(
[ signature,
composition = std::move(composition) ](auto&& callback) mutable {
// We mark the current 2-dimensional position through a pair:
// std::pair<size_constant<?>, size_constant<?>>
// ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
// Continuation pos Result pos
constexpr auto const begin = std::make_pair(
traits::size_constant_of<0>(), traits::size_constant_of<0>());
constexpr auto const pack = traits::identify<decltype(composition)>{};
constexpr auto const end = traits::pack_size_of(pack);
auto const condition = [=](auto pos) { return pos.first < end; };
// Invoke every continuation with it's callback of the submitter
traits::static_while(begin, condition, [&](auto current) mutable {
auto entry =
std::move(std::get<decltype(current.first)::value>(composition));
// Create the result submitter which caches all results and invokes
// the final callback upon completion.
auto submitter = all::make_all_result_submitter(
std::forward<decltype(callback)>(callback), end, signature);
// This is the length of the arguments of the current continuable
constexpr auto const arg_size =
traits::pack_size_of(hints::hint_of(traits::identity_of(entry)));
// Invoke every continuation with it's callback of the submitter
traits::static_while(begin, condition, [&](auto current) mutable {
auto entry = std::move(
std::get<decltype(current.first)::value>(composition));
// The next position in the result tuple
constexpr auto const next = current.second + arg_size;
// This is the length of the arguments of the current continuable
constexpr auto const arg_size = traits::pack_size_of(
hints::hint_of(traits::identity_of(entry)));
// Invoke the continuation with the associated submission callback
base::attorney::invoke_continuation(
std::move(entry), submitter->create_callback(current.second, next));
// The next position in the result tuple
constexpr auto const next = current.second + arg_size;
// Invoke the continuation with the associated submission callback
base::attorney::invoke_continuation(
std::move(entry),
submitter->create_callback(current.second, next));
return std::make_pair(current.first + traits::size_constant_of<1>(),
next);
});
},
signature, std::move(ownership_));
return std::make_pair(current.first + traits::size_constant_of<1>(),
next);
});
};
}
};
} // namespace composition

View File

@ -153,35 +153,30 @@ private:
/// Finalizes the any logic of a given composition
template <>
struct composition_finalizer<composition_strategy_any_tag> {
template <typename Continuable>
static auto finalize(Continuable&& continuation) {
template <typename Composition>
static constexpr auto hint() {
return decltype(traits::unpack(std::declval<Composition>(),
any::determine_shared_result{})){};
}
auto ownership = base::attorney::ownership_of(continuation);
template <typename Composition>
static auto finalize(Composition&& composition) {
return [composition = std::forward<Composition>(composition)](
auto&& callback) mutable {
// Create the submitter which calls the given callback once at the
// first callback invocation.
auto submitter = any::make_any_result_submitter(
std::forward<decltype(callback)>(callback));
auto composition =
base::attorney::consume_data(std::forward<Continuable>(continuation));
constexpr auto const signature =
traits::unpack(composition, any::determine_shared_result{});
return base::attorney::create(
[composition = std::move(composition)](auto&& callback) mutable {
// Create the submitter which calls the given callback once at the
// first callback invocation.
auto submitter = any::make_any_result_submitter(
std::forward<decltype(callback)>(callback));
traits::static_for_each_in(std::move(composition),
[&](auto&& entry) mutable {
// Invoke the continuation with a
// submission callback
base::attorney::invoke_continuation(
std::forward<decltype(entry)>(entry),
submitter->create_callback());
});
},
signature, std::move(ownership));
traits::static_for_each_in(std::move(composition),
[&](auto&& entry) mutable {
// Invoke the continuation with a
// submission callback
base::attorney::invoke_continuation(
std::forward<decltype(entry)>(entry),
submitter->create_callback());
});
};
}
};
} // namespace composition

View File

@ -202,6 +202,16 @@ public:
return *this;
}
// Assigns the right ownership to this one
ownership& operator|=(ownership const& right) noexcept {
if (!right.is_acquired()) {
release();
}
if (right.is_frozen()) {
freeze();
}
return *this;
}
// Merges both ownerships together
ownership operator|(ownership const& right) const noexcept {
return ownership(is_acquired() && right.is_acquired(),
@ -214,6 +224,10 @@ public:
constexpr bool is_frozen() const noexcept {
return frozen_;
}
/// Returns true when the ownership is in the default state
constexpr bool is_default() const noexcept {
return is_acquired() && !is_frozen();
}
void release() noexcept {
assert(is_acquired() && "Tried to release the ownership twice!");