diff --git a/include/continuable/detail/base.hpp b/include/continuable/detail/base.hpp index 5656470..ce861c0 100644 --- a/include/continuable/detail/base.hpp +++ b/include/continuable/detail/base.hpp @@ -99,7 +99,7 @@ struct attorney { } template - static util::ownership ownership_of(Continuable&& continuation) { + static util::ownership ownership_of(Continuable&& continuation) noexcept { return continuation.ownership_; } }; diff --git a/include/continuable/detail/composition.hpp b/include/continuable/detail/composition.hpp index d13d92b..5050b1c 100644 --- a/include/continuable/detail/composition.hpp +++ b/include/continuable/detail/composition.hpp @@ -31,6 +31,7 @@ #ifndef CONTINUABLE_DETAIL_COMPOSITION_HPP_INCLUDED #define CONTINUABLE_DETAIL_COMPOSITION_HPP_INCLUDED +#include #include #include #include @@ -134,23 +135,6 @@ auto connect(Strategy strategy, continuable_base&& left, template struct composition_finalizer; -struct aggregate_ownership { - util::ownership& ownership_; - - template >::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 auto finalize_composition(continuable_base&& continuation) { @@ -167,6 +151,48 @@ auto finalize_composition(continuable_base&& continuation) { return base::attorney::create(finalizer::finalize(std::move(composition)), signature, std::move(ownership)); } + +struct consume_ownership { + util::ownership& ownership_; + + template >::value>* = nullptr> + void operator()(Continuable& continuable) noexcept { + util::ownership other = base::attorney::ownership_of(continuable); + + assert(other.is_acquired() && "Only valid continuables should be passed!"); + + if (!ownership_.is_frozen() && other.is_frozen()) { + ownership_.freeze(); + } + + // Freeze the continuable since it is stored for later usage + continuable.freeze(); + } +}; + +template +auto apply_composition(Strategy, Args&&... args) { + using finalizer = composition_finalizer; + + auto composition = std::make_tuple(std::forward(args)...); + + // Retrieve the new signature hint + constexpr auto const signature = + finalizer::template hint(); + + // Freeze every continuable inside the given arguments, + // and freeze the ownership if one of the continuables + // is frozen already. + // Additionally test whether every continuable is acquired. + util::ownership ownership; + traverse_pack(consume_ownership{ownership}, std::move(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 diff --git a/include/continuable/detail/composition_remapping.hpp b/include/continuable/detail/composition_remapping.hpp index de576e5..274c99f 100644 --- a/include/continuable/detail/composition_remapping.hpp +++ b/include/continuable/detail/composition_remapping.hpp @@ -57,20 +57,13 @@ namespace remapping { // Guard object for representing void results struct void_result_guard {}; -/// Contains an continuable together with a location where the -/// result shall be stored. -template -struct indexed_continuable { - Continuable continuable; - Target* target; +// Callable object that maps void_result_guard zo zero arguments +struct clean_void_results { + auto operator()(void_result_guard) const noexcept { + return spread_this(); + } }; -template -struct is_indexed_continuable : std::false_type {}; -template -struct is_indexed_continuable> - : std::true_type {}; - namespace detail { struct result_extractor_mapper { /// Create slots for a void result which is removed later. @@ -103,22 +96,6 @@ struct result_extractor_mapper { } }; -/// Maps a deeply nested pack of continuables to -struct result_indexer_mapper { - /// Index a given continuable together with its target location - template < - typename T, - std::enable_if_t>::value>* = nullptr> - auto operator()(T&& continuable) { - auto constexpr const hint = hints::hint_of(traits::identify{}); - - using target = decltype(result_extractor_mapper::initialize(hint)); - - using type = indexed_continuable, target>; - return type{std::forward(continuable), nullptr}; - } -}; - /// Relocates the target of a deeply nested pack of indexed_continuable objects /// to the given target. template @@ -196,16 +173,6 @@ constexpr auto create_result_pack(Args&&... args) { std::forward(args)...); } -/// Returns the result pack of the given deeply nested pack. -/// This invalidates all non-continuable values contained inside the pack. -/// -/// This consumes all continuables inside the pack. -template -constexpr auto create_index_pack(Args&&... args) { - return cti::map_pack(detail::result_indexer_mapper{}, - std::forward(args)...); -} - /// Sets the target pointers of indexed_continuable's inside the index pack /// to point to their given counterparts inside the given target. template @@ -220,24 +187,9 @@ constexpr void relocate_index_pack(Relocator&& relocator, Index* index, mapper.traverse(tag, index, target); } -struct index_relocator { - template ::value>* = nullptr> - auto operator()(Index* index, Target* target) const noexcept { - // Assign the address of the target to the indexed continuable - index->target = target; - } -}; } // namespace remapping } // namespace composition } // namespace detail } // namespace cti -// auto p = std::make_tuple(cti::make_ready_continuable(0) /*, 0, 4, -// std::make_tuple(1, 2), cti::make_ready_continuable(0)*/); - -// auto r = create_result_pack(std::move(p)); -// auto i = create_index_pack(std::move(p)); -// relocate_index_pack(index_relocator{}, &i, &r); - #endif // CONTINUABLE_DETAIL_COMPOSITION_REMAPPING_HPP_INCLUDED diff --git a/include/continuable/detail/composition_seq.hpp b/include/continuable/detail/composition_seq.hpp index 0a04464..4269e7c 100644 --- a/include/continuable/detail/composition_seq.hpp +++ b/include/continuable/detail/composition_seq.hpp @@ -31,18 +31,16 @@ #ifndef CONTINUABLE_DETAIL_COMPOSITION_SEQ_HPP_INCLUDED #define CONTINUABLE_DETAIL_COMPOSITION_SEQ_HPP_INCLUDED -#include #include -#include #include #include #include #include +#include #include -#include +#include #include -#include namespace cti { namespace detail { @@ -68,12 +66,161 @@ auto sequential_connect(Left&& left, Right&& right) { }); }); } + +/// Contains an continuable together with a location where the +/// result shall be stored. +template +struct indexed_continuable { + Continuable continuable; + Target* target; +}; + +template +struct is_indexed_continuable : std::false_type {}; +template +struct is_indexed_continuable> + : std::true_type {}; + +/// Maps a deeply nested pack of continuables to an indexed continuable +struct result_indexer_mapper { + /// Index a given continuable together with its target location + template < + typename T, + std::enable_if_t>::value>* = nullptr> + auto operator()(T& continuable) { + auto constexpr const hint = hints::hint_of(traits::identify{}); + + using target = decltype(result_extractor_mapper::initialize(hint)); + + using type = indexed_continuable, target>; + return type{std::move(continuable), nullptr}; + } +}; + +/// Returns the result pack of the given deeply nested pack. +/// This invalidates all non-continuable values contained inside the pack. +/// +/// This consumes all continuables inside the pack. +template +constexpr auto create_index_pack(Args&&... args) { + return cti::map_pack(result_indexer_mapper{}, std::forward(args)...); +} + +struct index_relocator { + template ::value>* = nullptr> + auto operator()(Index* index, Target* target) const noexcept { + // Assign the address of the target to the indexed continuable + index->target = target; + } +}; + +constexpr remapping::void_result_guard wrap() { + return {}; +} +template +constexpr decltype(auto) wrap(First&& first) { + return std::forward(first); +} +template +constexpr decltype(auto) wrap(First&& first, Second&& second, Rest&&... rest) { + return std::make_tuple(std::forward(first), + std::forward(second), + std::forward(rest)...); +} + +template +struct sequential_dispatch_data { + Callback callback; + Index index; + Result result; +}; + +template +class sequential_dispatch_visitor + : std::enable_shared_from_this> { + + Data data_; + +public: + explicit sequential_dispatch_visitor(Data&& data) : data_(std::move(data)) { + // Assign the address of each result target to the corresponding + // indexed continuable. + relocate_index_pack(index_relocator{}, &data.index, &data.result); + } + + /// Returns the pack that should be traversed + auto& head() { + return data_.index; + } + + template ::value>* = nullptr> + bool operator()(async_traverse_visit_tag, Index&& /*index*/) { + return false; + } + + template + void operator()(async_traverse_detach_tag, Index&& index, N&& next) { + + std::move(index.continuable) + .then([ target = index.target, + next = std::forward(next) ](auto&&... args) { + + // Assign the result to the target + *target = wrap(std::forward(args)...); + + // Continue the asynchronous sequential traversal + next(); + }) + .done(); + } + + template + void operator()(async_traverse_complete_tag, T&& pack) { + // Remove void result guard tags + auto cleaned = + map_pack(remapping::clean_void_results{}, std::forward(pack)); + + // Call the final callback with the cleaned result + traits::unpack(std::move(cleaned), std::move(data_.callback)); + } +}; } // namespace seq /// Finalizes the seq logic of a given composition template <> struct composition_finalizer { - /// TODO + template + static constexpr auto hint() { + return decltype( + traits::unpack(std::declval(), all::entry_merger{})){}; + } + + /// Finalizes the all logic of a given composition + template + static auto finalize(Composition&& composition) { + return [composition = std::forward(composition)]( + auto&& callback) mutable { + + auto index = seq::create_index_pack(composition); + auto result = + remapping::create_result_pack(std::forward(composition)); + + // The data from which the visitor is constructed in-place + using data_t = + seq::sequential_dispatch_data, + std::decay_t, + std::decay_t>; + + // The visitor type + using visitor_t = seq::sequential_dispatch_visitor; + + traverse_pack_async(async_traverse_in_place_tag{}, + data_t{std::forward(callback), + std::move(index), std::move(result)}); + }; + } }; } // namespace composition } // namespace detail diff --git a/include/continuable/detail/util.hpp b/include/continuable/detail/util.hpp index 1b20f33..c025b59 100644 --- a/include/continuable/detail/util.hpp +++ b/include/continuable/detail/util.hpp @@ -202,16 +202,6 @@ 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(), @@ -224,10 +214,6 @@ 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!");