Merge pull request #31 from BlackMATov/dev

Dev
This commit is contained in:
2019-12-30 04:13:25 +07:00
committed by GitHub
3 changed files with 390 additions and 340 deletions

View File

@@ -10,14 +10,14 @@
[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.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.paypal]: https://img.shields.io/badge/donate-PayPal-orange.svg?logo=paypal&colorA=00457C
[travis]: https://travis-ci.org/BlackMATov/promise.hpp
[appveyor]: https://ci.appveyor.com/project/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
[paypal]: https://www.paypal.me/matov

View File

@@ -53,6 +53,9 @@ namespace promise_hpp
struct is_promise
: 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
//
@@ -72,6 +75,9 @@ namespace promise_hpp
struct is_promise_r
: 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
//
@@ -93,29 +99,37 @@ namespace promise_hpp
storage() = default;
~storage()
noexcept(std::is_nothrow_destructible<T>::value)
{
noexcept(std::is_nothrow_destructible_v<T>) {
if ( initialized_ ) {
ptr_()->~T();
}
}
template < typename U >
void set(U&& value)
noexcept(std::is_nothrow_constructible<T,U&&>::value)
{
void set(T&& value)
noexcept(std::is_nothrow_move_constructible_v<T>) {
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;
}
T get()
noexcept(std::is_nothrow_move_constructible<T>::value)
{
noexcept(std::is_nothrow_move_constructible_v<T>) {
assert(initialized_);
return std::move(*ptr_());
}
T& value() noexcept {
assert(initialized_);
return *ptr_();
}
const T& value() const noexcept {
assert(initialized_);
return *ptr_();
@@ -132,6 +146,37 @@ namespace promise_hpp
std::aligned_storage_t<sizeof(T), alignof(T)> data_;
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,
timeout
};
}
//
// promise<T>
//
// -----------------------------------------------------------------------------
//
// promise<T>
//
// -----------------------------------------------------------------------------
namespace promise_hpp
{
template < typename T >
class promise final {
public:
using value_type = T;
public:
promise()
: state_(std::make_shared<state>()) {}
promise(const promise&) noexcept = default;
promise& operator=(const promise&) noexcept = default;
promise(promise&&) = default;
promise& operator=(promise&&) = default;
promise(const promise&) = default;
promise& operator=(const promise&) = default;
void swap(promise& other) noexcept {
state_.swap(other.state_);
@@ -178,50 +231,80 @@ namespace promise_hpp
return l.state_ != r.state_;
}
template < typename ResolveF
, typename ResolveFR = std::invoke_result_t<ResolveF,T> >
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;
//
// get
//
then([
n = next,
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;
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);
}
}
//
// 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
, typename ResolveFR = std::invoke_result_t<ResolveF,T> >
, typename ResolveR = std::invoke_result_t<ResolveF, T> >
std::enable_if_t<
is_promise<ResolveFR>::value && !std::is_void<typename ResolveFR::value_type>::value,
promise<typename ResolveFR::value_type>>
is_promise_v<ResolveR>,
promise<typename ResolveR::value_type>>
then(ResolveF&& on_resolve) {
promise<typename ResolveFR::value_type> next;
promise<typename ResolveR::value_type> next;
then([
n = next,
f = std::forward<ResolveF>(on_resolve)
](auto&& v) mutable {
](auto&&... vs) mutable {
auto np = std::invoke(
std::forward<decltype(f)>(f),
std::forward<decltype(v)>(v));
std::move(np).then([n](auto&& nv) mutable {
n.resolve(std::forward<decltype(nv)>(nv));
std::forward<decltype(vs)>(vs)...);
std::move(np).then([n](auto&&... nvs) mutable {
n.resolve(std::forward<decltype(nvs)>(nvs)...);
}).except([n](std::exception_ptr e) mutable {
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
, typename RejectF
, typename ResolveFR = std::invoke_result_t<ResolveF,T> >
, typename ResolveR = std::invoke_result_t<ResolveF, T> >
std::enable_if_t<
!is_promise<ResolveFR>::value,
promise<ResolveFR>>
!is_promise_v<ResolveR>,
promise<ResolveR>>
then(ResolveF&& on_resolve, RejectF&& on_reject) {
promise<ResolveFR> next;
promise<ResolveR> next;
state_->attach(
next,
std::forward<ResolveF>(on_resolve),
std::forward<RejectF>(on_reject),
true);
return next;
}
template < typename ResolveF
, typename ResolveFR = std::invoke_result_t<ResolveF,T> >
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;
}
//
// except
//
template < typename RejectF >
promise<T> except(RejectF&& on_reject) {
@@ -307,52 +400,6 @@ namespace promise_hpp
[](auto&& v) { return std::forward<decltype(v)>(v); },
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:
class state;
std::shared_ptr<state> state_;
@@ -361,33 +408,8 @@ namespace promise_hpp
public:
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() {
std::unique_lock<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
cond_var_.wait(lock, [this](){
return status_ != status::pending;
});
@@ -399,42 +421,56 @@ namespace promise_hpp
}
void wait() const noexcept {
std::unique_lock<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
cond_var_.wait(lock, [this](){
return status_ != status::pending;
});
}
template < typename Rep, typename Period >
promise_wait_status wait_for(
const std::chrono::duration<Rep, Period>& timeout_duration) const
{
std::unique_lock<std::mutex> lock(mutex_);
promise_wait_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const {
std::unique_lock lock(mutex_);
return cond_var_.wait_for(lock, timeout_duration, [this](){
return status_ != status::pending;
}) ? promise_wait_status::no_timeout
: promise_wait_status::timeout;
}) ? promise_wait_status::no_timeout : promise_wait_status::timeout;
}
template < typename Clock, typename Duration >
promise_wait_status wait_until(
const std::chrono::time_point<Clock, Duration>& timeout_time) const
{
std::unique_lock<std::mutex> lock(mutex_);
promise_wait_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const {
std::unique_lock lock(mutex_);
return cond_var_.wait_until(lock, timeout_time, [this](){
return status_ != status::pending;
}) ? promise_wait_status::no_timeout
: promise_wait_status::timeout;
}) ? promise_wait_status::no_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 >
std::enable_if_t<std::is_void<U>::value, void>
attach(
promise<U>& next,
ResolveF&& on_resolve,
RejectF&& on_reject,
bool has_reject)
{
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject, bool has_reject) {
auto reject_h = [
n = next,
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));
}
template < typename U, typename ResolveF, typename RejectF >
std::enable_if_t<!std::is_void<U>::value, void>
attach(
promise<U>& next,
ResolveF&& on_resolve,
RejectF&& on_reject,
bool has_reject)
{
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject, bool has_reject) {
auto reject_h = [
n = next,
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));
}
private:
@@ -528,16 +559,15 @@ namespace promise_hpp
std::forward<RejectF>(reject),
exception_);
} else {
handlers_.emplace_back(
handlers_.push_back({
std::forward<ResolveF>(resolve),
std::forward<RejectF>(reject));
std::forward<RejectF>(reject)});
}
}
void invoke_resolve_handlers_() noexcept {
const T& value = storage_.value();
for ( const auto& h : handlers_ ) {
h.resolve_(value);
h.resolve_(storage_.value());
}
handlers_.clear();
}
@@ -567,32 +597,35 @@ namespace promise_hpp
resolve_t resolve_;
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_;
detail::storage<T> storage_;
};
};
}
//
// promise<void>
//
// -----------------------------------------------------------------------------
//
// promise<void>
//
// -----------------------------------------------------------------------------
namespace promise_hpp
{
template <>
class promise<void> final {
public:
using value_type = void;
public:
promise()
: state_(std::make_shared<state>()) {}
promise(const promise&) noexcept = default;
promise& operator=(const promise&) noexcept = default;
promise(promise&&) = default;
promise& operator=(promise&&) = default;
promise(const promise&) = default;
promise& operator=(const promise&) = default;
void swap(promise& other) noexcept {
state_.swap(other.state_);
@@ -614,48 +647,78 @@ namespace promise_hpp
return l.state_ != r.state_;
}
template < typename ResolveF
, typename ResolveFR = std::invoke_result_t<ResolveF> >
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;
//
// get
//
then([
n = next,
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() const {
state_->get();
}
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
, typename ResolveFR = std::invoke_result_t<ResolveF> >
, typename ResolveR = std::invoke_result_t<ResolveF> >
std::enable_if_t<
is_promise<ResolveFR>::value && !std::is_void<typename ResolveFR::value_type>::value,
promise<typename ResolveFR::value_type>>
is_promise_v<ResolveR>,
promise<typename ResolveR::value_type>>
then(ResolveF&& on_resolve) {
promise<typename ResolveFR::value_type> next;
promise<typename ResolveR::value_type> next;
then([
n = next,
f = std::forward<ResolveF>(on_resolve)
]() mutable {
](auto&&... vs) mutable {
auto np = std::invoke(
std::forward<decltype(f)>(f));
std::move(np).then([n](auto&& nv) mutable {
n.resolve(std::forward<decltype(nv)>(nv));
std::forward<decltype(f)>(f),
std::forward<decltype(vs)>(vs)...);
std::move(np).then([n](auto&&... nvs) mutable {
n.resolve(std::forward<decltype(nvs)>(nvs)...);
}).except([n](std::exception_ptr e) mutable {
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
, typename RejectF
, typename ResolveFR = std::invoke_result_t<ResolveF> >
, typename ResolveR = std::invoke_result_t<ResolveF> >
std::enable_if_t<
!is_promise<ResolveFR>::value,
promise<ResolveFR>>
!is_promise_v<ResolveR>,
promise<ResolveR>>
then(ResolveF&& on_resolve, RejectF&& on_reject) {
promise<ResolveFR> next;
promise<ResolveR> next;
state_->attach(
next,
std::forward<ResolveF>(on_resolve),
std::forward<RejectF>(on_reject),
true);
return next;
}
template < typename ResolveF
, typename ResolveFR = std::invoke_result_t<ResolveF> >
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;
}
//
// except
//
template < typename RejectF >
promise<void> except(RejectF&& on_reject) {
return then(
[]{},
[](){},
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:
class state;
std::shared_ptr<state> state_;
@@ -790,31 +819,8 @@ namespace promise_hpp
public:
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() {
std::unique_lock<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
cond_var_.wait(lock, [this](){
return status_ != status::pending;
});
@@ -825,42 +831,54 @@ namespace promise_hpp
}
void wait() const noexcept {
std::unique_lock<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
cond_var_.wait(lock, [this](){
return status_ != status::pending;
});
}
template < typename Rep, typename Period >
promise_wait_status wait_for(
const std::chrono::duration<Rep, Period>& timeout_duration) const
{
std::unique_lock<std::mutex> lock(mutex_);
promise_wait_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const {
std::unique_lock lock(mutex_);
return cond_var_.wait_for(lock, timeout_duration, [this](){
return status_ != status::pending;
}) ? promise_wait_status::no_timeout
: promise_wait_status::timeout;
}) ? promise_wait_status::no_timeout : promise_wait_status::timeout;
}
template < typename Clock, typename Duration >
promise_wait_status wait_until(
const std::chrono::time_point<Clock, Duration>& timeout_time) const
{
std::unique_lock<std::mutex> lock(mutex_);
promise_wait_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const {
std::unique_lock lock(mutex_);
return cond_var_.wait_until(lock, timeout_time, [this](){
return status_ != status::pending;
}) ? promise_wait_status::no_timeout
: promise_wait_status::timeout;
}) ? promise_wait_status::no_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 >
std::enable_if_t<std::is_void<U>::value, void>
attach(
promise<U>& next,
ResolveF&& on_resolve,
RejectF&& on_reject,
bool has_reject)
{
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject, bool has_reject) {
auto reject_h = [
n = next,
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));
}
template < typename U, typename ResolveF, typename RejectF >
std::enable_if_t<!std::is_void<U>::value, void>
attach(
promise<U>& next,
ResolveF&& on_resolve,
RejectF&& on_reject,
bool has_reject)
{
attach(promise<U>& next, ResolveF&& on_resolve, RejectF&& on_reject, bool has_reject) {
auto reject_h = [
n = next,
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));
}
private:
@@ -951,9 +964,9 @@ namespace promise_hpp
std::forward<RejectF>(reject),
exception_);
} else {
handlers_.emplace_back(
handlers_.push_back({
std::forward<ResolveF>(resolve),
std::forward<RejectF>(reject));
std::forward<RejectF>(reject)});
}
}
@@ -989,17 +1002,15 @@ namespace promise_hpp
resolve_t resolve_;
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_;
};
};
}
namespace promise_hpp
{
//
// swap
//
@@ -1099,7 +1110,7 @@ namespace promise_hpp
std::vector<ResultType> ret;
ret.reserve(results_.size());
for ( auto&& v : results_ ) {
ret.emplace_back(v.get());
ret.push_back(v.get());
}
return ret;
}
@@ -1209,7 +1220,7 @@ namespace promise_hpp
private:
template < std::size_t... 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:
std::atomic_size_t counter_{0};
@@ -1291,7 +1302,7 @@ namespace promise_hpp
make_tuple_promise(Tuple&& tuple) {
return impl::make_tuple_promise_impl(
std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<ResultTuple>::value>());
std::make_index_sequence<std::tuple_size_v<ResultTuple>>());
}
}

View File

@@ -202,6 +202,30 @@ TEST_CASE("promise") {
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") {
{
bool call_fail_with_logic_error = false;
@@ -867,6 +891,21 @@ TEST_CASE("promise") {
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") {
{