Improve cti::split and make it workable with plain callbacks

This commit is contained in:
Denis Blank 2019-03-11 16:39:35 +01:00
parent daa2fdd686
commit bc4d69735c
2 changed files with 40 additions and 19 deletions

View File

@ -36,10 +36,27 @@
#include <continuable/continuable-base.hpp> #include <continuable/continuable-base.hpp>
#include <continuable/continuable-traverse.hpp> #include <continuable/continuable-traverse.hpp>
#include <continuable/continuable-types.hpp> #include <continuable/continuable-types.hpp>
#include <continuable/detail/utility/traits.hpp>
namespace cti { namespace cti {
namespace detail { namespace detail {
namespace operations { namespace operations {
template <typename T, bool Else, typename = void>
struct operator_bool_or {
template <typename O>
static bool get(O&& /*obj*/) noexcept {
return Else;
}
};
template <typename T, bool Else>
struct operator_bool_or<T, Else,
traits::void_t<decltype(bool(std::declval<T&>()))>> {
template <typename O>
static bool get(O&& obj) noexcept {
return bool(obj);
}
};
template <typename First, typename... Promises> template <typename First, typename... Promises>
class split_promise { class split_promise {
First first_; First first_;
@ -51,34 +68,22 @@ public:
} }
template <typename... Args> template <typename... Args>
void operator()(Args... args) && { void operator()(Args&&... args) && {
traverse_pack( traverse_pack(
[&](auto&& promise) mutable -> void { [&](auto&& promise) mutable -> void {
if (promise) { using accessor =
operator_bool_or<traits::unrefcv_t<decltype(promise)>, true>;
if (accessor::get(promise)) {
std::forward<decltype(promise)>(promise)(args...); std::forward<decltype(promise)>(promise)(args...);
} }
}, },
std::move(promises_)); std::move(promises_));
if (first_) { if (operator_bool_or<First, true>::get(first_)) {
std::move(first_)(std::forward<Args>(args)...); std::move(first_)(std::forward<Args>(args)...);
} }
} }
void operator()(exception_arg_t tag, exception_t exception) && {
traverse_pack(
[&](auto&& promise) mutable -> void {
if (promise) {
std::forward<decltype(promise)>(promise)(tag, exception);
}
},
std::move(promises_));
if (first_) {
std::move(first_)(tag, std::move(exception));
}
}
template <typename... Args> template <typename... Args>
void set_value(Args... args) { void set_value(Args... args) {
std::move (*this)(std::move(args)...); std::move (*this)(std::move(args)...);
@ -89,10 +94,12 @@ public:
} }
explicit operator bool() const noexcept { explicit operator bool() const noexcept {
bool is_valid = bool(first_); bool is_valid = operator_bool_or<First, true>::get(first_);
traverse_pack( traverse_pack(
[&](auto&& promise) mutable -> void { [&](auto&& promise) mutable -> void {
if (!is_valid && bool(promise)) { using accessor =
operator_bool_or<traits::unrefcv_t<decltype(promise)>, true>;
if (!is_valid && accessor::get(promise)) {
is_valid = true; is_valid = true;
} }
}, },

View File

@ -46,3 +46,17 @@ TYPED_TEST(single_dimension_tests, operations_split) {
all.set_value(); all.set_value();
ASSERT_TRUE(resolved); ASSERT_TRUE(resolved);
} }
TYPED_TEST(single_dimension_tests, operations_split_plain_callback) {
promise<> all;
bool resolved = false;
all = split(std::move(all), [&](auto&&...) {
EXPECT_FALSE(resolved);
resolved = true;
});
ASSERT_FALSE(resolved);
all.set_value();
ASSERT_TRUE(resolved);
}