in demo_example/asio/asio/experimental/promise.hpp [299:389]
static auto race(Executor1 exec, Range range)
{
using var_t = typename std::decay_t<
decltype(*std::begin(range))>::value_type;
using signature_type = std::conditional_t<
std::is_same_v<var_t, std::monostate>,
void(std::size_t),
void(std::size_t, var_t)>;
using pi = detail::promise_impl<signature_type, Executor1>;
using promise_t = promise<signature_type, Executor1>;
struct impl_t : pi
{
impl_t(Executor1 exec, Range&& range)
: pi(std::move(exec)),
range(std::move(range))
{
this->slot.template emplace<cancel_handler>(this);
}
struct cancel_handler
{
impl_t* self;
cancel_handler(impl_t* self)
: self(self)
{
}
void operator()(asio::cancellation_type ct)
{
for (auto& r : self->range)
r.cancel(ct);
}
};
Range range;
cancellation_slot slot{this->cancel.slot()};
};
const auto size = std::distance(std::begin(range), std::end(range));
auto impl = std::allocate_shared<impl_t>(
get_associated_allocator(exec), exec, std::move(range));
impl->executor = exec;
if (size == 0u)
{
if constexpr (std::is_same_v<var_t, std::monostate>)
impl->result = {-1};
else
impl->result = {-1, var_t{}};
impl->done = true;
if (auto f = std::exchange(impl->completion, nullptr); !!f)
{
asio::post(exec,
[impl, f = std::move(f)]() mutable
{
std::apply(std::move(f), std::move(*impl->result));
});
}
return promise_t{impl};
}
auto idx = 0u;
for (auto& val : impl->range)
{
val.async_wait(
bind_executor(exec,
[idx, impl]<typename... Args>(Args&&... args)
{
if (impl->done)
return;
if constexpr (std::is_same_v<var_t, std::monostate>)
impl->result = idx;
else
impl->result = std::make_tuple(idx,
var_t(std::forward<Args>(args)...));
impl->done = true;
if (auto f = std::exchange(impl->completion, nullptr); !!f)
std::apply(std::move(f), std::move(*impl->result));
auto jdx = 0u;
for (auto &tc : impl->range)
if (jdx++ != idx)
tc.cancel();
}));
idx++;
}
return promise_t{impl};
}