First work on implementing deep sequential compositions

This commit is contained in:
Denis Blank 2018-02-26 18:55:06 +01:00
parent b1d7a76c8f
commit fd858a7ed7
5 changed files with 201 additions and 90 deletions

View File

@ -99,7 +99,7 @@ struct attorney {
} }
template <typename Continuable> template <typename Continuable>
static util::ownership ownership_of(Continuable&& continuation) { static util::ownership ownership_of(Continuable&& continuation) noexcept {
return continuation.ownership_; return continuation.ownership_;
} }
}; };

View File

@ -31,6 +31,7 @@
#ifndef CONTINUABLE_DETAIL_COMPOSITION_HPP_INCLUDED #ifndef CONTINUABLE_DETAIL_COMPOSITION_HPP_INCLUDED
#define CONTINUABLE_DETAIL_COMPOSITION_HPP_INCLUDED #define CONTINUABLE_DETAIL_COMPOSITION_HPP_INCLUDED
#include <cassert>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@ -134,23 +135,6 @@ auto connect(Strategy strategy, continuable_base<LData, LAnnotation>&& left,
template <typename Strategy> template <typename Strategy>
struct composition_finalizer; 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 /// Finalizes the any logic of a given composition
template <typename Data, typename Strategy> template <typename Data, typename Strategy>
auto finalize_composition(continuable_base<Data, Strategy>&& continuation) { auto finalize_composition(continuable_base<Data, Strategy>&& continuation) {
@ -167,6 +151,48 @@ auto finalize_composition(continuable_base<Data, Strategy>&& continuation) {
return base::attorney::create(finalizer::finalize(std::move(composition)), return base::attorney::create(finalizer::finalize(std::move(composition)),
signature, std::move(ownership)); signature, std::move(ownership));
} }
struct consume_ownership {
util::ownership& ownership_;
template <typename Continuable,
std::enable_if_t<base::is_continuable<
std::decay_t<Continuable>>::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 <typename Strategy, typename... Args>
auto apply_composition(Strategy, Args&&... args) {
using finalizer = composition_finalizer<Strategy>;
auto composition = std::make_tuple(std::forward<Args>(args)...);
// Retrieve the new signature hint
constexpr auto const signature =
finalizer::template hint<decltype(composition)>();
// 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 composition
} // namespace detail } // namespace detail
} // namespace cti } // namespace cti

View File

@ -57,20 +57,13 @@ namespace remapping {
// Guard object for representing void results // Guard object for representing void results
struct void_result_guard {}; struct void_result_guard {};
/// Contains an continuable together with a location where the // Callable object that maps void_result_guard zo zero arguments
/// result shall be stored. struct clean_void_results {
template <typename Continuable, typename Target> auto operator()(void_result_guard) const noexcept {
struct indexed_continuable { return spread_this();
Continuable continuable; }
Target* target;
}; };
template <typename T>
struct is_indexed_continuable : std::false_type {};
template <typename Continuable, typename Target>
struct is_indexed_continuable<indexed_continuable<Continuable, Target>>
: std::true_type {};
namespace detail { namespace detail {
struct result_extractor_mapper { struct result_extractor_mapper {
/// Create slots for a void result which is removed later. /// 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<base::is_continuable<std::decay_t<T>>::value>* = nullptr>
auto operator()(T&& continuable) {
auto constexpr const hint = hints::hint_of(traits::identify<T>{});
using target = decltype(result_extractor_mapper::initialize(hint));
using type = indexed_continuable<std::decay_t<T>, target>;
return type{std::forward<T>(continuable), nullptr};
}
};
/// Relocates the target of a deeply nested pack of indexed_continuable objects /// Relocates the target of a deeply nested pack of indexed_continuable objects
/// to the given target. /// to the given target.
template <typename Evaluator> template <typename Evaluator>
@ -196,16 +173,6 @@ constexpr auto create_result_pack(Args&&... args) {
std::forward<Args>(args)...); std::forward<Args>(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 <typename... Args>
constexpr auto create_index_pack(Args&&... args) {
return cti::map_pack(detail::result_indexer_mapper{},
std::forward<Args>(args)...);
}
/// Sets the target pointers of indexed_continuable's inside the index pack /// Sets the target pointers of indexed_continuable's inside the index pack
/// to point to their given counterparts inside the given target. /// to point to their given counterparts inside the given target.
template <typename Relocator, typename Index, typename Target> template <typename Relocator, typename Index, typename Target>
@ -220,24 +187,9 @@ constexpr void relocate_index_pack(Relocator&& relocator, Index* index,
mapper.traverse(tag, index, target); mapper.traverse(tag, index, target);
} }
struct index_relocator {
template <typename Index, typename Target,
std::enable_if_t<is_indexed_continuable<Index>::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 remapping
} // namespace composition } // namespace composition
} // namespace detail } // namespace detail
} // namespace cti } // 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 #endif // CONTINUABLE_DETAIL_COMPOSITION_REMAPPING_HPP_INCLUDED

View File

@ -31,18 +31,16 @@
#ifndef CONTINUABLE_DETAIL_COMPOSITION_SEQ_HPP_INCLUDED #ifndef CONTINUABLE_DETAIL_COMPOSITION_SEQ_HPP_INCLUDED
#define CONTINUABLE_DETAIL_COMPOSITION_SEQ_HPP_INCLUDED #define CONTINUABLE_DETAIL_COMPOSITION_SEQ_HPP_INCLUDED
#include <atomic>
#include <memory> #include <memory>
#include <mutex>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <continuable/continuable-promise-base.hpp> #include <continuable/continuable-promise-base.hpp>
#include <continuable/continuable-traverse-async.hpp>
#include <continuable/detail/base.hpp> #include <continuable/detail/base.hpp>
#include <continuable/detail/hints.hpp> #include <continuable/detail/composition_remapping.hpp>
#include <continuable/detail/traits.hpp> #include <continuable/detail/traits.hpp>
#include <continuable/detail/types.hpp>
namespace cti { namespace cti {
namespace detail { 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 <typename Continuable, typename Target>
struct indexed_continuable {
Continuable continuable;
Target* target;
};
template <typename T>
struct is_indexed_continuable : std::false_type {};
template <typename Continuable, typename Target>
struct is_indexed_continuable<indexed_continuable<Continuable, Target>>
: 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<base::is_continuable<std::decay_t<T>>::value>* = nullptr>
auto operator()(T& continuable) {
auto constexpr const hint = hints::hint_of(traits::identify<T>{});
using target = decltype(result_extractor_mapper::initialize(hint));
using type = indexed_continuable<std::decay_t<T>, 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 <typename... Args>
constexpr auto create_index_pack(Args&&... args) {
return cti::map_pack(result_indexer_mapper{}, std::forward<Args>(args)...);
}
struct index_relocator {
template <typename Index, typename Target,
std::enable_if_t<is_indexed_continuable<Index>::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 <typename First>
constexpr decltype(auto) wrap(First&& first) {
return std::forward<First>(first);
}
template <typename First, typename Second, typename... Rest>
constexpr decltype(auto) wrap(First&& first, Second&& second, Rest&&... rest) {
return std::make_tuple(std::forward<First>(first),
std::forward<Second>(second),
std::forward<Rest>(rest)...);
}
template <typename Callback, typename Index, typename Result>
struct sequential_dispatch_data {
Callback callback;
Index index;
Result result;
};
template <typename Data>
class sequential_dispatch_visitor
: std::enable_shared_from_this<sequential_dispatch_visitor<Data>> {
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 <typename Index,
std::enable_if_t<is_indexed_continuable<Index>::value>* = nullptr>
bool operator()(async_traverse_visit_tag, Index&& /*index*/) {
return false;
}
template <typename Index, typename N>
void operator()(async_traverse_detach_tag, Index&& index, N&& next) {
std::move(index.continuable)
.then([ target = index.target,
next = std::forward<N>(next) ](auto&&... args) {
// Assign the result to the target
*target = wrap(std::forward<decltype(args)>(args)...);
// Continue the asynchronous sequential traversal
next();
})
.done();
}
template <typename T>
void operator()(async_traverse_complete_tag, T&& pack) {
// Remove void result guard tags
auto cleaned =
map_pack(remapping::clean_void_results{}, std::forward<T>(pack));
// Call the final callback with the cleaned result
traits::unpack(std::move(cleaned), std::move(data_.callback));
}
};
} // namespace seq } // namespace seq
/// Finalizes the seq logic of a given composition /// Finalizes the seq logic of a given composition
template <> template <>
struct composition_finalizer<composition_strategy_seq_tag> { struct composition_finalizer<composition_strategy_seq_tag> {
/// TODO 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 Composition>
static auto finalize(Composition&& composition) {
return [composition = std::forward<Composition>(composition)](
auto&& callback) mutable {
auto index = seq::create_index_pack(composition);
auto result =
remapping::create_result_pack(std::forward<Composition>(composition));
// The data from which the visitor is constructed in-place
using data_t =
seq::sequential_dispatch_data<std::decay_t<decltype(callback)>,
std::decay_t<decltype(index)>,
std::decay_t<decltype(result)>>;
// The visitor type
using visitor_t = seq::sequential_dispatch_visitor<data_t>;
traverse_pack_async(async_traverse_in_place_tag<visitor_t>{},
data_t{std::forward<decltype(callback)>(callback),
std::move(index), std::move(result)});
};
}
}; };
} // namespace composition } // namespace composition
} // namespace detail } // namespace detail

View File

@ -202,16 +202,6 @@ public:
return *this; 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 // Merges both ownerships together
ownership operator|(ownership const& right) const noexcept { ownership operator|(ownership const& right) const noexcept {
return ownership(is_acquired() && right.is_acquired(), return ownership(is_acquired() && right.is_acquired(),
@ -224,10 +214,6 @@ public:
constexpr bool is_frozen() const noexcept { constexpr bool is_frozen() const noexcept {
return frozen_; 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 { void release() noexcept {
assert(is_acquired() && "Tried to release the ownership twice!"); assert(is_acquired() && "Tried to release the ownership twice!");