mirror of
https://github.com/BlackMATov/promise.hpp.git
synced 2025-12-15 04:25:28 +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 <mutex>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
@@ -185,6 +187,18 @@ namespace promise_hpp
|
||||
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
|
||||
, typename ResolveFR = invoke_hpp::invoke_result_t<ResolveF,T> >
|
||||
std::enable_if_t<
|
||||
@@ -458,6 +472,17 @@ namespace promise_hpp
|
||||
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
|
||||
, typename ResolveFR = invoke_hpp::invoke_result_t<ResolveF> >
|
||||
std::enable_if_t<
|
||||
@@ -689,6 +714,10 @@ namespace promise_hpp
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// make_resolved_promise
|
||||
//
|
||||
|
||||
inline promise<void> make_resolved_promise() {
|
||||
promise<void> result;
|
||||
result.resolve();
|
||||
@@ -702,6 +731,10 @@ namespace promise_hpp
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// make_rejected_promise
|
||||
//
|
||||
|
||||
template < typename E >
|
||||
promise<void> make_rejected_promise(E&& e) {
|
||||
promise<void> result;
|
||||
@@ -715,4 +748,57 @@ namespace promise_hpp
|
||||
result.reject(std::forward<E>(e));
|
||||
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);
|
||||
}
|
||||
}
|
||||
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