Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

execution::staging_executor

An executor adapter that records properties rather than applying them.

template<
    typename Executor,
    typename... Properties>
class staging_executor
Types

Name

Description

committed_executor_type

The type of executor that results from committing.

inner_executor_type

The type of the target executor.

Member Functions

Name

Description

commit

Apply the recorded properties to the target.

execute

Apply the recorded properties and submit a function object.

get_inner_executor

Obtain a reference to the target executor.

operator OtherExecutor

Convert to an owning executor by committing.

prefer

Record a preference.

query

Query the recorded allocator property.
—
Forward a query to the target executor.

query [static]

Query the recorded blocking property.
—
Query the recorded relationship property.

require

Record a property.

staging_executor [constructor]

Construct a staging executor for the specified target.
—
Copy constructor.
—
Move constructor.

Friends

Name

Description

operator!=

Compare two staging executors for inequality.

operator==

Compare two staging executors for equality.

A staging_executor refers to, or owns, a target executor. Calls to boost::asio::require and boost::asio::prefer on a staging executor do not touch the target. Instead, they return a new staging executor that records the property at the end of a sequence. The recorded properties are applied together, to the target itself, only when a function object is submitted using execute(), or when the staging executor is committed to an ordinary executor.

This avoids producing a sequence of intermediate executors when several properties are applied before a function object is submitted. The saving is greatest when the target is a polymorphic executor such as any_io_executor, where each intermediate result would otherwise be a newly constructed polymorphic wrapper.

Ownership

The Executor template parameter determines whether the target is owned:

Recorded properties

The Properties template parameter pack holds the recorded properties, in the order in which they were requested. A property that was required appears as the property's own type, such as execution::blocking_t::never_t, and a property P that was preferred appears as execution::prefer_only<P>. The recorded properties are applied in request order: the first is applied to the target, and each one after it to the result of the one before.

Each property is recorded under a key, which is the type the property is queried as where it has one, such as execution::blocking_t for execution::blocking_t::never_t, and the property's own type otherwise. A preference keys to the same entry as the corresponding requirement. Recording a property replaces the entry already holding its key, in the position that entry was first recorded in, so the sequence holds at most one entry per key. Only the last of the properties sharing a key is therefore applied, and the order of the entries is the order in which their keys were first requested.

A consequence is that the set of staging executor types that recording properties can reach is closed, which matters where a staging executor is reachable behind a polymorphic executor: such an executor applies every property it supports to every target it adopts, and adopts each result in turn.

A require is offered only when the resulting sequence is valid when applied to the target in that order. A preference that the target would not act upon, whether because it already has the property or because it does not support it, returns the staging executor unchanged.

Queries

A query that a recorded property answers is answered from the most recently recorded such property. All other queries are forwarded to the target.

Direct execution

The combinations that a polymorphic executor can apply to the executor it holds without constructing another polymorphic executor are recognised without regard to the order in which their entries were recorded, as the polymorphic executor applies the blocking requirement before the relationship preference in either case.

Example
void post_to(const boost::asio::any_io_executor& ex, F f)
{
  // No intermediate any_io_executor objects are created.
  boost::asio::prefer(
      boost::asio::require(execution::stage(ex), execution::blocking.never),
      execution::relationship.fork
    ).execute(std::move(f));
}
Requirements

Header: boost/asio/execution/staging_executor.hpp

Convenience header: boost/asio/execution.hpp


PrevUpHomeNext