[#race]
== cobalt/race.hpp

The `race` function can be used to `co_await` one <<awaitable, awaitable>> out of a set of them.

It can be called as a variadic function with multiple <<awaitable, awaitable>> or as on a range of <<awaitable, awaitables>>.

[source,cpp]
----
cobalt::promise<void> task1();
cobalt::promise<void> task2();

cobalt::promise<void> do_wait()
{
  co_await cobalt::race(task1(), task2()); // <1>
  std::vector<cobalt::promise<void>> aws {task1(), task2()};
  co_await cobalt::race(aws); // <2>
}
----
<1> Wait for a variadic set of <<awaitable, awaitables>>
<2> wait for a vector of <<awaitable, awaitables>>

The first parameter so `race` can be a https://en.cppreference.com/w/cpp/named_req/UniformRandomBitGenerator[uniform random bit generator].


.Signatures of race
[source, cpp]
----
extern promise<void> pv1, pv2;
std::vector<promise<void>> pvv;

std::default_random_engine rdm{1};
// if everything returns void race returns the index
std::size_t r1 = co_await race(pv1, pv2);
std::size_t r2 = co_await race(rdm, pv1, pv2);
std::size_t r3 = co_await race(pvv);
std::size_t r4 = co_await race(rdm, pvv);

// variant if not everything is void. void become monostate
extern promise<int> pi1, pi2;
variant2::variant<monostate, int, int> r5 = co_await race(pv1, pi1, pi2);
variant2::variant<monostate, int, int> r6 = co_await race(rdm, pv1, pi1, pi2);

// a range returns a pair of the index and the result if non-void
std::vector<promise<int>> piv;
std::pair<std::size_t, int> r7 = co_await race(piv);
std::pair<std::size_t, int> r8 = co_await race(rdm, piv);
----

[#interrupt_await]
=== Interrupt Wait

When arguments are passed as rvalue reference, the race will attempt to use `.interrupt_await`
on the <<awaitable, awaitable>> to signal the awaitable to complete now and that the result will be ignored.
If supported, the <<awaitable>> must resume the awaiting coroutine before `interrupt_await` returns.
If the `race` doesn't detect the function, it will send a cancellation.

This means that you can reuse race like this:

[source,cpp]
----

cobalt::promise<void> do_wait()
{
  auto t1 = task1();
  auto t2 = task2();
  co_await cobalt::race(t1, t2); // <1>
  co_await cobalt::race(t1, t2); // <2>
}
----
<1> Wait for the first task to complete
<2> Wait for the other task to complete

This is supported by <<promise, promise>>, <<generator, generator>> and <<gather, gather>>.

The `race` will invoke the functions of the `awaitable` as if used in a `co_await` expression
or not evaluate them at all.

[#left_race]
=== `left_race`

The `left_race` functions are like `race` but follow a strict left-to-right scan.
This can lead to starvation issues, which is why this is not the recommended default, but can
be useful for prioritization if proper care is taken.


[#race-outline]
=== Outline

[source,cpp,subs=+quotes]
----
// Concept for the random number generator.
include::../../include/boost/cobalt/race.hpp[tag=concept]

// Variadic race with a custom random number generator
template<asio::cancellation_type Ct = asio::cancellation_type::all,
         uniform_random_bit_generator URBG, awaitable ... Promise>
__awaitable__ race(URBG && g, Promise && ... p);

// Ranged race with a custom random number generator
template<asio::cancellation_type Ct = asio::cancellation_type::all,
         uniform_random_bit_generator URBG, range<awaitable> PromiseRange>
__awaitable__ race(URBG && g, PromiseRange && p);

// Variadic race with the default random number generator
template<asio::cancellation_type Ct = asio::cancellation_type::all, awaitable... Promise>
__awaitable__ race(Promise && ... p);

// Ranged race with the default random number generator
template<asio::cancellation_type Ct = asio::cancellation_type::all, range<awaitable>>
__awaitable__ race(PromiseRange && p);

// Variadic left race
template<asio::cancellation_type Ct = asio::cancellation_type::all, awaitable... Promise>
__awaitable__ left_race(Promise && ... p);

// Ranged left race
template<asio::cancellation_type Ct = asio::cancellation_type::all, range<awaitable>>
__awaitable__ left_race(PromiseRange && p);
----

NOTE: Selecting an empty range will cause an exception to be thrown.