mirror of
https://github.com/BlackMATov/promise.hpp.git
synced 2025-12-16 14:11:21 +07:00
make_all_promise, then_all
This commit is contained in:
86
promise.hpp
86
promise.hpp
@@ -5,9 +5,11 @@
|
|||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <iterator>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -185,6 +187,18 @@ namespace promise_hpp
|
|||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename ResolveF >
|
||||||
|
auto then_all(ResolveF&& on_resolve) {
|
||||||
|
return then([
|
||||||
|
f = std::forward<ResolveF>(on_resolve)
|
||||||
|
](const T& v) mutable {
|
||||||
|
auto r = invoke_hpp::invoke(
|
||||||
|
std::forward<decltype(f)>(f),
|
||||||
|
v);
|
||||||
|
return make_all_promise(std::move(r));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
template < typename ResolveF
|
template < typename ResolveF
|
||||||
, typename ResolveFR = invoke_hpp::invoke_result_t<ResolveF,T> >
|
, typename ResolveFR = invoke_hpp::invoke_result_t<ResolveF,T> >
|
||||||
std::enable_if_t<
|
std::enable_if_t<
|
||||||
@@ -458,6 +472,17 @@ namespace promise_hpp
|
|||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename ResolveF >
|
||||||
|
auto then_all(ResolveF&& on_resolve) {
|
||||||
|
return then([
|
||||||
|
f = std::forward<ResolveF>(on_resolve)
|
||||||
|
]() mutable {
|
||||||
|
auto r = invoke_hpp::invoke(
|
||||||
|
std::forward<decltype(f)>(f));
|
||||||
|
return make_all_promise(std::move(r));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
template < typename ResolveF
|
template < typename ResolveF
|
||||||
, typename ResolveFR = invoke_hpp::invoke_result_t<ResolveF> >
|
, typename ResolveFR = invoke_hpp::invoke_result_t<ResolveF> >
|
||||||
std::enable_if_t<
|
std::enable_if_t<
|
||||||
@@ -689,6 +714,10 @@ namespace promise_hpp
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// make_resolved_promise
|
||||||
|
//
|
||||||
|
|
||||||
inline promise<void> make_resolved_promise() {
|
inline promise<void> make_resolved_promise() {
|
||||||
promise<void> result;
|
promise<void> result;
|
||||||
result.resolve();
|
result.resolve();
|
||||||
@@ -702,6 +731,10 @@ namespace promise_hpp
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// make_rejected_promise
|
||||||
|
//
|
||||||
|
|
||||||
template < typename E >
|
template < typename E >
|
||||||
promise<void> make_rejected_promise(E&& e) {
|
promise<void> make_rejected_promise(E&& e) {
|
||||||
promise<void> result;
|
promise<void> result;
|
||||||
@@ -715,4 +748,57 @@ namespace promise_hpp
|
|||||||
result.reject(std::forward<E>(e));
|
result.reject(std::forward<E>(e));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// make_all_promise
|
||||||
|
//
|
||||||
|
|
||||||
|
template < typename Iter >
|
||||||
|
auto make_all_promise(Iter begin, Iter end) {
|
||||||
|
using child_promise_t = typename Iter::value_type;
|
||||||
|
using child_promise_value_t = typename child_promise_t::value_type;
|
||||||
|
using promise_out_container_t = std::vector<child_promise_value_t>;
|
||||||
|
|
||||||
|
struct context_t {
|
||||||
|
promise_out_container_t results;
|
||||||
|
std::atomic_size_t counter = ATOMIC_VAR_INIT(0);
|
||||||
|
|
||||||
|
context_t(std::size_t count)
|
||||||
|
: results(count) {}
|
||||||
|
|
||||||
|
bool apply_result(std::size_t index, const child_promise_value_t& value) {
|
||||||
|
results[index] = value;
|
||||||
|
return ++counter == results.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( begin == end ) {
|
||||||
|
return make_resolved_promise(promise_out_container_t());
|
||||||
|
}
|
||||||
|
|
||||||
|
return make_promise<promise_out_container_t>([begin, end](auto&& resolver, auto&& rejector){
|
||||||
|
std::size_t result_index = 0;
|
||||||
|
auto context = std::make_shared<context_t>(std::distance(begin, end));
|
||||||
|
for ( auto iter = begin; iter != end; ++iter, ++result_index ) {
|
||||||
|
(*iter).then([
|
||||||
|
context,
|
||||||
|
resolver,
|
||||||
|
result_index
|
||||||
|
](const child_promise_value_t& v) mutable {
|
||||||
|
if ( context->apply_result(result_index, v) ) {
|
||||||
|
resolver(std::move(context->results));
|
||||||
|
}
|
||||||
|
}).fail([rejector](std::exception_ptr e) mutable {
|
||||||
|
rejector(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Container >
|
||||||
|
auto make_all_promise(Container&& container) {
|
||||||
|
return make_all_promise(
|
||||||
|
std::begin(container),
|
||||||
|
std::end(container));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
83
tests.cpp
83
tests.cpp
@@ -573,4 +573,87 @@ TEST_CASE("promise") {
|
|||||||
REQUIRE(call_fail_with_logic_error);
|
REQUIRE(call_fail_with_logic_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SECTION("make_all_promise") {
|
||||||
|
{
|
||||||
|
bool all_is_ok = false;
|
||||||
|
pr::make_all_promise(std::vector<pr::promise<int>>())
|
||||||
|
.then([&all_is_ok](const std::vector<int>& c){
|
||||||
|
all_is_ok = c.empty();
|
||||||
|
});
|
||||||
|
REQUIRE(all_is_ok);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
bool all_is_ok = false;
|
||||||
|
auto p = pr::make_all_promise(std::vector<pr::promise<int>>{
|
||||||
|
pr::make_resolved_promise(32),
|
||||||
|
pr::make_resolved_promise(10)
|
||||||
|
}).then([&all_is_ok](const std::vector<int>& c){
|
||||||
|
all_is_ok = (2 == c.size())
|
||||||
|
&& c[0] == 32
|
||||||
|
&& c[1] == 10;
|
||||||
|
});
|
||||||
|
REQUIRE(all_is_ok);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto p1 = pr::promise<int>();
|
||||||
|
auto p2 = pr::promise<int>();
|
||||||
|
|
||||||
|
int call_then_only_once = 0;
|
||||||
|
pr::make_all_promise(std::vector<pr::promise<int>>{p1, p2})
|
||||||
|
.then([&call_then_only_once](const std::vector<int>& c){
|
||||||
|
++call_then_only_once;
|
||||||
|
});
|
||||||
|
|
||||||
|
p1.resolve(1);
|
||||||
|
p2.resolve(2);
|
||||||
|
|
||||||
|
REQUIRE(call_then_only_once == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("make_all_promise_fail") {
|
||||||
|
{
|
||||||
|
bool call_fail_with_logic_error = false;
|
||||||
|
bool not_call_then_on_reject = true;
|
||||||
|
auto p = pr::make_all_promise(std::vector<pr::promise<int>>{
|
||||||
|
pr::make_rejected_promise<int>(std::logic_error("hello fail")),
|
||||||
|
pr::make_resolved_promise(10)
|
||||||
|
}).then([¬_call_then_on_reject](const std::vector<int>& c){
|
||||||
|
(void)c;
|
||||||
|
not_call_then_on_reject = false;
|
||||||
|
}).fail([&call_fail_with_logic_error](std::exception_ptr e){
|
||||||
|
call_fail_with_logic_error = check_hello_fail_exception(e);
|
||||||
|
});
|
||||||
|
REQUIRE(not_call_then_on_reject);
|
||||||
|
REQUIRE(call_fail_with_logic_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("then_all") {
|
||||||
|
{
|
||||||
|
int check_42_int = 0;
|
||||||
|
pr::make_resolved_promise()
|
||||||
|
.then_all([](){
|
||||||
|
return std::vector<pr::promise<int>>{
|
||||||
|
pr::make_resolved_promise(32),
|
||||||
|
pr::make_resolved_promise(10)};
|
||||||
|
}).then([&check_42_int](const std::vector<int>& v){
|
||||||
|
check_42_int = std::accumulate(v.begin(), v.end(), 0);
|
||||||
|
});
|
||||||
|
REQUIRE(check_42_int == 42);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int check_42_int = 0;
|
||||||
|
int check_42_int2 = 0;
|
||||||
|
pr::make_resolved_promise(42)
|
||||||
|
.then_all([&check_42_int](int v){
|
||||||
|
check_42_int = v;
|
||||||
|
return std::vector<pr::promise<int>>{
|
||||||
|
pr::make_resolved_promise(32),
|
||||||
|
pr::make_resolved_promise(10)};
|
||||||
|
}).then([&check_42_int2](const std::vector<int>& v){
|
||||||
|
check_42_int2 = std::accumulate(v.begin(), v.end(), 0);
|
||||||
|
});
|
||||||
|
REQUIRE(check_42_int == 42);
|
||||||
|
REQUIRE(check_42_int2 == 42);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user