stlab 2.3.0
Modern, modular C++ algorithms, data structures, and concurrency primitives
Loading...
Searching...
No Matches
future.hpp File Reference

Futures, packaged tasks, channels, and coroutine integration. More...

#include <stlab/config.hpp>
#include <algorithm>
#include <array>
#include <atomic>
#include <cassert>
#include <cstdint>
#include <exception>
#include <functional>
#include <initializer_list>
#include <memory>
#include <mutex>
#include <optional>
#include <utility>
#include <variant>
#include <vector>
#include <stlab/concurrency/executor_base.hpp>
#include <stlab/concurrency/immediate_executor.hpp>
#include <stlab/concurrency/task.hpp>
#include <stlab/concurrency/traits.hpp>
#include <stlab/concurrency/tuple_algorithm.hpp>
#include <stlab/functional.hpp>
#include <stlab/memory.hpp>
#include <stlab/utility.hpp>

Go to the source code of this file.

Classes

struct  stlab::void_to_monostate< T >
 Maps void to std::monostate for uniform future result storage; other types unchanged. More...
class  stlab::future_error
 Exception thrown when a future-related contract is violated (e.g. broken_promise, no_state). More...
class  stlab::packaged_task< Args >
 Invocable that completes a future when called with arguments of type Args...; created by package(). More...
class  stlab::future< T, enable_if_copyable< void_to_monostate_t< T > > >
 Consumer side of a one-shot result (copyable T). More...
class  stlab::future< T, enable_if_not_copyable< void_to_monostate_t< T > > >
 Consumer side of a one-shot result (non-copyable T). Use get_ready() or get_try(); then/recover only on rvalue. More...
struct  stlab::make_when_any< T >
 Helper to implement when_any for result type T. More...
struct  stlab::make_when_any< void >
 Helper to implement when_any for void results. More...

Typedefs

template<class T>
using stlab::void_to_monostate_t
 Alias for void_to_monostate<T>::type.

Enumerations

enum class  stlab::future_error_codes : std::uint8_t { stlab::future_error_codes::broken_promise , stlab::future_error_codes::no_state }
 Error codes for future_error. More...

Functions

template<class F, class... Args>
auto stlab::invoke_void_to_monostate_result (F &&f, Args &&... args)
 Invokes f with args and returns its result, or std::monostate{} if the result is void.
template<class T>
auto stlab::optional_monostate_to_bool (std::optional< T > &&o)
 Returns o.has_value() when T is std::monostate, otherwise std::move(o).
template<class T>
auto stlab::monostate_to_void (T &&a)
 Converts std::monostate to void (no return); forwards other types unchanged.
template<class T>
auto stlab::monostate_to_empty_tuple (T &&a)
 Converts std::monostate to std::tuple{}; wraps other types in std::tuple for uniform application.
template<class F, class... Args>
auto stlab::invoke_remove_monostate_arguments (F &&f, Args &&... args)
 Invokes f with args after removing std::monostate values (for void future results).
template<class Sig, class E, class F>
auto stlab::package (E executor, F &&f) -> std::pair< detail::packaged_task_from_signature_t< Sig >, detail::reduced_result_t< Sig > >
 Creates a packaged task and its future for the callable f, run on executor.
template<class T, class E>
auto stlab::future_with_broken_promise (E executor) -> detail::reduced_t< T >
 Returns a future of type T that is already ready with a broken_promise error (e.g. for canceled work).
template<class E, class F, class... Ts>
auto stlab::when_all (const E &executor, F f, future< Ts >... args)
 Returns a future that completes when all input futures are ready; f receives their values.
template<class E, class F, class T, class... Ts>
auto stlab::when_any (E &&executor, F &&f, future< T > &&arg, future< Ts > &&... args)
 Returns a future that completes when any of the given futures is ready; f receives the value and the index of the future that completed first (as a second argument of type std::size_t).
template<class E, class F, class I>
auto stlab::when_all (const E &executor, F f, std::pair< I, I > range)
 Returns a future that completes when all futures in [range.first, range.second) are ready; f receives their values.
template<class E, class F, class I>
auto stlab::when_any (const E &executor, F &&f, std::pair< I, I > range)
 Returns a future that completes when any future in [range.first, range.second) is ready; f receives the result and the index of the future that completed first (as a second argument of type std::size_t).
template<class E, class F, class... Args>
auto stlab::async (const E &executor, F &&f, Args &&... args) -> detail::reduced_t< detail::result_t< std::decay_t< F >, std::decay_t< Args >... > >
 Runs f with args on executor and returns a future for the result.

Variables

template<class T>
constexpr bool stlab::is_monostate_v
 True if T is std::monostate.

Detailed Description

Futures, packaged tasks, channels, and coroutine integration.

Asynchronous one-shot results: futures and packaged tasks.

future<T> is the consumer side: it eventually holds a value or an exception. packaged_task<Args...> is the producer side: an invocable that, when called, runs a callable and completes its associated future with the result. You create a task and its future together with package<Sig>(executor, f). Return types are auto-reduced: a future<future<T>> is flattened to future<T>, so continuations and package() never expose nested futures.

Lifecycle and cancellation: if a future is destroyed before the result is produced, the other side can observe cancellation (future_error_codes::broken_promise). If a packaged_task is destroyed without being invoked, its future is completed with broken_promise. Thus tasks are effectively canceled when their future or packaged_task is destroyed. A packaged_task can call canceled() to see if the future was already released.

Futures to copyable types are copyable; you can attach multiple continuations via then(), recover(), |, or ^ from the same future. Futures to non-copyable types are move-only and support a single continuation (use std::move(f).then(...)). then(f) runs when the future has a value; recover(f) runs when the future is ready (value or exception), so you can handle errors. Continuations run on an executor (default or explicit). Use when_all and when_any to combine futures; use async(executor, f, args...) to run a function on an executor and get a future for its result. Obtain the value with get_ready() (if the future is known to be ready) or get_try() (returns immediately with value or empty); call detach() to drop the future without cancelling the associated task.

Coroutines: a function returning future<T> can use co_return and co_await. Use co_await std::move(f) to await a future (resumption happens in the thread that completes the future). Use co_await resume_on(executor, std::move(f)) to resume the current coroutine on a specific executor when the future completes.

Compared with std::future: copyable value types need no shared_future; there is no blocking wait()/get()—use get_try() / get_ready() or continuations. then() is const and may be called multiple times on copyable futures (a split); continuations receive the value type, not a future. Sink arguments should be taken by value and moved; read-only use const&; modifying through a non-const reference is undefined. When the last future is destroyed, the associated task and argument futures are released and an uninvoked packaged_task becomes a no-op.

Specialize stlab::smart_test when T is e.g. std::vector<std::unique_ptr<>> so move-only dispatch is correct (std::is_copy_constructible is defective for such types).