mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 16:56:44 +08:00
First work on implementing deep sequential compositions
This commit is contained in:
parent
b1d7a76c8f
commit
fd858a7ed7
@ -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_;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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!");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user