mirror of
https://github.com/Naios/continuable.git
synced 2025-12-07 17:26:47 +08:00
233 lines
7.9 KiB
C++
233 lines
7.9 KiB
C++
|
|
/*
|
|
|
|
/~` _ _ _|_. _ _ |_ | _
|
|
\_,(_)| | | || ||_|(_||_)|(/_
|
|
|
|
https://github.com/Naios/continuable
|
|
v3.0.0
|
|
|
|
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files(the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions :
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
**/
|
|
|
|
#ifndef CONTINUABLE_DETAIL_COMPOSITION_SEQ_HPP_INCLUDED
|
|
#define CONTINUABLE_DETAIL_COMPOSITION_SEQ_HPP_INCLUDED
|
|
|
|
#include <memory>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include <continuable/continuable-promise-base.hpp>
|
|
#include <continuable/continuable-traverse-async.hpp>
|
|
#include <continuable/detail/base.hpp>
|
|
#include <continuable/detail/composition_remapping.hpp>
|
|
#include <continuable/detail/traits.hpp>
|
|
|
|
namespace cti {
|
|
namespace detail {
|
|
namespace composition {
|
|
namespace seq {
|
|
/// Connects the left and the right continuable to a sequence
|
|
///
|
|
/// \note This is implemented in an eager way because we would not gain
|
|
/// any profit from chaining sequences lazily.
|
|
template <typename Left, typename Right>
|
|
auto sequential_connect(Left&& left, Right&& right) {
|
|
left.freeze(right.is_frozen());
|
|
right.freeze();
|
|
|
|
return std::forward<Left>(left).then([right = std::forward<Right>(right)](
|
|
auto&&... args) mutable {
|
|
return std::move(right).then([previous = std::make_tuple(
|
|
std::forward<decltype(args)>(args)...)](
|
|
auto&&... args) mutable {
|
|
return traits::merge(
|
|
std::move(previous),
|
|
std::make_tuple(std::forward<decltype(args)>(args)...));
|
|
});
|
|
});
|
|
}
|
|
|
|
/// 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(remapping::detail::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
|
|
: public 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.
|
|
remapping::relocate_index_pack(index_relocator{}, &data.index,
|
|
&data.result);
|
|
}
|
|
|
|
virtual ~sequential_dispatch_visitor() = default;
|
|
|
|
/// Returns the pack that should be traversed
|
|
auto& head() {
|
|
return data_.index;
|
|
}
|
|
|
|
template <typename Index, std::enable_if_t<is_indexed_continuable<
|
|
std::decay_t<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) mutable {
|
|
|
|
// 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 = all::flatten(
|
|
map_pack(remapping::clean_void_results{}, std::move(data_.result)));
|
|
|
|
// 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<composition_strategy_seq_tag> {
|
|
template <typename Composition>
|
|
static constexpr auto hint() {
|
|
return decltype(all::deduce_hint(std::declval<Composition>())){};
|
|
}
|
|
|
|
/// 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 detail
|
|
} // namespace cti
|
|
|
|
#endif // CONTINUABLE_DETAIL_COMPOSITION_SEQ_HPP_INCLUDED
|