aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <ted.sybil@gmail.com>2018-02-04 15:16:58 -0500
committerDeterminant <ted.sybil@gmail.com>2018-02-04 15:16:58 -0500
commitac3a0030123a350bff490d69a4786954a9003686 (patch)
tree54d85b015739cef725a8eaec19d4678fa44f57d4
parent7a95221366f1a2aef9414ae7484242726bb812a1 (diff)
add `race`
-rw-r--r--README.rst67
-rw-r--r--promise.hpp74
-rw-r--r--test.cpp17
-rw-r--r--test_ref.txt4
4 files changed, 127 insertions, 35 deletions
diff --git a/README.rst b/README.rst
index 9cdcd21..76591e6 100644
--- a/README.rst
+++ b/README.rst
@@ -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) {
diff --git a/test.cpp b/test.cpp
index afa0f3f..737512e 100644
--- a/test.cpp
+++ b/test.cpp
@@ -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