Merge pull request #14 from BlackMATov/dev

Dev
This commit is contained in:
BlackMat MATov
2018-12-17 16:51:57 +07:00
committed by GitHub
5 changed files with 225 additions and 53 deletions

View File

@@ -277,7 +277,7 @@ namespace jobber_hpp
tasks_.emplace_back(priority, std::move(task)); tasks_.emplace_back(priority, std::move(task));
std::push_heap(tasks_.begin(), tasks_.end()); std::push_heap(tasks_.begin(), tasks_.end());
++active_task_count_; ++active_task_count_;
cond_var_.notify_all(); cond_var_.notify_one();
} }
inline jobber::task_ptr jobber::pop_task_() noexcept { inline jobber::task_ptr jobber::pop_task_() noexcept {

View File

@@ -280,7 +280,8 @@ namespace promise_hpp
state_->attach( state_->attach(
next, next,
std::forward<ResolveF>(on_resolve), std::forward<ResolveF>(on_resolve),
std::forward<RejectF>(on_reject)); std::forward<RejectF>(on_reject),
true);
return next; return next;
} }
@@ -290,9 +291,15 @@ namespace promise_hpp
!is_promise<ResolveFR>::value, !is_promise<ResolveFR>::value,
promise<ResolveFR>> promise<ResolveFR>>
then(ResolveF&& on_resolve) { then(ResolveF&& on_resolve) {
return then( promise<ResolveFR> next;
state_->attach(
next,
std::forward<ResolveF>(on_resolve), std::forward<ResolveF>(on_resolve),
[](std::exception_ptr){}); [](std::exception_ptr e) -> ResolveFR {
std::rethrow_exception(e);
},
false);
return next;
} }
template < typename RejectF > template < typename RejectF >
@@ -422,19 +429,29 @@ namespace promise_hpp
template < typename U, typename ResolveF, typename RejectF > template < typename U, typename ResolveF, typename RejectF >
std::enable_if_t<std::is_void<U>::value, void> std::enable_if_t<std::is_void<U>::value, void>
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject) { attach(
promise<U>& next,
ResolveF&& on_resolve,
RejectF&& on_reject,
bool has_reject)
{
auto reject_h = [ auto reject_h = [
n = next, n = next,
f = std::forward<RejectF>(on_reject) f = std::forward<RejectF>(on_reject),
has_reject
](std::exception_ptr e) mutable { ](std::exception_ptr e) mutable {
if ( has_reject ) {
try { try {
invoke_hpp::invoke( invoke_hpp::invoke(
std::forward<decltype(f)>(f), std::forward<decltype(f)>(f),
e); e);
n.reject(e); n.resolve();
} catch (...) { } catch (...) {
n.reject(std::current_exception()); n.reject(std::current_exception());
} }
} else {
n.reject(e);
}
}; };
auto resolve_h = [ auto resolve_h = [
@@ -457,19 +474,29 @@ namespace promise_hpp
template < typename U, typename ResolveF, typename RejectF > template < typename U, typename ResolveF, typename RejectF >
std::enable_if_t<!std::is_void<U>::value, void> std::enable_if_t<!std::is_void<U>::value, void>
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject) { attach(
promise<U>& next,
ResolveF&& on_resolve,
RejectF&& on_reject,
bool has_reject)
{
auto reject_h = [ auto reject_h = [
n = next, n = next,
f = std::forward<RejectF>(on_reject) f = std::forward<RejectF>(on_reject),
has_reject
](std::exception_ptr e) mutable { ](std::exception_ptr e) mutable {
if ( has_reject ) {
try { try {
invoke_hpp::invoke( auto r = invoke_hpp::invoke(
std::forward<decltype(f)>(f), std::forward<decltype(f)>(f),
e); e);
n.reject(e); n.resolve(std::move(r));
} catch (...) { } catch (...) {
n.reject(std::current_exception()); n.reject(std::current_exception());
} }
} else {
n.reject(e);
}
}; };
auto resolve_h = [ auto resolve_h = [
@@ -683,7 +710,8 @@ namespace promise_hpp
state_->attach( state_->attach(
next, next,
std::forward<ResolveF>(on_resolve), std::forward<ResolveF>(on_resolve),
std::forward<RejectF>(on_reject)); std::forward<RejectF>(on_reject),
true);
return next; return next;
} }
@@ -693,9 +721,15 @@ namespace promise_hpp
!is_promise<ResolveFR>::value, !is_promise<ResolveFR>::value,
promise<ResolveFR>> promise<ResolveFR>>
then(ResolveF&& on_resolve) { then(ResolveF&& on_resolve) {
return then( promise<ResolveFR> next;
state_->attach(
next,
std::forward<ResolveF>(on_resolve), std::forward<ResolveF>(on_resolve),
[](std::exception_ptr){}); [](std::exception_ptr e) -> ResolveFR {
std::rethrow_exception(e);
},
false);
return next;
} }
template < typename RejectF > template < typename RejectF >
@@ -821,19 +855,29 @@ namespace promise_hpp
template < typename U, typename ResolveF, typename RejectF > template < typename U, typename ResolveF, typename RejectF >
std::enable_if_t<std::is_void<U>::value, void> std::enable_if_t<std::is_void<U>::value, void>
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject) { attach(
promise<U>& next,
ResolveF&& on_resolve,
RejectF&& on_reject,
bool has_reject)
{
auto reject_h = [ auto reject_h = [
n = next, n = next,
f = std::forward<RejectF>(on_reject) f = std::forward<RejectF>(on_reject),
has_reject
](std::exception_ptr e) mutable { ](std::exception_ptr e) mutable {
if ( has_reject ) {
try { try {
invoke_hpp::invoke( invoke_hpp::invoke(
std::forward<decltype(f)>(f), std::forward<decltype(f)>(f),
e); e);
n.reject(e); n.resolve();
} catch (...) { } catch (...) {
n.reject(std::current_exception()); n.reject(std::current_exception());
} }
} else {
n.reject(e);
}
}; };
auto resolve_h = [ auto resolve_h = [
@@ -855,19 +899,29 @@ namespace promise_hpp
template < typename U, typename ResolveF, typename RejectF > template < typename U, typename ResolveF, typename RejectF >
std::enable_if_t<!std::is_void<U>::value, void> std::enable_if_t<!std::is_void<U>::value, void>
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject) { attach(
promise<U>& next,
ResolveF&& on_resolve,
RejectF&& on_reject,
bool has_reject)
{
auto reject_h = [ auto reject_h = [
n = next, n = next,
f = std::forward<RejectF>(on_reject) f = std::forward<RejectF>(on_reject),
has_reject
](std::exception_ptr e) mutable { ](std::exception_ptr e) mutable {
if ( has_reject ) {
try { try {
invoke_hpp::invoke( auto r = invoke_hpp::invoke(
std::forward<decltype(f)>(f), std::forward<decltype(f)>(f),
e); e);
n.reject(e); n.resolve(std::move(r));
} catch (...) { } catch (...) {
n.reject(std::current_exception()); n.reject(std::current_exception());
} }
} else {
n.reject(e);
}
}; };
auto resolve_h = [ auto resolve_h = [

View File

@@ -179,16 +179,6 @@ TEST_CASE("promise") {
}); });
REQUIRE(check_42_int == 42); REQUIRE(check_42_int == 42);
} }
{
int check_42_int = 0;
auto p = pr::promise<int>();
p.resolve(42);
p.except([](std::exception_ptr){
}).then([&check_42_int](int value){
check_42_int = value;
});
REQUIRE(check_42_int == 42);
}
{ {
int check_84_int = 0; int check_84_int = 0;
bool check_void_call = false; bool check_void_call = false;
@@ -252,8 +242,9 @@ TEST_CASE("promise") {
int check_multi_fail = 0; int check_multi_fail = 0;
auto p = pr::promise<>(); auto p = pr::promise<>();
p.reject(std::logic_error("hello fail")); p.reject(std::logic_error("hello fail"));
p.except([&check_multi_fail](std::exception_ptr){ p.except([&check_multi_fail](std::exception_ptr e){
++check_multi_fail; ++check_multi_fail;
std::rethrow_exception(e);
}).except([&check_multi_fail](std::exception_ptr){ }).except([&check_multi_fail](std::exception_ptr){
++check_multi_fail; ++check_multi_fail;
}); });
@@ -316,6 +307,7 @@ TEST_CASE("promise") {
}); });
p.except([&call_fail_with_logic_error](std::exception_ptr e){ p.except([&call_fail_with_logic_error](std::exception_ptr e){
call_fail_with_logic_error = check_hello_fail_exception(e); call_fail_with_logic_error = check_hello_fail_exception(e);
return 0;
}); });
REQUIRE(call_fail_with_logic_error); REQUIRE(call_fail_with_logic_error);
} }
@@ -328,6 +320,7 @@ TEST_CASE("promise") {
}); });
p.except([&call_fail_with_logic_error](std::exception_ptr e){ p.except([&call_fail_with_logic_error](std::exception_ptr e){
call_fail_with_logic_error = check_hello_fail_exception(e); call_fail_with_logic_error = check_hello_fail_exception(e);
return 0;
}); });
REQUIRE(call_fail_with_logic_error); REQUIRE(call_fail_with_logic_error);
} }
@@ -356,6 +349,7 @@ TEST_CASE("promise") {
pr::make_rejected_promise<int>(std::logic_error("hello fail")) pr::make_rejected_promise<int>(std::logic_error("hello fail"))
.except([&call_fail_with_logic_error](std::exception_ptr e){ .except([&call_fail_with_logic_error](std::exception_ptr e){
call_fail_with_logic_error = check_hello_fail_exception(e); call_fail_with_logic_error = check_hello_fail_exception(e);
return 0;
}); });
REQUIRE(call_fail_with_logic_error); REQUIRE(call_fail_with_logic_error);
} }
@@ -703,7 +697,7 @@ TEST_CASE("promise") {
class o_t { class o_t {
public: public:
o_t() = delete; o_t() = delete;
o_t(int) {} o_t(int i) { (void)i; }
}; };
pr::promise<>() pr::promise<>()
@@ -759,7 +753,7 @@ TEST_CASE("promise") {
class o_t { class o_t {
public: public:
o_t() = delete; o_t() = delete;
o_t(int) {} o_t(int i) { (void)i; }
}; };
pr::promise<>() pr::promise<>()
@@ -988,6 +982,7 @@ TEST_CASE("promise") {
pr::make_resolved_promise(42)}; pr::make_resolved_promise(42)};
}).except([&call_fail_with_logic_error](std::exception_ptr e){ }).except([&call_fail_with_logic_error](std::exception_ptr e){
call_fail_with_logic_error = check_hello_fail_exception(e); call_fail_with_logic_error = check_hello_fail_exception(e);
return 0;
}); });
REQUIRE(call_fail_with_logic_error); REQUIRE(call_fail_with_logic_error);
} }
@@ -1044,6 +1039,7 @@ TEST_CASE("promise") {
pr::make_rejected_promise<float>(std::logic_error("hello fail"))); pr::make_rejected_promise<float>(std::logic_error("hello fail")));
}).except([&call_fail_with_logic_error](std::exception_ptr e){ }).except([&call_fail_with_logic_error](std::exception_ptr e){
call_fail_with_logic_error = check_hello_fail_exception(e); call_fail_with_logic_error = check_hello_fail_exception(e);
return std::make_tuple(0, 0.f);
}); });
REQUIRE(call_fail_with_logic_error); REQUIRE(call_fail_with_logic_error);
} }
@@ -1077,6 +1073,25 @@ TEST_CASE("get_and_wait") {
}}; }};
REQUIRE_NOTHROW(p.get()); REQUIRE_NOTHROW(p.get());
} }
{
const auto time_now = [](){
return std::chrono::high_resolution_clock::now();
};
auto p1 = pr::make_resolved_promise();
REQUIRE_NOTHROW(p1.wait());
REQUIRE(p1.wait_for(std::chrono::milliseconds(-1)) == pr::promise_wait_status::no_timeout);
REQUIRE(p1.wait_for(std::chrono::milliseconds(0)) == pr::promise_wait_status::no_timeout);
REQUIRE(p1.wait_until(time_now() + std::chrono::milliseconds(-1)) == pr::promise_wait_status::no_timeout);
REQUIRE(p1.wait_until(time_now() + std::chrono::milliseconds(0)) == pr::promise_wait_status::no_timeout);
auto p2 = pr::make_resolved_promise<int>(5);
REQUIRE_NOTHROW(p2.wait());
REQUIRE(p2.wait_for(std::chrono::milliseconds(-1)) == pr::promise_wait_status::no_timeout);
REQUIRE(p2.wait_for(std::chrono::milliseconds(0)) == pr::promise_wait_status::no_timeout);
REQUIRE(p2.wait_until(time_now() + std::chrono::milliseconds(-1)) == pr::promise_wait_status::no_timeout);
REQUIRE(p2.wait_until(time_now() + std::chrono::milliseconds(0)) == pr::promise_wait_status::no_timeout);
}
{ {
auto p = pr::promise<void>(); auto p = pr::promise<void>();
auto_thread t{[p]() mutable { auto_thread t{[p]() mutable {
@@ -1242,7 +1257,9 @@ TEST_CASE("promise_transformations") {
.then([](int)->int{ .then([](int)->int{
throw std::logic_error("hello fail"); throw std::logic_error("hello fail");
}) })
.except([](std::exception_ptr){}); .except([](std::exception_ptr){
return 0;
});
static_assert( static_assert(
std::is_same<decltype(p_v)::value_type, int>::value, std::is_same<decltype(p_v)::value_type, int>::value,
"unit test fail"); "unit test fail");
@@ -1253,6 +1270,7 @@ TEST_CASE("promise_transformations") {
throw std::logic_error("hello fail"); throw std::logic_error("hello fail");
}) })
.except([](std::exception_ptr){ .except([](std::exception_ptr){
return 0;
}); });
static_assert( static_assert(
std::is_same<decltype(p_v)::value_type, int>::value, std::is_same<decltype(p_v)::value_type, int>::value,
@@ -1260,3 +1278,76 @@ TEST_CASE("promise_transformations") {
} }
} }
} }
TEST_CASE("life_after_except") {
{
int check_42_int = 0;
bool call_fail_with_logic_error = false;
auto p = pr::make_rejected_promise<int>(std::logic_error("hello fail"));
p.then([](int v){
return v;
})
.except([&call_fail_with_logic_error](std::exception_ptr e){
call_fail_with_logic_error = check_hello_fail_exception(e);
return 42;
})
.then([&check_42_int](int value){
check_42_int = value;
});
REQUIRE(check_42_int == 42);
REQUIRE(call_fail_with_logic_error);
}
{
int check_42_int = 0;
bool call_fail_with_logic_error = false;
auto p = pr::make_rejected_promise<int>(std::logic_error("hello fail"));
p.then([](int v){
return v;
})
.except([&call_fail_with_logic_error](std::exception_ptr e) -> int {
call_fail_with_logic_error = check_hello_fail_exception(e);
std::rethrow_exception(e);
})
.except([&call_fail_with_logic_error](std::exception_ptr e){
call_fail_with_logic_error = call_fail_with_logic_error && check_hello_fail_exception(e);
return 42;
})
.then([&check_42_int](int value){
check_42_int = value;
});
REQUIRE(check_42_int == 42);
REQUIRE(call_fail_with_logic_error);
}
{
bool call_then_after_except = false;
bool call_fail_with_logic_error = false;
auto p = pr::make_rejected_promise(std::logic_error("hello fail"));
p.then([](){})
.except([&call_fail_with_logic_error](std::exception_ptr e){
call_fail_with_logic_error = check_hello_fail_exception(e);
})
.then([&call_then_after_except](){
call_then_after_except = true;
});
REQUIRE(call_then_after_except);
REQUIRE(call_fail_with_logic_error);
}
{
bool call_fail_with_logic_error = false;
bool call_then_after_multi_except = false;
auto p = pr::make_rejected_promise(std::logic_error("hello fail"));
p.then([](){})
.except([&call_fail_with_logic_error](std::exception_ptr e){
call_fail_with_logic_error = check_hello_fail_exception(e);
std::rethrow_exception(e);
})
.except([&call_fail_with_logic_error](std::exception_ptr e){
call_fail_with_logic_error = call_fail_with_logic_error && check_hello_fail_exception(e);
})
.then([&call_then_after_multi_except](){
call_then_after_multi_except = true;
});
REQUIRE(call_fail_with_logic_error);
REQUIRE(call_then_after_multi_except);
}
}

View File

@@ -65,6 +65,7 @@ namespace scheduler_hpp
, typename R = schedule_invoke_result_t<F, Args...> > , typename R = schedule_invoke_result_t<F, Args...> >
promise<R> schedule(scheduler_priority scheduler_priority, F&& f, Args&&... args); promise<R> schedule(scheduler_priority scheduler_priority, F&& f, Args&&... args);
bool process_one_task() noexcept;
scheduler_wait_status process_all_tasks() noexcept; scheduler_wait_status process_all_tasks() noexcept;
template < typename Rep, typename Period > template < typename Rep, typename Period >
@@ -157,6 +158,15 @@ namespace scheduler_hpp
return future; return future;
} }
inline bool scheduler::process_one_task() noexcept {
std::unique_lock<std::mutex> lock(tasks_mutex_);
if ( tasks_.empty() ) {
return false;
}
process_task_(std::move(lock));
return true;
}
inline scheduler_wait_status scheduler::process_all_tasks() noexcept { inline scheduler_wait_status scheduler::process_all_tasks() noexcept {
while ( !cancelled_ && active_task_count_ ) { while ( !cancelled_ && active_task_count_ ) {
std::unique_lock<std::mutex> lock(tasks_mutex_); std::unique_lock<std::mutex> lock(tasks_mutex_);
@@ -237,6 +247,7 @@ namespace scheduler_hpp
if ( task ) { if ( task ) {
lock.unlock(); lock.unlock();
task->run(); task->run();
lock.lock();
--active_task_count_; --active_task_count_;
cond_var_.notify_all(); cond_var_.notify_all();
} }

View File

@@ -46,6 +46,22 @@ TEST_CASE("scheduler") {
s.process_all_tasks(); s.process_all_tasks();
REQUIRE(counter == 3); REQUIRE(counter == 3);
} }
{
sd::scheduler s;
int counter = 0;
s.schedule([&counter](){ ++counter; });
s.schedule([&counter](){ ++counter; });
s.schedule([&counter](){ ++counter; });
REQUIRE(counter == 0);
REQUIRE(s.process_one_task());
REQUIRE(counter == 1);
REQUIRE(s.process_one_task());
REQUIRE(counter == 2);
REQUIRE(s.process_one_task());
REQUIRE(counter == 3);
REQUIRE_FALSE(s.process_one_task());
REQUIRE(counter == 3);
}
{ {
sd::scheduler s; sd::scheduler s;
int counter = 0; int counter = 0;