mirror of
https://github.com/Naios/continuable.git
synced 2025-12-08 01:36:46 +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/loop.hpp>
|
||||
#include <continuable/operations/split.hpp>
|
||||
|
||||
#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-operations-async.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-regression.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