mirror of
https://github.com/BlackMATov/promise.hpp.git
synced 2025-12-13 03:46:29 +07:00
@@ -10,14 +10,14 @@
|
|||||||
[badge.travis]: https://img.shields.io/travis/BlackMATov/promise.hpp/master.svg?logo=travis
|
[badge.travis]: https://img.shields.io/travis/BlackMATov/promise.hpp/master.svg?logo=travis
|
||||||
[badge.appveyor]: https://img.shields.io/appveyor/ci/BlackMATov/promise-hpp/master.svg?logo=appveyor
|
[badge.appveyor]: https://img.shields.io/appveyor/ci/BlackMATov/promise-hpp/master.svg?logo=appveyor
|
||||||
[badge.codecov]: https://img.shields.io/codecov/c/github/BlackMATov/promise.hpp/master.svg?logo=codecov
|
[badge.codecov]: https://img.shields.io/codecov/c/github/BlackMATov/promise.hpp/master.svg?logo=codecov
|
||||||
[badge.language]: https://img.shields.io/badge/language-C%2B%2B14-red.svg
|
[badge.language]: https://img.shields.io/badge/language-C%2B%2B17-yellow.svg
|
||||||
[badge.license]: https://img.shields.io/badge/license-MIT-blue.svg
|
[badge.license]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||||
[badge.paypal]: https://img.shields.io/badge/donate-PayPal-orange.svg?logo=paypal&colorA=00457C
|
[badge.paypal]: https://img.shields.io/badge/donate-PayPal-orange.svg?logo=paypal&colorA=00457C
|
||||||
|
|
||||||
[travis]: https://travis-ci.org/BlackMATov/promise.hpp
|
[travis]: https://travis-ci.org/BlackMATov/promise.hpp
|
||||||
[appveyor]: https://ci.appveyor.com/project/BlackMATov/promise-hpp
|
[appveyor]: https://ci.appveyor.com/project/BlackMATov/promise-hpp
|
||||||
[codecov]: https://codecov.io/gh/BlackMATov/promise.hpp
|
[codecov]: https://codecov.io/gh/BlackMATov/promise.hpp
|
||||||
[language]: https://en.wikipedia.org/wiki/C%2B%2B14
|
[language]: https://en.wikipedia.org/wiki/C%2B%2B17
|
||||||
[license]: https://en.wikipedia.org/wiki/MIT_License
|
[license]: https://en.wikipedia.org/wiki/MIT_License
|
||||||
[paypal]: https://www.paypal.me/matov
|
[paypal]: https://www.paypal.me/matov
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ namespace promise_hpp
|
|||||||
struct is_promise
|
struct is_promise
|
||||||
: impl::is_promise_impl<std::remove_cv_t<T>> {};
|
: impl::is_promise_impl<std::remove_cv_t<T>> {};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
inline constexpr bool is_promise_v = is_promise<T>::value;
|
||||||
|
|
||||||
//
|
//
|
||||||
// is_promise_r
|
// is_promise_r
|
||||||
//
|
//
|
||||||
@@ -72,6 +75,9 @@ namespace promise_hpp
|
|||||||
struct is_promise_r
|
struct is_promise_r
|
||||||
: impl::is_promise_r_impl<R, std::remove_cv_t<T>> {};
|
: impl::is_promise_r_impl<R, std::remove_cv_t<T>> {};
|
||||||
|
|
||||||
|
template < typename R, typename T >
|
||||||
|
inline constexpr bool is_promise_r_v = is_promise_r<R, T>::value;
|
||||||
|
|
||||||
//
|
//
|
||||||
// detail
|
// detail
|
||||||
//
|
//
|
||||||
@@ -93,29 +99,37 @@ namespace promise_hpp
|
|||||||
storage() = default;
|
storage() = default;
|
||||||
|
|
||||||
~storage()
|
~storage()
|
||||||
noexcept(std::is_nothrow_destructible<T>::value)
|
noexcept(std::is_nothrow_destructible_v<T>) {
|
||||||
{
|
|
||||||
if ( initialized_ ) {
|
if ( initialized_ ) {
|
||||||
ptr_()->~T();
|
ptr_()->~T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename U >
|
void set(T&& value)
|
||||||
void set(U&& value)
|
noexcept(std::is_nothrow_move_constructible_v<T>) {
|
||||||
noexcept(std::is_nothrow_constructible<T,U&&>::value)
|
|
||||||
{
|
|
||||||
assert(!initialized_);
|
assert(!initialized_);
|
||||||
::new(ptr_()) T(std::forward<U>(value));
|
::new(ptr_()) T(std::move(value));
|
||||||
|
initialized_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(const T& value)
|
||||||
|
noexcept(std::is_nothrow_copy_constructible_v<T>) {
|
||||||
|
assert(!initialized_);
|
||||||
|
::new(ptr_()) T(value);
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
T get()
|
T get()
|
||||||
noexcept(std::is_nothrow_move_constructible<T>::value)
|
noexcept(std::is_nothrow_move_constructible_v<T>) {
|
||||||
{
|
|
||||||
assert(initialized_);
|
assert(initialized_);
|
||||||
return std::move(*ptr_());
|
return std::move(*ptr_());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T& value() noexcept {
|
||||||
|
assert(initialized_);
|
||||||
|
return *ptr_();
|
||||||
|
}
|
||||||
|
|
||||||
const T& value() const noexcept {
|
const T& value() const noexcept {
|
||||||
assert(initialized_);
|
assert(initialized_);
|
||||||
return *ptr_();
|
return *ptr_();
|
||||||
@@ -132,6 +146,37 @@ namespace promise_hpp
|
|||||||
std::aligned_storage_t<sizeof(T), alignof(T)> data_;
|
std::aligned_storage_t<sizeof(T), alignof(T)> data_;
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
class storage<T&> final : private noncopyable {
|
||||||
|
public:
|
||||||
|
storage() = default;
|
||||||
|
~storage() = default;
|
||||||
|
|
||||||
|
void set(T& value) noexcept {
|
||||||
|
assert(!initialized_);
|
||||||
|
value_ = &value;
|
||||||
|
initialized_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& get() noexcept {
|
||||||
|
assert(initialized_);
|
||||||
|
return *value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& value() noexcept {
|
||||||
|
assert(initialized_);
|
||||||
|
return *value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& value() const noexcept {
|
||||||
|
assert(initialized_);
|
||||||
|
return *value_;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
T* value_{nullptr};
|
||||||
|
bool initialized_ = false;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -142,21 +187,29 @@ namespace promise_hpp
|
|||||||
no_timeout,
|
no_timeout,
|
||||||
timeout
|
timeout
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//
|
// -----------------------------------------------------------------------------
|
||||||
// promise<T>
|
//
|
||||||
//
|
// promise<T>
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace promise_hpp
|
||||||
|
{
|
||||||
template < typename T >
|
template < typename T >
|
||||||
class promise final {
|
class promise final {
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
public:
|
|
||||||
promise()
|
promise()
|
||||||
: state_(std::make_shared<state>()) {}
|
: state_(std::make_shared<state>()) {}
|
||||||
|
|
||||||
promise(const promise&) noexcept = default;
|
promise(promise&&) = default;
|
||||||
promise& operator=(const promise&) noexcept = default;
|
promise& operator=(promise&&) = default;
|
||||||
|
|
||||||
|
promise(const promise&) = default;
|
||||||
|
promise& operator=(const promise&) = default;
|
||||||
|
|
||||||
void swap(promise& other) noexcept {
|
void swap(promise& other) noexcept {
|
||||||
state_.swap(other.state_);
|
state_.swap(other.state_);
|
||||||
@@ -178,50 +231,80 @@ namespace promise_hpp
|
|||||||
return l.state_ != r.state_;
|
return l.state_ != r.state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename ResolveF
|
//
|
||||||
, typename ResolveFR = std::invoke_result_t<ResolveF,T> >
|
// get
|
||||||
std::enable_if_t<
|
//
|
||||||
is_promise<ResolveFR>::value && std::is_void<typename ResolveFR::value_type>::value,
|
|
||||||
promise<typename ResolveFR::value_type>>
|
|
||||||
then(ResolveF&& on_resolve) {
|
|
||||||
promise<typename ResolveFR::value_type> next;
|
|
||||||
|
|
||||||
then([
|
const T& get() const {
|
||||||
n = next,
|
return state_->get();
|
||||||
f = std::forward<ResolveF>(on_resolve)
|
|
||||||
](auto&& v) mutable {
|
|
||||||
auto np = std::invoke(
|
|
||||||
std::forward<decltype(f)>(f),
|
|
||||||
std::forward<decltype(v)>(v));
|
|
||||||
std::move(np).then([n]() mutable {
|
|
||||||
n.resolve();
|
|
||||||
}).except([n](std::exception_ptr e) mutable {
|
|
||||||
n.reject(e);
|
|
||||||
});
|
|
||||||
}).except([n = next](std::exception_ptr e) mutable {
|
|
||||||
n.reject(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
return next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename U >
|
||||||
|
T get_or_default(U&& def) const {
|
||||||
|
try {
|
||||||
|
return get();
|
||||||
|
} catch (...) {
|
||||||
|
return std::forward<U>(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// wait
|
||||||
|
//
|
||||||
|
|
||||||
|
void wait() const noexcept {
|
||||||
|
state_->wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Rep, typename Period >
|
||||||
|
promise_wait_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const {
|
||||||
|
return state_->wait_for(timeout_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Clock, typename Duration >
|
||||||
|
promise_wait_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const {
|
||||||
|
return state_->wait_until(timeout_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// resolve/reject
|
||||||
|
//
|
||||||
|
|
||||||
|
template < typename U >
|
||||||
|
bool resolve(U&& value) {
|
||||||
|
return state_->resolve(std::forward<U>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reject(std::exception_ptr e) noexcept {
|
||||||
|
return state_->reject(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename E >
|
||||||
|
bool reject(E&& e) {
|
||||||
|
return state_->reject(std::make_exception_ptr(std::forward<E>(e)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// then
|
||||||
|
//
|
||||||
|
|
||||||
template < typename ResolveF
|
template < typename ResolveF
|
||||||
, typename ResolveFR = std::invoke_result_t<ResolveF,T> >
|
, typename ResolveR = std::invoke_result_t<ResolveF, T> >
|
||||||
std::enable_if_t<
|
std::enable_if_t<
|
||||||
is_promise<ResolveFR>::value && !std::is_void<typename ResolveFR::value_type>::value,
|
is_promise_v<ResolveR>,
|
||||||
promise<typename ResolveFR::value_type>>
|
promise<typename ResolveR::value_type>>
|
||||||
then(ResolveF&& on_resolve) {
|
then(ResolveF&& on_resolve) {
|
||||||
promise<typename ResolveFR::value_type> next;
|
promise<typename ResolveR::value_type> next;
|
||||||
|
|
||||||
then([
|
then([
|
||||||
n = next,
|
n = next,
|
||||||
f = std::forward<ResolveF>(on_resolve)
|
f = std::forward<ResolveF>(on_resolve)
|
||||||
](auto&& v) mutable {
|
](auto&&... vs) mutable {
|
||||||
auto np = std::invoke(
|
auto np = std::invoke(
|
||||||
std::forward<decltype(f)>(f),
|
std::forward<decltype(f)>(f),
|
||||||
std::forward<decltype(v)>(v));
|
std::forward<decltype(vs)>(vs)...);
|
||||||
std::move(np).then([n](auto&& nv) mutable {
|
std::move(np).then([n](auto&&... nvs) mutable {
|
||||||
n.resolve(std::forward<decltype(nv)>(nv));
|
n.resolve(std::forward<decltype(nvs)>(nvs)...);
|
||||||
}).except([n](std::exception_ptr e) mutable {
|
}).except([n](std::exception_ptr e) mutable {
|
||||||
n.reject(e);
|
n.reject(e);
|
||||||
});
|
});
|
||||||
@@ -268,38 +351,48 @@ namespace promise_hpp
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// then
|
||||||
|
//
|
||||||
|
|
||||||
|
template < typename ResolveF
|
||||||
|
, typename ResolveR = std::invoke_result_t<ResolveF, T> >
|
||||||
|
std::enable_if_t<
|
||||||
|
!is_promise_v<ResolveR>,
|
||||||
|
promise<ResolveR>>
|
||||||
|
then(ResolveF&& on_resolve) {
|
||||||
|
promise<ResolveR> next;
|
||||||
|
|
||||||
|
state_->attach(
|
||||||
|
next,
|
||||||
|
std::forward<ResolveF>(on_resolve),
|
||||||
|
[](std::exception_ptr e) -> ResolveR { std::rethrow_exception(e); },
|
||||||
|
false);
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
template < typename ResolveF
|
template < typename ResolveF
|
||||||
, typename RejectF
|
, typename RejectF
|
||||||
, typename ResolveFR = std::invoke_result_t<ResolveF,T> >
|
, typename ResolveR = std::invoke_result_t<ResolveF, T> >
|
||||||
std::enable_if_t<
|
std::enable_if_t<
|
||||||
!is_promise<ResolveFR>::value,
|
!is_promise_v<ResolveR>,
|
||||||
promise<ResolveFR>>
|
promise<ResolveR>>
|
||||||
then(ResolveF&& on_resolve, RejectF&& on_reject) {
|
then(ResolveF&& on_resolve, RejectF&& on_reject) {
|
||||||
promise<ResolveFR> next;
|
promise<ResolveR> next;
|
||||||
|
|
||||||
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);
|
true);
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename ResolveF
|
//
|
||||||
, typename ResolveFR = std::invoke_result_t<ResolveF,T> >
|
// except
|
||||||
std::enable_if_t<
|
//
|
||||||
!is_promise<ResolveFR>::value,
|
|
||||||
promise<ResolveFR>>
|
|
||||||
then(ResolveF&& on_resolve) {
|
|
||||||
promise<ResolveFR> next;
|
|
||||||
state_->attach(
|
|
||||||
next,
|
|
||||||
std::forward<ResolveF>(on_resolve),
|
|
||||||
[](std::exception_ptr e) -> ResolveFR {
|
|
||||||
std::rethrow_exception(e);
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename RejectF >
|
template < typename RejectF >
|
||||||
promise<T> except(RejectF&& on_reject) {
|
promise<T> except(RejectF&& on_reject) {
|
||||||
@@ -307,52 +400,6 @@ namespace promise_hpp
|
|||||||
[](auto&& v) { return std::forward<decltype(v)>(v); },
|
[](auto&& v) { return std::forward<decltype(v)>(v); },
|
||||||
std::forward<RejectF>(on_reject));
|
std::forward<RejectF>(on_reject));
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename U >
|
|
||||||
bool resolve(U&& value) {
|
|
||||||
return state_->resolve(std::forward<U>(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool reject(std::exception_ptr e) noexcept {
|
|
||||||
return state_->reject(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename E >
|
|
||||||
bool reject(E&& e) {
|
|
||||||
return state_->reject(
|
|
||||||
std::make_exception_ptr(std::forward<E>(e)));
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& get() const {
|
|
||||||
return state_->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename U >
|
|
||||||
T get_or_default(U&& def) const {
|
|
||||||
try {
|
|
||||||
return get();
|
|
||||||
} catch (...) {
|
|
||||||
return std::forward<U>(def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void wait() const noexcept {
|
|
||||||
state_->wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename Rep, typename Period >
|
|
||||||
promise_wait_status wait_for(
|
|
||||||
const std::chrono::duration<Rep, Period>& timeout_duration) const
|
|
||||||
{
|
|
||||||
return state_->wait_for(timeout_duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename Clock, typename Duration >
|
|
||||||
promise_wait_status wait_until(
|
|
||||||
const std::chrono::time_point<Clock, Duration>& timeout_time) const
|
|
||||||
{
|
|
||||||
return state_->wait_until(timeout_time);
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
class state;
|
class state;
|
||||||
std::shared_ptr<state> state_;
|
std::shared_ptr<state> state_;
|
||||||
@@ -361,33 +408,8 @@ namespace promise_hpp
|
|||||||
public:
|
public:
|
||||||
state() = default;
|
state() = default;
|
||||||
|
|
||||||
template < typename U >
|
|
||||||
bool resolve(U&& value) {
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
if ( status_ != status::pending ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
storage_.set(std::forward<U>(value));
|
|
||||||
status_ = status::resolved;
|
|
||||||
invoke_resolve_handlers_();
|
|
||||||
cond_var_.notify_all();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool reject(std::exception_ptr e) noexcept {
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
if ( status_ != status::pending ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
exception_ = e;
|
|
||||||
status_ = status::rejected;
|
|
||||||
invoke_reject_handlers_();
|
|
||||||
cond_var_.notify_all();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const T& get() {
|
const T& get() {
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock lock(mutex_);
|
||||||
cond_var_.wait(lock, [this](){
|
cond_var_.wait(lock, [this](){
|
||||||
return status_ != status::pending;
|
return status_ != status::pending;
|
||||||
});
|
});
|
||||||
@@ -399,42 +421,56 @@ namespace promise_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
void wait() const noexcept {
|
void wait() const noexcept {
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock lock(mutex_);
|
||||||
cond_var_.wait(lock, [this](){
|
cond_var_.wait(lock, [this](){
|
||||||
return status_ != status::pending;
|
return status_ != status::pending;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Rep, typename Period >
|
template < typename Rep, typename Period >
|
||||||
promise_wait_status wait_for(
|
promise_wait_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const {
|
||||||
const std::chrono::duration<Rep, Period>& timeout_duration) const
|
std::unique_lock lock(mutex_);
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
|
||||||
return cond_var_.wait_for(lock, timeout_duration, [this](){
|
return cond_var_.wait_for(lock, timeout_duration, [this](){
|
||||||
return status_ != status::pending;
|
return status_ != status::pending;
|
||||||
}) ? promise_wait_status::no_timeout
|
}) ? promise_wait_status::no_timeout : promise_wait_status::timeout;
|
||||||
: promise_wait_status::timeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Clock, typename Duration >
|
template < typename Clock, typename Duration >
|
||||||
promise_wait_status wait_until(
|
promise_wait_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const {
|
||||||
const std::chrono::time_point<Clock, Duration>& timeout_time) const
|
std::unique_lock lock(mutex_);
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
|
||||||
return cond_var_.wait_until(lock, timeout_time, [this](){
|
return cond_var_.wait_until(lock, timeout_time, [this](){
|
||||||
return status_ != status::pending;
|
return status_ != status::pending;
|
||||||
}) ? promise_wait_status::no_timeout
|
}) ? promise_wait_status::no_timeout : promise_wait_status::timeout;
|
||||||
: promise_wait_status::timeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template < typename U >
|
||||||
|
bool resolve(U&& value) {
|
||||||
|
std::lock_guard guard(mutex_);
|
||||||
|
if ( status_ != status::pending ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
storage_.set(std::forward<U>(value));
|
||||||
|
status_ = status::resolved;
|
||||||
|
invoke_resolve_handlers_();
|
||||||
|
cond_var_.notify_all();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reject(std::exception_ptr e) noexcept {
|
||||||
|
std::lock_guard guard(mutex_);
|
||||||
|
if ( status_ != status::pending ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
exception_ = e;
|
||||||
|
status_ = status::rejected;
|
||||||
|
invoke_reject_handlers_();
|
||||||
|
cond_var_.notify_all();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public:
|
||||||
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(
|
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject, bool has_reject) {
|
||||||
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),
|
||||||
@@ -468,18 +504,13 @@ namespace promise_hpp
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard guard(mutex_);
|
||||||
add_handlers_(std::move(resolve_h), std::move(reject_h));
|
add_handlers_(std::move(resolve_h), std::move(reject_h));
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject, bool has_reject) {
|
||||||
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),
|
||||||
@@ -513,7 +544,7 @@ namespace promise_hpp
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard guard(mutex_);
|
||||||
add_handlers_(std::move(resolve_h), std::move(reject_h));
|
add_handlers_(std::move(resolve_h), std::move(reject_h));
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@@ -528,16 +559,15 @@ namespace promise_hpp
|
|||||||
std::forward<RejectF>(reject),
|
std::forward<RejectF>(reject),
|
||||||
exception_);
|
exception_);
|
||||||
} else {
|
} else {
|
||||||
handlers_.emplace_back(
|
handlers_.push_back({
|
||||||
std::forward<ResolveF>(resolve),
|
std::forward<ResolveF>(resolve),
|
||||||
std::forward<RejectF>(reject));
|
std::forward<RejectF>(reject)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void invoke_resolve_handlers_() noexcept {
|
void invoke_resolve_handlers_() noexcept {
|
||||||
const T& value = storage_.value();
|
|
||||||
for ( const auto& h : handlers_ ) {
|
for ( const auto& h : handlers_ ) {
|
||||||
h.resolve_(value);
|
h.resolve_(storage_.value());
|
||||||
}
|
}
|
||||||
handlers_.clear();
|
handlers_.clear();
|
||||||
}
|
}
|
||||||
@@ -567,32 +597,35 @@ namespace promise_hpp
|
|||||||
|
|
||||||
resolve_t resolve_;
|
resolve_t resolve_;
|
||||||
reject_t reject_;
|
reject_t reject_;
|
||||||
|
|
||||||
template < typename ResolveF, typename RejectF >
|
|
||||||
handler(ResolveF&& resolve, RejectF&& reject)
|
|
||||||
: resolve_(std::forward<ResolveF>(resolve))
|
|
||||||
, reject_(std::forward<RejectF>(reject)) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<handler> handlers_;
|
std::vector<handler> handlers_;
|
||||||
detail::storage<T> storage_;
|
detail::storage<T> storage_;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//
|
// -----------------------------------------------------------------------------
|
||||||
// promise<void>
|
//
|
||||||
//
|
// promise<void>
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace promise_hpp
|
||||||
|
{
|
||||||
template <>
|
template <>
|
||||||
class promise<void> final {
|
class promise<void> final {
|
||||||
public:
|
public:
|
||||||
using value_type = void;
|
using value_type = void;
|
||||||
public:
|
|
||||||
promise()
|
promise()
|
||||||
: state_(std::make_shared<state>()) {}
|
: state_(std::make_shared<state>()) {}
|
||||||
|
|
||||||
promise(const promise&) noexcept = default;
|
promise(promise&&) = default;
|
||||||
promise& operator=(const promise&) noexcept = default;
|
promise& operator=(promise&&) = default;
|
||||||
|
|
||||||
|
promise(const promise&) = default;
|
||||||
|
promise& operator=(const promise&) = default;
|
||||||
|
|
||||||
void swap(promise& other) noexcept {
|
void swap(promise& other) noexcept {
|
||||||
state_.swap(other.state_);
|
state_.swap(other.state_);
|
||||||
@@ -614,48 +647,78 @@ namespace promise_hpp
|
|||||||
return l.state_ != r.state_;
|
return l.state_ != r.state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename ResolveF
|
//
|
||||||
, typename ResolveFR = std::invoke_result_t<ResolveF> >
|
// get
|
||||||
std::enable_if_t<
|
//
|
||||||
is_promise<ResolveFR>::value && std::is_void<typename ResolveFR::value_type>::value,
|
|
||||||
promise<typename ResolveFR::value_type>>
|
|
||||||
then(ResolveF&& on_resolve) {
|
|
||||||
promise<typename ResolveFR::value_type> next;
|
|
||||||
|
|
||||||
then([
|
void get() const {
|
||||||
n = next,
|
state_->get();
|
||||||
f = std::forward<ResolveF>(on_resolve)
|
|
||||||
]() mutable {
|
|
||||||
auto np = std::invoke(
|
|
||||||
std::forward<decltype(f)>(f));
|
|
||||||
std::move(np).then([n]() mutable {
|
|
||||||
n.resolve();
|
|
||||||
}).except([n](std::exception_ptr e) mutable {
|
|
||||||
n.reject(e);
|
|
||||||
});
|
|
||||||
}).except([n = next](std::exception_ptr e) mutable {
|
|
||||||
n.reject(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
return next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_or_default() const {
|
||||||
|
try {
|
||||||
|
return get();
|
||||||
|
} catch (...) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// wait
|
||||||
|
//
|
||||||
|
|
||||||
|
void wait() const noexcept {
|
||||||
|
state_->wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Rep, typename Period >
|
||||||
|
promise_wait_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const {
|
||||||
|
return state_->wait_for(timeout_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Clock, typename Duration >
|
||||||
|
promise_wait_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const {
|
||||||
|
return state_->wait_until(timeout_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// resolve/reject
|
||||||
|
//
|
||||||
|
|
||||||
|
bool resolve() {
|
||||||
|
return state_->resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reject(std::exception_ptr e) noexcept {
|
||||||
|
return state_->reject(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename E >
|
||||||
|
bool reject(E&& e) {
|
||||||
|
return state_->reject(std::make_exception_ptr(std::forward<E>(e)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// then
|
||||||
|
//
|
||||||
|
|
||||||
template < typename ResolveF
|
template < typename ResolveF
|
||||||
, typename ResolveFR = std::invoke_result_t<ResolveF> >
|
, typename ResolveR = std::invoke_result_t<ResolveF> >
|
||||||
std::enable_if_t<
|
std::enable_if_t<
|
||||||
is_promise<ResolveFR>::value && !std::is_void<typename ResolveFR::value_type>::value,
|
is_promise_v<ResolveR>,
|
||||||
promise<typename ResolveFR::value_type>>
|
promise<typename ResolveR::value_type>>
|
||||||
then(ResolveF&& on_resolve) {
|
then(ResolveF&& on_resolve) {
|
||||||
promise<typename ResolveFR::value_type> next;
|
promise<typename ResolveR::value_type> next;
|
||||||
|
|
||||||
then([
|
then([
|
||||||
n = next,
|
n = next,
|
||||||
f = std::forward<ResolveF>(on_resolve)
|
f = std::forward<ResolveF>(on_resolve)
|
||||||
]() mutable {
|
](auto&&... vs) mutable {
|
||||||
auto np = std::invoke(
|
auto np = std::invoke(
|
||||||
std::forward<decltype(f)>(f));
|
std::forward<decltype(f)>(f),
|
||||||
std::move(np).then([n](auto&& nv) mutable {
|
std::forward<decltype(vs)>(vs)...);
|
||||||
n.resolve(std::forward<decltype(nv)>(nv));
|
std::move(np).then([n](auto&&... nvs) mutable {
|
||||||
|
n.resolve(std::forward<decltype(nvs)>(nvs)...);
|
||||||
}).except([n](std::exception_ptr e) mutable {
|
}).except([n](std::exception_ptr e) mutable {
|
||||||
n.reject(e);
|
n.reject(e);
|
||||||
});
|
});
|
||||||
@@ -699,89 +762,55 @@ namespace promise_hpp
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// then
|
||||||
|
//
|
||||||
|
|
||||||
|
template < typename ResolveF
|
||||||
|
, typename ResolveR = std::invoke_result_t<ResolveF> >
|
||||||
|
std::enable_if_t<
|
||||||
|
!is_promise_v<ResolveR>,
|
||||||
|
promise<ResolveR>>
|
||||||
|
then(ResolveF&& on_resolve) {
|
||||||
|
promise<ResolveR> next;
|
||||||
|
|
||||||
|
state_->attach(
|
||||||
|
next,
|
||||||
|
std::forward<ResolveF>(on_resolve),
|
||||||
|
[](std::exception_ptr e) -> ResolveR { std::rethrow_exception(e); },
|
||||||
|
false);
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
template < typename ResolveF
|
template < typename ResolveF
|
||||||
, typename RejectF
|
, typename RejectF
|
||||||
, typename ResolveFR = std::invoke_result_t<ResolveF> >
|
, typename ResolveR = std::invoke_result_t<ResolveF> >
|
||||||
std::enable_if_t<
|
std::enable_if_t<
|
||||||
!is_promise<ResolveFR>::value,
|
!is_promise_v<ResolveR>,
|
||||||
promise<ResolveFR>>
|
promise<ResolveR>>
|
||||||
then(ResolveF&& on_resolve, RejectF&& on_reject) {
|
then(ResolveF&& on_resolve, RejectF&& on_reject) {
|
||||||
promise<ResolveFR> next;
|
promise<ResolveR> next;
|
||||||
|
|
||||||
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);
|
true);
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename ResolveF
|
//
|
||||||
, typename ResolveFR = std::invoke_result_t<ResolveF> >
|
// except
|
||||||
std::enable_if_t<
|
//
|
||||||
!is_promise<ResolveFR>::value,
|
|
||||||
promise<ResolveFR>>
|
|
||||||
then(ResolveF&& on_resolve) {
|
|
||||||
promise<ResolveFR> next;
|
|
||||||
state_->attach(
|
|
||||||
next,
|
|
||||||
std::forward<ResolveF>(on_resolve),
|
|
||||||
[](std::exception_ptr e) -> ResolveFR {
|
|
||||||
std::rethrow_exception(e);
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename RejectF >
|
template < typename RejectF >
|
||||||
promise<void> except(RejectF&& on_reject) {
|
promise<void> except(RejectF&& on_reject) {
|
||||||
return then(
|
return then(
|
||||||
[]{},
|
[](){},
|
||||||
std::forward<RejectF>(on_reject));
|
std::forward<RejectF>(on_reject));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool resolve() {
|
|
||||||
return state_->resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool reject(std::exception_ptr e) noexcept {
|
|
||||||
return state_->reject(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename E >
|
|
||||||
bool reject(E&& e) {
|
|
||||||
return state_->reject(
|
|
||||||
std::make_exception_ptr(std::forward<E>(e)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void get() const {
|
|
||||||
state_->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_or_default() const {
|
|
||||||
try {
|
|
||||||
return get();
|
|
||||||
} catch (...) {
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void wait() const noexcept {
|
|
||||||
state_->wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename Rep, typename Period >
|
|
||||||
promise_wait_status wait_for(
|
|
||||||
const std::chrono::duration<Rep, Period>& timeout_duration) const
|
|
||||||
{
|
|
||||||
return state_->wait_for(timeout_duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename Clock, typename Duration >
|
|
||||||
promise_wait_status wait_until(
|
|
||||||
const std::chrono::time_point<Clock, Duration>& timeout_time) const
|
|
||||||
{
|
|
||||||
return state_->wait_until(timeout_time);
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
class state;
|
class state;
|
||||||
std::shared_ptr<state> state_;
|
std::shared_ptr<state> state_;
|
||||||
@@ -790,31 +819,8 @@ namespace promise_hpp
|
|||||||
public:
|
public:
|
||||||
state() = default;
|
state() = default;
|
||||||
|
|
||||||
bool resolve() {
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
if ( status_ != status::pending ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
status_ = status::resolved;
|
|
||||||
invoke_resolve_handlers_();
|
|
||||||
cond_var_.notify_all();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool reject(std::exception_ptr e) noexcept {
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
if ( status_ != status::pending ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
exception_ = e;
|
|
||||||
status_ = status::rejected;
|
|
||||||
invoke_reject_handlers_();
|
|
||||||
cond_var_.notify_all();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void get() {
|
void get() {
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock lock(mutex_);
|
||||||
cond_var_.wait(lock, [this](){
|
cond_var_.wait(lock, [this](){
|
||||||
return status_ != status::pending;
|
return status_ != status::pending;
|
||||||
});
|
});
|
||||||
@@ -825,42 +831,54 @@ namespace promise_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
void wait() const noexcept {
|
void wait() const noexcept {
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock lock(mutex_);
|
||||||
cond_var_.wait(lock, [this](){
|
cond_var_.wait(lock, [this](){
|
||||||
return status_ != status::pending;
|
return status_ != status::pending;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Rep, typename Period >
|
template < typename Rep, typename Period >
|
||||||
promise_wait_status wait_for(
|
promise_wait_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const {
|
||||||
const std::chrono::duration<Rep, Period>& timeout_duration) const
|
std::unique_lock lock(mutex_);
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
|
||||||
return cond_var_.wait_for(lock, timeout_duration, [this](){
|
return cond_var_.wait_for(lock, timeout_duration, [this](){
|
||||||
return status_ != status::pending;
|
return status_ != status::pending;
|
||||||
}) ? promise_wait_status::no_timeout
|
}) ? promise_wait_status::no_timeout : promise_wait_status::timeout;
|
||||||
: promise_wait_status::timeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Clock, typename Duration >
|
template < typename Clock, typename Duration >
|
||||||
promise_wait_status wait_until(
|
promise_wait_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const {
|
||||||
const std::chrono::time_point<Clock, Duration>& timeout_time) const
|
std::unique_lock lock(mutex_);
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
|
||||||
return cond_var_.wait_until(lock, timeout_time, [this](){
|
return cond_var_.wait_until(lock, timeout_time, [this](){
|
||||||
return status_ != status::pending;
|
return status_ != status::pending;
|
||||||
}) ? promise_wait_status::no_timeout
|
}) ? promise_wait_status::no_timeout : promise_wait_status::timeout;
|
||||||
: promise_wait_status::timeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool resolve() {
|
||||||
|
std::lock_guard guard(mutex_);
|
||||||
|
if ( status_ != status::pending ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
status_ = status::resolved;
|
||||||
|
invoke_resolve_handlers_();
|
||||||
|
cond_var_.notify_all();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reject(std::exception_ptr e) noexcept {
|
||||||
|
std::lock_guard guard(mutex_);
|
||||||
|
if ( status_ != status::pending ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
exception_ = e;
|
||||||
|
status_ = status::rejected;
|
||||||
|
invoke_reject_handlers_();
|
||||||
|
cond_var_.notify_all();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public:
|
||||||
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(
|
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject, bool has_reject) {
|
||||||
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),
|
||||||
@@ -893,18 +911,13 @@ namespace promise_hpp
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard guard(mutex_);
|
||||||
add_handlers_(std::move(resolve_h), std::move(reject_h));
|
add_handlers_(std::move(resolve_h), std::move(reject_h));
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject, bool has_reject) {
|
||||||
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),
|
||||||
@@ -937,7 +950,7 @@ namespace promise_hpp
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
std::lock_guard guard(mutex_);
|
||||||
add_handlers_(std::move(resolve_h), std::move(reject_h));
|
add_handlers_(std::move(resolve_h), std::move(reject_h));
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@@ -951,9 +964,9 @@ namespace promise_hpp
|
|||||||
std::forward<RejectF>(reject),
|
std::forward<RejectF>(reject),
|
||||||
exception_);
|
exception_);
|
||||||
} else {
|
} else {
|
||||||
handlers_.emplace_back(
|
handlers_.push_back({
|
||||||
std::forward<ResolveF>(resolve),
|
std::forward<ResolveF>(resolve),
|
||||||
std::forward<RejectF>(reject));
|
std::forward<RejectF>(reject)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -989,17 +1002,15 @@ namespace promise_hpp
|
|||||||
|
|
||||||
resolve_t resolve_;
|
resolve_t resolve_;
|
||||||
reject_t reject_;
|
reject_t reject_;
|
||||||
|
|
||||||
template < typename ResolveF, typename RejectF >
|
|
||||||
handler(ResolveF&& resolve, RejectF&& reject)
|
|
||||||
: resolve_(std::forward<ResolveF>(resolve))
|
|
||||||
, reject_(std::forward<RejectF>(reject)) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<handler> handlers_;
|
std::vector<handler> handlers_;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace promise_hpp
|
||||||
|
{
|
||||||
//
|
//
|
||||||
// swap
|
// swap
|
||||||
//
|
//
|
||||||
@@ -1099,7 +1110,7 @@ namespace promise_hpp
|
|||||||
std::vector<ResultType> ret;
|
std::vector<ResultType> ret;
|
||||||
ret.reserve(results_.size());
|
ret.reserve(results_.size());
|
||||||
for ( auto&& v : results_ ) {
|
for ( auto&& v : results_ ) {
|
||||||
ret.emplace_back(v.get());
|
ret.push_back(v.get());
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1209,7 +1220,7 @@ namespace promise_hpp
|
|||||||
private:
|
private:
|
||||||
template < std::size_t... Is >
|
template < std::size_t... Is >
|
||||||
std::tuple<ResultTypes...> get_results_impl(std::index_sequence<Is...>) {
|
std::tuple<ResultTypes...> get_results_impl(std::index_sequence<Is...>) {
|
||||||
return std::make_tuple(std::get<Is>(results_).get()...);
|
return {std::get<Is>(results_).get()...};
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::atomic_size_t counter_{0};
|
std::atomic_size_t counter_{0};
|
||||||
@@ -1291,7 +1302,7 @@ namespace promise_hpp
|
|||||||
make_tuple_promise(Tuple&& tuple) {
|
make_tuple_promise(Tuple&& tuple) {
|
||||||
return impl::make_tuple_promise_impl(
|
return impl::make_tuple_promise_impl(
|
||||||
std::forward<Tuple>(tuple),
|
std::forward<Tuple>(tuple),
|
||||||
std::make_index_sequence<std::tuple_size<ResultTuple>::value>());
|
std::make_index_sequence<std::tuple_size_v<ResultTuple>>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -202,6 +202,30 @@ TEST_CASE("promise") {
|
|||||||
REQUIRE(check_100500_transform == 100500);
|
REQUIRE(check_100500_transform == 100500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SECTION("resolved_ref") {
|
||||||
|
{
|
||||||
|
int* check_42_int = nullptr;
|
||||||
|
auto p = pr::promise<int&>();
|
||||||
|
int i = 42;
|
||||||
|
p.resolve(i);
|
||||||
|
p.then([&check_42_int](int& value) mutable {
|
||||||
|
check_42_int = &value;
|
||||||
|
});
|
||||||
|
REQUIRE(check_42_int);
|
||||||
|
REQUIRE(*check_42_int == 42);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const int* check_42_int = nullptr;
|
||||||
|
auto p = pr::promise<const int&>();
|
||||||
|
const int i = 42;
|
||||||
|
p.resolve(i);
|
||||||
|
p.then([&check_42_int](const int& value) mutable {
|
||||||
|
check_42_int = &value;
|
||||||
|
});
|
||||||
|
REQUIRE(check_42_int);
|
||||||
|
REQUIRE(*check_42_int == 42);
|
||||||
|
}
|
||||||
|
}
|
||||||
SECTION("rejected") {
|
SECTION("rejected") {
|
||||||
{
|
{
|
||||||
bool call_fail_with_logic_error = false;
|
bool call_fail_with_logic_error = false;
|
||||||
@@ -867,6 +891,21 @@ TEST_CASE("promise") {
|
|||||||
return std::make_tuple(std::move(p1), std::move(p2));
|
return std::make_tuple(std::move(p1), std::move(p2));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
auto p1 = pr::promise<int&>();
|
||||||
|
auto p2 = pr::promise<float&>();
|
||||||
|
auto p3 = pr::make_tuple_promise(std::make_tuple(p1, p2));
|
||||||
|
|
||||||
|
int i = 10;
|
||||||
|
float f = 0.f;
|
||||||
|
p1.resolve(i);
|
||||||
|
p2.resolve(f);
|
||||||
|
|
||||||
|
p3.then([&i,&f](const std::tuple<int&, float&>& t){
|
||||||
|
REQUIRE(&std::get<0>(t) == &i);
|
||||||
|
REQUIRE(&std::get<1>(t) == &f);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SECTION("make_all_promise_fail") {
|
SECTION("make_all_promise_fail") {
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user