make_all_promise, then_all

This commit is contained in:
2018-12-10 04:59:10 +07:00
parent e1af6f13ac
commit 77fa05c3f1
2 changed files with 169 additions and 0 deletions

View File

@@ -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));
}
}

View File

@@ -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([&not_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);
}
}
}