mirror of
https://github.com/Naios/continuable.git
synced 2026-02-07 18:26:40 +08:00
Implement cti::split which makes it possible to resolve multiple
asynchronous control flows from a single promise.
This commit is contained in:
parent
41f3429c85
commit
daa2fdd686
@ -36,5 +36,6 @@
|
|||||||
|
|
||||||
#include <continuable/operations/async.hpp>
|
#include <continuable/operations/async.hpp>
|
||||||
#include <continuable/operations/loop.hpp>
|
#include <continuable/operations/loop.hpp>
|
||||||
|
#include <continuable/operations/split.hpp>
|
||||||
|
|
||||||
#endif // CONTINUABLE_OPERATIONS_HPP_INCLUDED
|
#endif // CONTINUABLE_OPERATIONS_HPP_INCLUDED
|
||||||
|
|||||||
107
include/continuable/detail/operations/split.hpp
Normal file
107
include/continuable/detail/operations/split.hpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
https://github.com/Naios/continuable
|
||||||
|
v4.0.0
|
||||||
|
|
||||||
|
Copyright(c) 2015 - 2019 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_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||||
|
#define CONTINUABLE_DETAIL_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
#include <continuable/continuable-base.hpp>
|
||||||
|
#include <continuable/continuable-traverse.hpp>
|
||||||
|
#include <continuable/continuable-types.hpp>
|
||||||
|
|
||||||
|
namespace cti {
|
||||||
|
namespace detail {
|
||||||
|
namespace operations {
|
||||||
|
template <typename First, typename... Promises>
|
||||||
|
class split_promise {
|
||||||
|
First first_;
|
||||||
|
std::tuple<Promises...> promises_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit split_promise(First first, Promises... promises)
|
||||||
|
: first_(std::move(first)), promises_(std::move(promises)...) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void operator()(Args... args) && {
|
||||||
|
traverse_pack(
|
||||||
|
[&](auto&& promise) mutable -> void {
|
||||||
|
if (promise) {
|
||||||
|
std::forward<decltype(promise)>(promise)(args...);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
std::move(promises_));
|
||||||
|
|
||||||
|
if (first_) {
|
||||||
|
std::move(first_)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(exception_arg_t tag, exception_t exception) && {
|
||||||
|
traverse_pack(
|
||||||
|
[&](auto&& promise) mutable -> void {
|
||||||
|
if (promise) {
|
||||||
|
std::forward<decltype(promise)>(promise)(tag, exception);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
std::move(promises_));
|
||||||
|
|
||||||
|
if (first_) {
|
||||||
|
std::move(first_)(tag, std::move(exception));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void set_value(Args... args) {
|
||||||
|
std::move (*this)(std::move(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_exception(exception_t error) {
|
||||||
|
std::move (*this)(exception_arg_t{}, std::move(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const noexcept {
|
||||||
|
bool is_valid = bool(first_);
|
||||||
|
traverse_pack(
|
||||||
|
[&](auto&& promise) mutable -> void {
|
||||||
|
if (!is_valid && bool(promise)) {
|
||||||
|
is_valid = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
promises_);
|
||||||
|
return is_valid;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace operations
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace cti
|
||||||
|
|
||||||
|
#endif // CONTINUABLE_DETAIL_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||||
96
include/continuable/operations/split.hpp
Normal file
96
include/continuable/operations/split.hpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
/~` _ _ _|_. _ _ |_ | _
|
||||||
|
\_,(_)| | | || ||_|(_||_)|(/_
|
||||||
|
|
||||||
|
https://github.com/Naios/continuable
|
||||||
|
v4.0.0
|
||||||
|
|
||||||
|
Copyright(c) 2015 - 2019 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_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||||
|
#define CONTINUABLE_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <continuable/detail/operations/split.hpp>
|
||||||
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
|
|
||||||
|
namespace cti {
|
||||||
|
/// \ingroup Operations
|
||||||
|
/// \{
|
||||||
|
|
||||||
|
/// Splits the asynchronous control flow and merges multiple promises/callbacks
|
||||||
|
/// together, which take the same types of arguments, into one.
|
||||||
|
///
|
||||||
|
/// The invocation order of all promises is undefined.
|
||||||
|
///
|
||||||
|
/// The split function is the opposite of the connection functions
|
||||||
|
/// like `when_all` because is can merge multiple waiters together rather than
|
||||||
|
/// joining those.
|
||||||
|
///
|
||||||
|
/// The split function can be used to resolve multiple waiters when resolving
|
||||||
|
/// a single promise.
|
||||||
|
/// ```cpp
|
||||||
|
/// class my_class {
|
||||||
|
/// cti::promise<> promise_;
|
||||||
|
///
|
||||||
|
/// public:
|
||||||
|
/// cti::continuable<> wait_for_sth() {
|
||||||
|
/// return [this](auto&& promise) mutable {
|
||||||
|
/// // Make sure accessing promise_ is done in a thread safe way!
|
||||||
|
/// promise_ = cti::split(std::move(promise_),
|
||||||
|
/// std::forward<decltype(promise)>(promise));
|
||||||
|
/// };
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// void resolve_all() {
|
||||||
|
/// // Resolves all waiting promises
|
||||||
|
/// promise_.set_value();
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// \note The split function only works if all asynchronous arguments are
|
||||||
|
/// copyable. All asynchronous arguments and exceptions will be passed
|
||||||
|
/// to all split promises.
|
||||||
|
///
|
||||||
|
/// \param promises The promises to split the control flow into,
|
||||||
|
/// can be single promises or heterogeneous or homogeneous
|
||||||
|
/// containers of promises (see traverse_pack for a description
|
||||||
|
/// of supported nested arguments).
|
||||||
|
///
|
||||||
|
/// \returns A new promise with the same asynchronous result types as
|
||||||
|
/// the given promises.
|
||||||
|
///
|
||||||
|
/// \since 4.0.0
|
||||||
|
///
|
||||||
|
template <typename... Promises>
|
||||||
|
auto split(Promises&&... promises) {
|
||||||
|
return detail::operations::split_promise<
|
||||||
|
detail::traits::unrefcv_t<Promises>...>(
|
||||||
|
std::forward<Promises>(promises)...);
|
||||||
|
}
|
||||||
|
/// \}
|
||||||
|
} // namespace cti
|
||||||
|
|
||||||
|
#endif // CONTINUABLE_OPERATIONS_SPLIT_HPP_INCLUDED
|
||||||
@ -59,6 +59,7 @@ set(TEST_SOURCES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-seq.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-connection-seq.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-operations-async.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-operations-async.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-operations-loop.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-operations-loop.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-operations-split.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-erasure.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-erasure.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-regression.cpp
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-regression.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-transforms.cpp)
|
${CMAKE_CURRENT_LIST_DIR}/multi/test-continuable-transforms.cpp)
|
||||||
|
|||||||
48
test/unit-test/multi/test-continuable-operations-split.cpp
Normal file
48
test/unit-test/multi/test-continuable-operations-split.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
Copyright(c) 2015 - 2019 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.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <test-continuable.hpp>
|
||||||
|
|
||||||
|
using namespace cti;
|
||||||
|
|
||||||
|
auto add(promise<>& all) {
|
||||||
|
return make_continuable<void>([&](auto&& promise) {
|
||||||
|
auto res = split(std::move(all), std::forward<decltype(promise)>(promise));
|
||||||
|
EXPECT_TRUE(res);
|
||||||
|
all = std::move(res);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(single_dimension_tests, operations_split) {
|
||||||
|
promise<> all;
|
||||||
|
bool resolved = false;
|
||||||
|
|
||||||
|
when_all(add(all), add(all), add(all)).then([&resolved] {
|
||||||
|
EXPECT_FALSE(resolved);
|
||||||
|
resolved = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(resolved);
|
||||||
|
all.set_value();
|
||||||
|
ASSERT_TRUE(resolved);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user