From 3bc274228c91dd5a1e3b4314d9e6b6be1daa90ed Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 14 Dec 2018 02:35:46 +0700 Subject: [PATCH] fix except exception safety --- promise.hpp | 109 ++++++++++++++++++++-------------------------- promise_tests.cpp | 89 ++++++++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 62 deletions(-) diff --git a/promise.hpp b/promise.hpp index 79a5663..85931a8 100644 --- a/promise.hpp +++ b/promise.hpp @@ -178,16 +178,16 @@ namespace promise_hpp then([ n = next, f = std::forward(on_resolve) - ](const T& v) mutable { + ](auto&& v) mutable { auto np = invoke_hpp::invoke( std::forward(f), - v); - np.then([n]() mutable { + std::forward(v)); + std::move(np).then([n]() mutable { n.resolve(); - }, [n](std::exception_ptr e) mutable { + }).except([n](std::exception_ptr e) mutable { n.reject(e); }); - }, [n = next](std::exception_ptr e) mutable { + }).except([n = next](std::exception_ptr e) mutable { n.reject(e); }); @@ -205,16 +205,16 @@ namespace promise_hpp then([ n = next, f = std::forward(on_resolve) - ](const T& v) mutable { + ](auto&& v) mutable { auto np = invoke_hpp::invoke( std::forward(f), - v); - np.then([n](const typename ResolveFR::value_type& nv) mutable { - n.resolve(nv); - }, [n](std::exception_ptr e) mutable { + std::forward(v)); + std::move(np).then([n](auto&& nv) mutable { + n.resolve(std::forward(nv)); + }).except([n](std::exception_ptr e) mutable { n.reject(e); }); - }, [n = next](std::exception_ptr e) mutable { + }).except([n = next](std::exception_ptr e) mutable { n.reject(e); }); @@ -225,10 +225,10 @@ namespace promise_hpp auto then_all(ResolveF&& on_resolve) { return then([ f = std::forward(on_resolve) - ](const T& v) mutable { + ](auto&& v) mutable { auto r = invoke_hpp::invoke( std::forward(f), - v); + std::forward(v)); return make_all_promise(std::move(r)); }); } @@ -237,10 +237,10 @@ namespace promise_hpp auto then_any(ResolveF&& on_resolve) { return then([ f = std::forward(on_resolve) - ](const T& v) mutable { + ](auto&& v) mutable { auto r = invoke_hpp::invoke( std::forward(f), - v); + std::forward(v)); return make_any_promise(std::move(r)); }); } @@ -274,14 +274,13 @@ namespace promise_hpp template < typename RejectF > promise except(RejectF&& on_reject) { return then( - [](const T& value) { return value; }, + [](auto&& v) { return std::forward(v); }, std::forward(on_reject)); } template < typename U > bool resolve(U&& value) { - return state_->resolve( - std::forward(value)); + return state_->resolve(std::forward(value)); } bool reject(std::exception_ptr e) noexcept { @@ -391,10 +390,10 @@ namespace promise_hpp template < typename U, typename ResolveF, typename RejectF > std::enable_if_t::value, void> - attach(promise& next, ResolveF&& resolve, RejectF&& reject) { + attach(promise& next, ResolveF&& on_resolve, RejectF&& on_reject) { auto reject_h = [ n = next, - f = std::forward(reject) + f = std::forward(on_reject) ](std::exception_ptr e) mutable { try { invoke_hpp::invoke( @@ -408,18 +407,15 @@ namespace promise_hpp auto resolve_h = [ n = next, - f = std::forward(resolve), - j = reject_h - ](const T& v) mutable { + f = std::forward(on_resolve) + ](auto&& v) mutable { try { invoke_hpp::invoke( std::forward(f), - v); + std::forward(v)); n.resolve(); } catch (...) { - invoke_hpp::invoke( - std::move(j), - std::current_exception()); + n.reject(std::current_exception()); } }; @@ -429,10 +425,10 @@ namespace promise_hpp template < typename U, typename ResolveF, typename RejectF > std::enable_if_t::value, void> - attach(promise& next, ResolveF&& resolve, RejectF&& reject) { + attach(promise& next, ResolveF&& on_resolve, RejectF&& on_reject) { auto reject_h = [ n = next, - f = std::forward(reject) + f = std::forward(on_reject) ](std::exception_ptr e) mutable { try { invoke_hpp::invoke( @@ -446,18 +442,15 @@ namespace promise_hpp auto resolve_h = [ n = next, - f = std::forward(resolve), - j = reject_h - ](const T& v) mutable { + f = std::forward(on_resolve) + ](auto&& v) mutable { try { auto r = invoke_hpp::invoke( std::forward(f), - v); + std::forward(v)); n.resolve(std::move(r)); } catch (...) { - invoke_hpp::invoke( - std::move(j), - std::current_exception()); + n.reject(std::current_exception()); } }; @@ -576,12 +569,12 @@ namespace promise_hpp ]() mutable { auto np = invoke_hpp::invoke( std::forward(f)); - np.then([n]() mutable { + std::move(np).then([n]() mutable { n.resolve(); - }, [n](std::exception_ptr e) mutable { + }).except([n](std::exception_ptr e) mutable { n.reject(e); }); - }, [n = next](std::exception_ptr e) mutable { + }).except([n = next](std::exception_ptr e) mutable { n.reject(e); }); @@ -602,12 +595,12 @@ namespace promise_hpp ]() mutable { auto np = invoke_hpp::invoke( std::forward(f)); - np.then([n](const typename ResolveFR::value_type& nv) mutable { - n.resolve(nv); - }, [n](std::exception_ptr e) mutable { + std::move(np).then([n](auto&& nv) mutable { + n.resolve(std::forward(nv)); + }).except([n](std::exception_ptr e) mutable { n.reject(e); }); - }, [n = next](std::exception_ptr e) mutable { + }).except([n = next](std::exception_ptr e) mutable { n.reject(e); }); @@ -777,10 +770,10 @@ namespace promise_hpp template < typename U, typename ResolveF, typename RejectF > std::enable_if_t::value, void> - attach(promise& next, ResolveF&& resolve, RejectF&& reject) { + attach(promise& next, ResolveF&& on_resolve, RejectF&& on_reject) { auto reject_h = [ n = next, - f = std::forward(reject) + f = std::forward(on_reject) ](std::exception_ptr e) mutable { try { invoke_hpp::invoke( @@ -794,17 +787,14 @@ namespace promise_hpp auto resolve_h = [ n = next, - f = std::forward(resolve), - j = reject_h + f = std::forward(on_resolve) ]() mutable { try { invoke_hpp::invoke( std::forward(f)); n.resolve(); } catch (...) { - invoke_hpp::invoke( - std::move(j), - std::current_exception()); + n.reject(std::current_exception()); } }; @@ -814,10 +804,10 @@ namespace promise_hpp template < typename U, typename ResolveF, typename RejectF > std::enable_if_t::value, void> - attach(promise& next, ResolveF&& resolve, RejectF&& reject) { + attach(promise& next, ResolveF&& on_resolve, RejectF&& on_reject) { auto reject_h = [ n = next, - f = std::forward(reject) + f = std::forward(on_reject) ](std::exception_ptr e) mutable { try { invoke_hpp::invoke( @@ -831,17 +821,14 @@ namespace promise_hpp auto resolve_h = [ n = next, - f = std::forward(resolve), - j = reject_h + f = std::forward(on_resolve) ]() mutable { try { auto r = invoke_hpp::invoke( std::forward(f)); n.resolve(std::move(r)); } catch (...) { - invoke_hpp::invoke( - std::move(j), - std::current_exception()); + n.reject(std::current_exception()); } }; @@ -1020,11 +1007,11 @@ namespace promise_hpp context, resolver, result_index - ](const child_promise_value_t& v) mutable { - if ( context->apply_result(result_index, v) ) { + ](auto&& v) mutable { + if ( context->apply_result(result_index, std::forward(v)) ) { resolver(std::move(context->results)); } - }, rejector); + }).except(rejector); } }); } @@ -1051,7 +1038,7 @@ namespace promise_hpp return make_promise([begin, end](auto&& resolver, auto&& rejector){ for ( auto iter = begin; iter != end; ++iter ) { - (*iter).then(resolver, rejector); + (*iter).then(resolver).except(rejector); } }); } diff --git a/promise_tests.cpp b/promise_tests.cpp index e53714d..80aa228 100644 --- a/promise_tests.cpp +++ b/promise_tests.cpp @@ -404,7 +404,7 @@ TEST_CASE("promise") { }, [](std::exception_ptr){ throw std::logic_error("hello fail2"); }).except([&call_fail_with_logic_error](std::exception_ptr e){ - call_fail_with_logic_error = check_hello_fail2_exception(e); + call_fail_with_logic_error = check_hello_fail_exception(e); }); REQUIRE(not_call_then_on_reject); REQUIRE(call_fail_with_logic_error); @@ -768,6 +768,27 @@ TEST_CASE("promise") { REQUIRE(not_call_then_on_reject); REQUIRE(call_fail_with_logic_error); } + { + auto p1 = pr::promise(); + auto p2 = pr::promise(); + + int call_then_count = 0; + int call_except_count = 0; + pr::make_all_promise(std::vector>{p1, p2}) + .then([&call_then_count](const std::vector& c){ + (void)c; + ++call_then_count; + }, [&call_except_count](std::exception_ptr){ + ++call_except_count; + }); + + p1.resolve(1); + REQUIRE(call_then_count == 0); + REQUIRE(call_except_count == 0); + p2.reject(std::logic_error("hello fail")); + REQUIRE(call_then_count == 0); + REQUIRE(call_except_count == 1); + } } SECTION("make_any_promise_fail") { REQUIRE_THROWS_AS( @@ -978,3 +999,69 @@ TEST_CASE("get_and_wait") { } } } + +TEST_CASE("promise_transformations") { + { + auto p_v = pr::promise() + .then([](int){}); + static_assert( + std::is_same::value, + "unit test fail"); + + auto p_f = pr::promise() + .then([](int){return 1.f;}); + static_assert( + std::is_same::value, + "unit test fail"); + + auto p_d = pr::promise() + .then([](int){return 1.f;}) + .then([](float){return 1.0;}); + static_assert( + std::is_same::value, + "unit test fail"); + } + { + auto p_v = pr::promise() + .then([](){}); + static_assert( + std::is_same::value, + "unit test fail"); + + auto p_f = pr::promise() + .then([](){return 1.f;}); + static_assert( + std::is_same::value, + "unit test fail"); + + auto p_d = pr::promise() + .then([](){return 1.f;}) + .then([](float){return 1.0;}); + static_assert( + std::is_same::value, + "unit test fail"); + } + SECTION("after_except") { + { + auto p_v = pr::promise() + .then([](int)->int{ + throw std::logic_error("hello fail"); + }) + .except([](std::exception_ptr){}); + static_assert( + std::is_same::value, + "unit test fail"); + } + { + auto p_v = pr::promise() + .then([](int)->int{ + throw std::logic_error("hello fail"); + }) + .except([](std::exception_ptr){ + }); + static_assert( + std::is_same::value, + "unit test fail"); + } + } +}