diff options
author | Determinant <[email protected]> | 2018-02-04 15:16:58 -0500 |
---|---|---|
committer | Determinant <[email protected]> | 2018-02-04 15:16:58 -0500 |
commit | ac3a0030123a350bff490d69a4786954a9003686 (patch) | |
tree | 54d85b015739cef725a8eaec19d4678fa44f57d4 | |
parent | 7a95221366f1a2aef9414ae7484242726bb812a1 (diff) |
add `race`
-rw-r--r-- | README.rst | 67 | ||||
-rw-r--r-- | promise.hpp | 74 | ||||
-rw-r--r-- | test.cpp | 17 | ||||
-rw-r--r-- | test_ref.txt | 4 |
4 files changed, 127 insertions, 35 deletions
@@ -19,7 +19,7 @@ API .. code-block:: cpp - typename<typename Func> promise_t(Func callback); + typename<typename Func> promise_t::promise_t(Func callback); Create a new promise object, the ``callback(promise_t pm)`` is invoked immediately after the object is constructed, so usually the user registers @@ -28,44 +28,85 @@ immediately after the object is constructed, so usually the user registers .. code-block:: cpp - template<typename T> resolve(T result) const; + template<typename T> promise_t::resolve(T result) const; Resolve the promise with value ``result``. This may trigger the other promises waiting for the current promise recursively. When a promise is triggered, the -registered ``on_fulfilled()`` function will be invoked using ``result`` as the argument. +registered ``on_fulfilled()`` function will be invoked with ``result`` as the +argument. .. code-block:: cpp - template<typename T> reject(T reason) const; + template<typename T> promise_t::reject(T reason) const; -Reject the promise with value ``result``. This may reject the other promises +Reject the promise with value ``reason``. This may reject the other promises waiting for the current promise recursively. When a promise is rejected, the -registered ``on_rejected()`` function will be invoked using ``reason`` as the argument. +registered ``on_rejected()`` function will be invoked with ``reason`` as the +argument. + +.. code-block:: cpp + + promise_t::resolve() const; + +Resolve the promise without empty result. This may trigger the other promises +waiting for the current promise recursively. When a promise is triggered, the +registered ``on_fulfilled()`` function should be expecting no argument, +otherwise a type mismatch is thrown. + +.. code-block:: cpp + + promise_t::reject() const; + +Reject the promise without empty reason. This may reject the other promises +waiting for the current promise recursively. When a promise is rejected, the +registered ``on_rejected()`` function should be expecting on argument, +otherwise a type mismatch is thrown. .. code-block:: cpp template<typename FuncFulfilled> - promise_t then(FuncFulfilled on_fulfilled) const; + promise_t promise_t::then(FuncFulfilled on_fulfilled) const; Create a new promise that waits for the resolution of the current promise. -``on_fulfilled`` will be called with result from the current promise when +``on_fulfilled`` will be invoked with result from the current promise when resolved. The rejection will skip the callback and pass on to the promises that follow the created promise. .. code-block:: cpp template<typename FuncRejected> - promise_t fail(FuncRejected on_rejected) const; + promise_t promise_t::fail(FuncRejected on_rejected) const; Create a new promise that waits for the rejection of the current promise. -``on_rejected`` will be called with reason from the current promise when +``on_rejected`` will be invoked with reason from the current promise when rejected. The resolution will skip the callback and pass on to the promises that follow the created promise. .. code-block:: cpp template<typename FuncFulfilled, typename FuncRejected> - promise_t then(FuncFulfilled on_fulfilled, - FuncRejected on_rejected) const; + promise_t promise_t::then(FuncFulfilled on_fulfilled, + FuncRejected on_rejected) const; + +Create a promise with callbacks that handle both resolution and rejection of +the current promise. + +.. code-block:: cpp + + template<typename PList> promise_t promise::all(PList promise_list); + +Create a promise waiting for the asynchronous resolution of all promises in +``promise_list``. The result for the created promise will be typed +``values_t``, a vector of ``pm_any_t`` values, each of which being the result +corresponds to a listed promise in ``promise_list`` in order. The created +promise will be rejected with the reason from the first rejection of any listed +promises. + +.. code-block:: cpp + + template<typename PList> promise_t promise::race(PList promise_list); -Create a promise that handles both resolution and rejection of the current promise. +Create a promise waiting for the asynchronous resolution of any promises in +``promise_list``. The result for the created promise will be the result from +the first resolved promise, and typed ``pm_any_t``. The created promise will +be rejected with the reason from the first rejection of any listed promises. diff --git a/promise.hpp b/promise.hpp index ae77c43..97a1400 100644 --- a/promise.hpp +++ b/promise.hpp @@ -110,11 +110,22 @@ namespace promise { !std::is_same<typename function_traits<Func>::ret_type, ReturnType>::value>; + template<typename Func, typename ArgType> + using enable_if_arg = typename std::enable_if< + std::is_same<typename function_traits<Func>::arg_type, + ArgType>::value>; + + template<typename Func, typename ArgType> + using disable_if_arg = typename std::enable_if< + !std::is_same<typename function_traits<Func>::arg_type, + ArgType>::value>; + class Promise; class promise_t: std::shared_ptr<Promise> { public: friend Promise; template<typename PList> friend promise_t all(PList promise_list); + template<typename PList> friend promise_t race(PList promise_list); template<typename Func> promise_t(Func callback): std::shared_ptr<Promise>(std::make_shared<Promise>()) { @@ -159,29 +170,25 @@ namespace promise { rejected_callbacks.push_back(cb); } - template<typename Func, typename function_traits<Func>::non_empty_arg * = nullptr> - static constexpr auto cps_transform(Func f, const pm_any_t &result, const promise_t &npm) { + template<typename Func, + typename function_traits<Func>::non_empty_arg * = nullptr> + static constexpr auto cps_transform( + Func f, const pm_any_t &result, const promise_t &npm) { return [&result, f, npm]() mutable { f(result)->then( - [npm] (pm_any_t result_) { - npm->resolve(result_); - }, - [npm] (pm_any_t reason_) { - npm->reject(reason_); - }); + [npm] (pm_any_t result) {npm->resolve(result);}, + [npm] (pm_any_t reason) {npm->reject(reason);}); }; } - template<typename Func, typename function_traits<Func>::empty_arg * = nullptr> - static constexpr auto cps_transform(Func f, const pm_any_t &, const promise_t &npm) { + template<typename Func, + typename function_traits<Func>::empty_arg * = nullptr> + static constexpr auto cps_transform( + Func f, const pm_any_t &, const promise_t &npm) { return [f, npm]() mutable { f()->then( - [npm] (pm_any_t result_) { - npm->resolve(result_); - }, - [npm] (pm_any_t reason_) { - npm->reject(reason_); - }); + [npm] (pm_any_t result) {npm->resolve(result);}, + [npm] (pm_any_t reason) {npm->reject(reason);}); }; } @@ -391,14 +398,21 @@ namespace promise { if (!--(*size)) npm->resolve(*results); }, - [npm, size](pm_any_t reason) { - npm->reject(reason); - }); + [npm](pm_any_t reason) {npm->reject(reason);}); idx++; } }); } + template<typename PList> promise_t race(PList promise_list) { + return promise_t([promise_list] (promise_t npm) { + for (const auto &pm: promise_list) { + pm->then([npm](pm_any_t result) {npm->resolve(result);}, + [npm](pm_any_t reason) {npm->reject(reason);}); + } + }); + } + template<typename T> inline void promise_t::resolve(T result) const { (*this)->resolve(result); } @@ -417,6 +431,7 @@ namespace promise { }; template<typename Func, + typename disable_if_arg<Func, pm_any_t>::type * = nullptr, typename enable_if_return<Func, void>::type * = nullptr, typename function_traits<Func>::non_empty_arg * = nullptr> constexpr auto gen_any_callback(Func f) { @@ -429,11 +444,32 @@ namespace promise { } template<typename Func, + typename enable_if_arg<Func, pm_any_t>::type * = nullptr, + typename enable_if_return<Func, void>::type * = nullptr, + typename function_traits<Func>::non_empty_arg * = nullptr> + constexpr auto gen_any_callback(Func f) { + using func_t = callback_types<Func>; + return [f](pm_any_t v) mutable {f(v);}; + } + + template<typename Func, typename enable_if_return<Func, void>::type * = nullptr, typename function_traits<Func>::empty_arg * = nullptr> constexpr auto gen_any_callback(Func f) { return f; } template<typename Func, + typename enable_if_arg<Func, pm_any_t>::type * = nullptr, + typename disable_if_return<Func, void>::type * = nullptr, + typename function_traits<Func>::non_empty_arg * = nullptr> + constexpr auto gen_any_callback(Func f) { + using func_t = callback_types<Func>; + return [f](pm_any_t v) mutable { + return typename func_t::ret_type(f(v)); + }; + } + + template<typename Func, + typename disable_if_arg<Func, pm_any_t>::type * = nullptr, typename disable_if_return<Func, void>::type * = nullptr, typename function_traits<Func>::non_empty_arg * = nullptr> constexpr auto gen_any_callback(Func f) { @@ -63,7 +63,7 @@ int main() { printf("got resolved x = %d, output 12\n", x); return 12; }).then(f).then(a1).fail(a2).then(b1).fail(b2).then(g).then(a3, b3) - .then([](int x) { + .then([](int) { puts("void return is ok"); }).then([]() { puts("void parameter is ok"); @@ -102,8 +102,21 @@ int main() { return reason; }) .then([](const promise::values_t values) { - printf("finally %d\n", any_cast<int>(values[1])); + int x = any_cast<int>(values[1]); + printf("promise 1, 6 resolved %d\n", x); + return x + 1; }); + + auto pm8 = promise_t([](promise_t) { + puts("promsie 8 will never be resolved"); + }); + + auto pm9 = promise::race(std::vector<promise_t>{pm7, pm8}) + .then([](promise::pm_any_t value) { + printf("finally, promise 9 resolved with %d\n", + any_cast<int>(value)); + }); + puts("calling t4: resolve promise 3"); t4(); puts("calling t5: resolve promise 4"); diff --git a/test_ref.txt b/test_ref.txt index 54d6079..142ba93 100644 --- a/test_ref.txt +++ b/test_ref.txt @@ -2,6 +2,7 @@ promise 1 constructed, but won't be resolved immediately promise 3 constructed promise 4 constructed promise 5 constructed +promsie 8 will never be resolved calling t4: resolve promise 3 calling t5: resolve promise 4 calling t3: resolve promise 5 @@ -21,4 +22,5 @@ operator A got 1 void return is ok void parameter is ok void parameter will ignore the returned value -finally 100 +promise 1, 6 resolved 100 +finally, promise 9 resolved with 101 |