mirror of
https://github.com/Naios/continuable.git
synced 2026-02-06 17:59:47 +08:00
Add the sequence operator feature
This commit is contained in:
parent
cd265f991b
commit
22d13997df
@ -265,10 +265,10 @@ Although the library has progressed very far there are still some candies missin
|
||||
```
|
||||
|
||||
|
||||
- [ ] The **sequential/pipe operator** which invokes continuables sequentially and calls the callback with all results:
|
||||
- [x] The **sequential operator** which invokes continuables sequentially and calls the callback with all results:
|
||||
|
||||
```c++
|
||||
(http_request("github.com") | http_request("travis-ci.org") | http_request("atom.io"))
|
||||
(http_request("github.com") >> http_request("travis-ci.org") >> http_request("atom.io"))
|
||||
.then([](std::string github, std::string travis, std::string atom) {
|
||||
// The requests are done sequentially and the callback is called
|
||||
// with the response of github, travis and atom as soon as atom has responded.
|
||||
|
||||
@ -14,8 +14,7 @@ if (PLATFORM EQUAL 64)
|
||||
add_definitions("-D_WIN64")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /MP")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /MP /bigobj")
|
||||
|
||||
if (TESTS_NO_EXCEPTIONS)
|
||||
add_definitions(-D_HAS_EXCEPTIONS=0)
|
||||
|
||||
@ -422,6 +422,13 @@ inline auto or_folding() {
|
||||
std::forward<decltype(right)>(right);
|
||||
};
|
||||
}
|
||||
/// Returns a folding function using operator `>>`.
|
||||
inline auto seq_folding() {
|
||||
return [](auto&& left, auto&& right) {
|
||||
return std::forward<decltype(left)>(left) >>
|
||||
std::forward<decltype(right)>(right);
|
||||
};
|
||||
}
|
||||
|
||||
/// Deduces to a std::false_type
|
||||
template <typename T>
|
||||
@ -927,7 +934,7 @@ auto wrap_continuation(Continuation&& continuation) {
|
||||
} // end namespace base
|
||||
|
||||
/// The namespace `compose` offers methods to chain continuations together
|
||||
/// with `all` and `any` logic.
|
||||
/// with `all`, `any` or `seq` logic.
|
||||
namespace compose {
|
||||
struct strategy_all_tag {};
|
||||
struct strategy_any_tag {};
|
||||
@ -1262,6 +1269,24 @@ auto finalize_composition(strategy_any_tag, Composition&& composition) {
|
||||
},
|
||||
signature);
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
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 util::merge(
|
||||
std::move(previous),
|
||||
std::make_tuple(std::forward<decltype(args)>(args)...));
|
||||
});
|
||||
});
|
||||
}
|
||||
} // end namespace compose
|
||||
|
||||
/// Provides helper functions to transform continuations to other types
|
||||
@ -1405,6 +1430,13 @@ public:
|
||||
std::move(*this), std::move(right));
|
||||
}
|
||||
|
||||
template <typename OData, typename OAnnotation>
|
||||
auto operator>>(continuable_base<OData, OAnnotation>&& right) && {
|
||||
right.assert_owning();
|
||||
return detail::compose::sequential_connect(std::move(*this),
|
||||
std::move(right));
|
||||
}
|
||||
|
||||
auto futurize() && {
|
||||
return detail::transforms::as_future(std::move(*this).materialize());
|
||||
}
|
||||
@ -1573,6 +1605,22 @@ auto any_of(Continuables&&... continuables) {
|
||||
std::forward<Continuables>(continuables)...);
|
||||
}
|
||||
|
||||
/// Connects the given continuables with a *seq* logic.
|
||||
///
|
||||
/// \param continuables The continuable_base objects to connect.
|
||||
/// Requires at least 2 objects to connect.
|
||||
///
|
||||
/// \see continuable_base::operator>> for details.
|
||||
///
|
||||
/// \since version 1.0.0
|
||||
template <typename... Continuables>
|
||||
auto seq_of(Continuables&&... continuables) {
|
||||
static_assert(sizeof...(continuables) >= 2,
|
||||
"Requires at least 2 continuables!");
|
||||
return detail::util::fold(detail::util::seq_folding(),
|
||||
std::forward<Continuables>(continuables)...);
|
||||
}
|
||||
|
||||
template <template <typename> class CallbackWrapper,
|
||||
template <typename> class ContinuationWrapper, typename... Args>
|
||||
using continuable_erasure_of_t =
|
||||
|
||||
@ -103,4 +103,45 @@ TYPED_TEST(single_dimension_tests, is_logical_or_connectable) {
|
||||
EXPECT_ASYNC_RESULT(std::move(composed));
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(single_dimension_tests, is_logical_seq_connectable) {
|
||||
|
||||
{
|
||||
auto chain = this->supply() >> this->supply();
|
||||
EXPECT_ASYNC_RESULT(std::move(chain));
|
||||
}
|
||||
|
||||
{
|
||||
auto chain = this->supply(1) >> this->supply(2);
|
||||
EXPECT_ASYNC_RESULT(std::move(chain), 1, 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto chain = this->supply(1, 2) >> this->supply(3, 4);
|
||||
EXPECT_ASYNC_RESULT(std::move(chain), 1, 2, 3, 4);
|
||||
}
|
||||
|
||||
{
|
||||
auto chain = this->supply(tag1{}, tag2{}) >> this->supply(tag1{}, tag2{});
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), tag1, tag2, tag1, tag2);
|
||||
}
|
||||
|
||||
{
|
||||
auto chain = this->supply(tag1{}, tag2{}, tag3{}) >>
|
||||
this->supply(tag1{}, tag2{}, tag3{});
|
||||
ASSERT_ASYNC_TYPES(std::move(chain), tag1, tag2, tag3, tag1, tag2, tag3);
|
||||
}
|
||||
|
||||
{
|
||||
// Check the evaluation order
|
||||
unsigned i = 0;
|
||||
auto composed =
|
||||
make_step(this, i, 0) >> make_step(this, i, 1) >> make_step(this, i, 2);
|
||||
EXPECT_ASYNC_RESULT(std::move(composed));
|
||||
}
|
||||
|
||||
{
|
||||
auto chain = this->supply('a') >> this->supply('b') >> this->supply('c');
|
||||
EXPECT_ASYNC_RESULT(std::move(chain), 'a', 'b', 'c');
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,22 +134,34 @@ template <typename Provider> struct provide_continuation_and_right {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Provider> struct provide_continuation_seq_right {
|
||||
Provider provider_;
|
||||
|
||||
template <typename... Args, typename... Hint, typename T>
|
||||
auto make(identity<Args...> args, identity<Hint...> hint, T&& callback) {
|
||||
return provider_.make(args, hint, std::forward<T>(callback)) >>
|
||||
empty_continuable();
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
// Feel free to uncomment more tests, however this will increase the
|
||||
// build time significantly.
|
||||
using single_types = ::testing::Types<
|
||||
provide_copyable,
|
||||
provide_unique,
|
||||
provide_copyable_erasure,
|
||||
// provide_unique,
|
||||
// provide_copyable_erasure,
|
||||
provide_unique_erasure,
|
||||
// Some instantiations out commented for compilation speed reasons
|
||||
// provide_continuation_and_left<provide_copyable>,
|
||||
provide_continuation_and_left<provide_unique>,
|
||||
// provide_continuation_and_left<provide_copyable_erasure>,
|
||||
// provide_continuation_and_left<provide_unique_erasure>,
|
||||
// Some instantiations out commented for compilation speed reasons
|
||||
// provide_continuation_and_left<provide_copyable_erasure>,
|
||||
// provide_continuation_and_left<provide_unique_erasure>,
|
||||
// provide_continuation_and_right<provide_copyable>,
|
||||
provide_continuation_and_right<provide_unique>
|
||||
provide_continuation_and_right<provide_unique>,
|
||||
// provide_continuation_and_left<provide_copyable_erasure>,
|
||||
// provide_continuation_and_left<provide_unique_erasure>
|
||||
provide_continuation_seq_right<provide_unique>
|
||||
>;
|
||||
// clang-format on
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user