Doc. no:  N4243 
Date:     2014-10-13
Revises:  N2175
Reply-To: Christopher Kohlhoff <chris@kohlhoff.com>

Networking Library Proposal (Revision 2)

1. Introduction

In the June 2014 committee meeting in Rapperswil, LEWG requested that Boost.Asio-based N2175 Networking Library Proposal for TR2 (Revision 1) be updated for C++14 and brought forward as a proposed Networking Technical Specification. This document is that revision. As well as updating the proposal for C++14, it incorporates improvements to Asio that are based on the widespread field experience accumulated since 2007.

The Boost.Asio library, from which this proposal is derived, has been deployed in numerous systems, from large (including internet-facing HTTP servers, instant messaging gateways and financial markets applications) to small (mobile phones and embedded systems). The Asio library supports, or has been ported to, many operating systems including Linux, Mac OS X, Windows (native), Windows Runtime, Solaris, FreeBSD, NetBSD, OpenBSD, HP-UX, Tru64, AIX, iOS, Android, WinCE, Symbian, vxWorks and QNX Neutrino.

2. Reference implementation

An almost complete implementation of the proposal text may be found in a variant of Asio that stands alone from Boost. This variant is available at https://github.com/chriskohlhoff/asio/tree/master.

3. Library examples

Unfamiliar readers are encouraged to look to the Boost.Asio documentation and examples for a more complete picture of the use of the libary.

However, to give some idea of the flavour of the proposed library, consider the following sample code. This is part of a server program that echoes the characters it receives back to the client in upper case.

template <typename Iterator>
void uppercase(Iterator begin, Iterator end)
{
  std::locale loc("");
  for (Iterator iter = begin; iter != end; ++iter)
    *iter = std::toupper(*iter, loc);
}

void sync_connection(tcp::socket& socket)
{
  try
  {
    std::vector<char> buffer_space(1024);
    for (;;)
    {
      std::size_t length = socket.read_some(buffer(buffer_space));
      uppercase(buffer_space.begin(), buffer_space.begin() + length);
      write(socket, buffer(buffer_space, length));
    }
  }
  catch (std::system_error& e)
  {
    // ...
  }
}

The synchronous operations used above are functions that do not return control to the caller until the corresponding operating system operation completes. In Asio-based programs their use cases typically fall into two categories:

  • Simple programs that do not care about timeouts, or are happy to rely on the timeout behaviour provided by the underlying operating system.
  • Programs that require fine grained control over system calls, and are aware of the conditions under which synchronous operations will or will not block.

Next, the equivalent code developed using asynchronous operations might look something like this:

class async_connection
  : public std::enable_shared_from_this<async_connection>
{
public:
  async_connection(tcp::socket socket)
    : socket_(std::move(socket))
  {
  }

  void start()
  {
    do_read();
  }

private:
  void do_read()
  {
    auto self(shared_from_this());
    socket_.async_read_some(buffer(buffer_space_),
        [this, self](std::error_code ec, std::size_t length)
        {
          if (!ec)
          {
            uppercase(buffer_space_.begin(), buffer_space_.begin() + length);
            do_write(length);
          }
        });
  }

  void do_write(std::size_t length)
  {
    auto self(shared_from_this());
    async_write(socket_, buffer(buffer_space_, length),
        [this, self](std::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            do_read();
          }
        });
  }

  tcp::socket socket_;
  std::vector<char> buffer_space_{1024};
};

Asynchronous operations do not block the caller, but instead involve the delivery of a notification to the program when the corresponding operating system operation completes. Most non-trivial Asio-based programs will make use of asynchronous operations.

While the code may appear more complex due to the inverted flow of control, it allows a knowledgeable programmer to write code that will scale to a great many concurrent connections. However, this proposal uses the asynchronous model described in [N4045]. This is an extensible model that allows the asynchronous operations to support a variety of composition and notification mechanisms, and these mechanisms may alleviate this complexity. This includes futures:

std::future<std::size_t> fut =
  socket.async_read_some(buffer(buffer_space), use_future);

// ...

std::size_t length = fut.get();

and, through library extensions, coroutines:

void coro_connection(tcp::socket& socket, yield_context yield)
{
  try
  {
    std::vector<char> buffer_space(1024);
    for (;;)
    {
      std::size_t length = socket.async_read_some(buffer(buffer_space), yield);
      uppercase(buffer_space.begin(), buffer_space.begin() + length);
      async_write(socket, buffer(buffer_space, length), yield);
    }
  }
  catch (std::system_error& e)
  {
    // ...
  }
}

Finally, for many applications, networking is not a core feature, nor is it seen as a core competency of the application’s programmers. To cater to these use cases, the proposal provides a high-level interface to TCP sockets that is designed around the familiar C++ I/O streams framework.

Using the library in this way is as easy as opening a stream object with the remote host’s details:

tcp::iostream s("www.boost.org", "http");

Once connected, you send and receive any data as needed. In this case you send a request:

s << "GET / HTTP/1.0\r\n";
s << "Host: www.boost.org\r\n";
s << "Accept: */*\r\n";
s << "Connection: close\r\n\r\n";

Then receive and process the response:

std::string header;
while (std::getline(s, header) && header != "\r")
  std::cout << header << "\n";
std::cout << s.rdbuf();

You can set a timeout to detect unresponsive connections:

s.expires_after(std::chrono::seconds(60));

And, if at any time there is an error, the tcp::iostream class’s error() member function may be used to obtain an error_code that identifies the reason for failure:

if (!s)
{
  std::cout << "Unable to connect: " << s.error().message() << "\n";
  return 1;
}

4. Scope

Problem areas addressed by this proposal include:

  • Networking using TCP and UDP, including support for multicast.
  • Client and server applications.
  • Scalability to handle many concurrent connections.
  • Protocol independence between IPv4 and IPv6.
  • Name resolution (i.e. DNS).
  • Timers.

Features that are considered outside the scope of this proposal include:

  • Protocol implementations such as HTTP, SMTP or FTP.
  • Encryption (e.g. SSL, TLS).
  • Operating system specific demultiplexing APIs.
  • Support for realtime environments.
  • QoS-enabled sockets.
  • Other TCP/IP protocols such as ICMP.
  • Functions and classes for enumerating network interfaces.

5. Target audience

The bulk of the library interface is intended for use by developers with at least some understanding of networking concepts (or a willingness to learn). A high level iostreams interface supports simple use cases and permits novices to develop network code without needing to get into too much depth.

6. Related work

The interface is based on the BSD sockets API, which is widely implemented and supported by extensive literature. It is also used as the basis of networking APIs in other languages (e.g. Java). Unsafe practices of the BSD sockets API, e.g. lack of compile-time type safety, are not included.

Asynchronous support is derived from the Proactor design pattern as implemented by the ADAPTIVE Communication Environment [ACE], and is influenced by the design of the Symbian C++ sockets API [SYMBIAN], which supports synchronous and asynchronous operations side-by-side. The Microsoft .NET socket classes [MS-NET] and the Extended Sockets API [ES-API] developed by The Open Group support similar styles of network programming.

7. Impact on the standard

This is a pure library proposal. It does not add any new language features, nor does it alter any existing standard library headers. It makes additions to experimental headers that may also be modified by other Technical Specifications.

This library can be implemented using compilers that conform to the C++14 standard. An implementation of this library requires operating system-specific functions that lie outside the C++14 standard.

8. Relationship to other proposals

The asynchronous operations defined in this proposal use the asynchronous model described in [N4045]. With the extensible asynchronous model presented in that paper, the user has the ability to select an asynchronous approach that is appropriate to each use case. With these library foundations, a single extensible asynchronous model can support a variety of composition methods, including:

  • Callbacks, where minimal runtime penalty is desirable.
  • Futures, and not just std::future but also future classes supplied by other libraries.
  • Coroutines or resumable functions, without adding new keywords to the language.

To facilitate the coordination of asynchronous operations in multithreaded programs, the asynchronous model also utilises the executors design described in [N4046].

As executors and the extensible asynchronous model are a prerequisite for the networking library, the proposed text below incorporates a complete specification of these facilities.

9. Proposed text

9.1. Definitions
9.1.1. host byte order
9.1.2. network byte order
9.1.3. synchronous operation
9.1.4. asynchronous operation
9.2. Error reporting
9.2.1. Synchronous operations
9.2.2. Asynchronous operations
9.2.3. Error conditions
9.3. Asynchronous model
9.3.1. Header <experimental/type_traits> synopsis
9.3.2. Header <experimental/memory> synopsis
9.3.3. Header <experimental/executor> synopsis
9.3.4. Header <experimental/strand> synopsis
9.3.5. Header <experimental/future> synopsis
9.3.6. Requirements
9.3.6.1. Requirements on asynchronous operations
9.3.6.1.1. Completion tokens and handlers
9.3.6.1.2. Automatic deduction of initiating function return type
9.3.6.1.3. Production of initiating function return value
9.3.6.1.4. Lifetime of initiating function arguments
9.3.6.1.5. I/O executor
9.3.6.1.6. Handler executor
9.3.6.1.7. Outstanding work
9.3.6.1.8. Allocation of intermediate storage
9.3.6.1.9. Execution of handler on completion of asynchronous operation
9.3.6.2. Executor requirements
9.3.6.3. Service requirements
9.3.7. Class template handler_type
9.3.7.1. handler_type members
9.3.8. Class template async_result
9.3.8.1. async_result members
9.3.9. Class template async_completion
9.3.9.1. async_completion members
9.3.10. Class template associated_allocator
9.3.10.1. associated_allocator members
9.3.11. Function get_associated_allocator
9.3.12. Class execution_context
9.3.12.1. execution_context constructor
9.3.12.2. execution_context destructor
9.3.12.3. execution_context operations
9.3.12.4. execution_context protected operations
9.3.12.5. execution_context globals
9.3.13. Class execution_context::service
9.3.13.1. execution_context::service constructors
9.3.13.2. execution_context::service observers
9.3.13.3. execution_context::service operations
9.3.14. Class template is_executor
9.3.15. Executor argument tag
9.3.16. uses_executor
9.3.16.1. uses_executor trait
9.3.16.2. uses-executor construction
9.3.17. Class template associated_executor
9.3.17.1. associated_executor members
9.3.18. Function get_associated_executor
9.3.19. Class template executor_wrapper
9.3.19.1. executor_wrapper constructors
9.3.19.2. executor_wrapper access
9.3.19.3. executor_wrapper invocation
9.3.19.4. Class template specialization async_result
9.3.19.5. Class template specialization associated_allocator
9.3.19.6. Class template specialization associated_executor
9.3.20. Function wrap
9.3.21. Class template executor_work
9.3.21.1. executor_work constructors
9.3.21.2. executor_work destructor
9.3.21.3. executor_work observers
9.3.21.4. executor_work modifiers
9.3.22. Function make_work
9.3.23. Class system_executor
9.3.23.1. system_executor operations
9.3.23.2. system_executor comparisons
9.3.24. Class bad_executor
9.3.24.1. bad_executor constructor
9.3.25. Class executor
9.3.25.1. executor constructors
9.3.25.2. executor assignment
9.3.25.3. executor destructor
9.3.25.4. executor modifiers
9.3.25.5. executor operations
9.3.25.6. executor capacity
9.3.25.7. executor target access
9.3.25.8. executor comparisons
9.3.25.9. executor specialized algorithms
9.3.26. Function dispatch
9.3.27. Function post
9.3.28. Function defer
9.3.29. Class template strand
9.3.29.1. strand constructors
9.3.29.2. strand assignment
9.3.29.3. strand destructor
9.3.29.4. strand operations
9.3.29.5. strand comparisons
9.3.30. Class template use_future_t
9.3.30.1. use_future_t constructors
9.3.30.2. use_future_t members
9.3.30.3. use_future_t traits
9.3.31. Class template specialization async_result for packaged_task
9.3.32. Class template packaged_handler
9.3.32.1. packaged_handler constructors
9.3.32.2. packaged_handler operations
9.3.32.3. Class template specialization async_result
9.3.33. Class template packaged_token
9.3.33.1. packaged_token constructors
9.3.33.2. packaged_token operations
9.3.34. Function package
9.4. Basic I/O services
9.4.1. Header <experimental/io_service> synopsis
9.4.2. Class io_service
9.4.2.1. io_service constructors/destructor
9.4.2.2. io_service members
9.4.3. Class io_service::executor_type
9.4.3.1. io_service::executor_type constructors
9.4.3.2. io_service::executor_type assignment
9.4.3.3. executor_type operations
9.4.3.4. executor_type comparisons
9.5. Timers
9.5.1. Header <experimental/timer> synopsis
9.5.2. Requirements
9.5.2.1. Wait traits requirements
9.5.3. Class template wait_traits
9.5.3.1. Class template wait_traits members
9.5.4. Class template basic_waitable_timer
9.5.4.1. basic_waitable_timer constructors
9.5.4.2. basic_waitable_timer destructor
9.5.4.3. basic_waitable_timer assignment
9.5.4.4. basic_waitable_timer operations
9.6. Buffers
9.6.1. Header <experimental/buffer> synopsis
9.6.2. Requirements
9.6.2.1. Convertible to mutable buffer requirements
9.6.2.2. Mutable buffer sequence requirements
9.6.2.3. Convertible to const buffer requirements
9.6.2.4. Constant buffer sequence requirements
9.6.2.5. Dynamic buffer sequence requirements
9.6.2.6. Requirements on synchronous read operations
9.6.2.7. Requirements on asynchronous read operations
9.6.2.8. Requirements on synchronous write operations
9.6.2.9. Requirements on asynchronous write operations
9.6.2.10. Buffer-oriented synchronous read stream requirements
9.6.2.11. Buffer-oriented asynchronous read stream requirements
9.6.2.12. Buffer-oriented synchronous write stream requirements
9.6.2.13. Buffer-oriented asynchronous write stream requirements
9.6.3. Class mutable_buffer
9.6.3.1. mutable_buffer constructors
9.6.4. Class const_buffer
9.6.4.1. const_buffer constructors
9.6.5. Class mutable_buffers_1
9.6.5.1. mutable_buffers_1 constructors
9.6.5.2. mutable_buffers_1 members
9.6.6. Class const_buffers_1
9.6.6.1. const_buffers_1 constructors
9.6.6.2. const_buffers_1 members
9.6.7. Buffer type traits
9.6.8. Function buffer_cast
9.6.9. Function buffer_size
9.6.10. Function buffer_copy
9.6.11. Buffer arithmetic
9.6.12. Buffer creation functions
9.6.13. Class template dynamic_vector_buffer
9.6.13.1. dynamic_vector_buffer constructors
9.6.13.2. dynamic_vector_buffer members
9.6.14. Class template dynamic_string_buffer
9.6.14.1. dynamic_string_buffer constructors
9.6.14.2. dynamic_string_buffer members
9.6.15. Dynamic buffer creation functions
9.6.16. Class transfer_all
9.6.17. Class transfer_at_least
9.6.18. Class transfer_exactly
9.6.19. Synchronous read operations
9.6.20. Asynchronous read operations
9.6.21. Synchronous write operations
9.6.22. Asynchronous write operations
9.6.23. Synchronous delimited read operations
9.6.24. Asynchronous delimited read operations
9.7. Sockets
9.7.1. Header <experimental/socket> synopsis
9.7.2. Requirements
9.7.2.1. Native handles
9.7.2.2. Extensibility
9.7.2.3. Endpoint requirements
9.7.2.4. Protocol requirements
9.7.2.5. Gettable socket option requirements
9.7.2.6. Settable socket option requirements
9.7.2.7. I/O control command requirements
9.7.3. Error codes
9.7.4. Class socket_base
9.7.5. Boolean socket options
9.7.5.1. Boolean socket option constructors
9.7.5.2. Boolean socket option members
9.7.5.3. Boolean socket option members (extensible implementations)
9.7.6. Integral socket options
9.7.6.1. Integral socket option constructors
9.7.6.2. Integral socket option members
9.7.6.3. Integral socket option members (extensible implementations)
9.7.7. Class socket_base::linger
9.7.7.1. socket_base::linger constructors
9.7.7.2. socket_base::linger members
9.7.7.3. socket_base::linger members (extensible implementations)
9.7.8. Class template basic_socket
9.7.8.1. basic_socket constructors
9.7.8.2. basic_socket destructor
9.7.8.3. basic_socket assignment
9.7.8.4. basic_socket operations
9.7.9. Class template basic_datagram_socket
9.7.9.1. basic_datagram_socket constructors
9.7.9.2. basic_datagram_socket assignment
9.7.9.3. basic_datagram_socket operations
9.7.10. Class template basic_stream_socket
9.7.10.1. basic_stream_socket constructors
9.7.10.2. basic_stream_socket assignment
9.7.10.3. basic_stream_socket operations
9.7.11. Class template basic_socket_acceptor
9.7.11.1. basic_socket_acceptor constructors
9.7.11.2. basic_socket_acceptor destructor
9.7.11.3. basic_socket_acceptor assignment
9.7.11.4. basic_socket_acceptor operations
9.8. Socket streams
9.8.1. Class template basic_socket_streambuf
9.8.1.1. basic_socket_streambuf constructors
9.8.1.2. basic_socket_streambuf members
9.8.1.3. basic_socket_streambuf overridden virtual functions
9.8.2. Class template basic_socket_iostream
9.8.2.1. basic_socket_iostream constructors
9.8.2.2. basic_socket_iostream members
9.9. Synchronous connect operations
9.10. Asynchronous connect operations
9.11. Internet protocol
9.11.1. Header <experimental/internet> synopsis
9.11.2. Requirements
9.11.2.1. Internet protocol requirements
9.11.3. Error codes
9.11.4. Class ip::address
9.11.4.1. ip::address constructors
9.11.4.2. ip::address assignment
9.11.4.3. ip::address members
9.11.4.4. ip::address comparisons
9.11.4.5. ip::address creation
9.11.4.6. ip::address I/O
9.11.5. Class ip::address_v4
9.11.5.1. Struct ip::address_v4::bytes_type
9.11.5.2. ip::address_v4 constructors
9.11.5.3. ip::address_v4 assignment
9.11.5.4. ip::address_v4 members
9.11.5.5. ip::address_v4 static members
9.11.5.6. ip::address_v4 comparisons
9.11.5.7. ip::address_v4 creation
9.11.5.8. ip::address_v4 I/O
9.11.6. Class ip::address_v6
9.11.6.1. Struct ip::address_v6::bytes_type
9.11.6.2. ip::address_v6 constructors
9.11.6.3. ip::address_v6 assignment
9.11.6.4. ip::address_v6 members
9.11.6.5. ip::address_v6 static members
9.11.6.6. ip::address_v6 comparisons
9.11.6.7. ip::address_v6 creation
9.11.6.8. ip::address_v6 I/O
9.11.7. Class ip::bad_address_cast
9.11.8. Function ip::address_cast
9.11.9. Hash support
9.11.10. Class template ip::address_iterator_v4
9.11.10.1. ip::address_iterator_v4 constructors
9.11.10.2. ip::address_iterator_v4 members
9.11.11. Class template ip::address_iterator_v6
9.11.11.1. ip::address_iterator_v6 constructors
9.11.11.2. ip::address_iterator_v6 members
9.11.12. Class template ip::address_range_v4
9.11.12.1. ip::address_range_v4 constructors
9.11.12.2. ip::address_range_v4 members
9.11.13. Class template ip::address_range_v6
9.11.13.1. ip::address_range_v6 constructors
9.11.13.2. ip::address_range_v6 members
9.11.14. Class template ip::network_v4
9.11.14.1. ip::network_v4 constructors
9.11.14.2. ip::network_v4 members
9.11.14.3. ip::network_v4 comparisons
9.11.14.4. ip::network_v4 creation
9.11.14.5. ip::network_v4 I/O
9.11.15. Class template ip::network_v6
9.11.15.1. ip::network_v6 constructors
9.11.15.2. ip::network_v6 members
9.11.15.3. ip::network_v6 comparisons
9.11.15.4. ip::network_v6 creation
9.11.15.5. ip::network_v6 I/O
9.11.16. Class template ip::basic_endpoint
9.11.16.1. ip::basic_endpoint constructors
9.11.16.2. ip::basic_endpoint members
9.11.16.3. ip::basic_endpoint comparisons
9.11.16.4. ip::basic_endpoint I/O
9.11.16.5. ip::basic_endpoint members (extensible implementations)
9.11.17. Class ip::resolver_query_base
9.11.18. Class template ip::basic_resolver_entry
9.11.18.1. ip::basic_resolver_entry constructors
9.11.18.2. ip::basic_resolver_entry members
9.11.19. Class template ip::basic_resolver_iterator
9.11.19.1. ip::basic_resolver_iterator constructors
9.11.20. Class template ip::basic_resolver_query
9.11.21. Class template ip::basic_resolver
9.11.21.1. ip::basic_resolver constructors
9.11.21.2. ip::basic_resolver destructor
9.11.21.3. ip::basic_resolver assignment
9.11.21.4. ip::basic_resolver operations
9.11.22. Host name functions
9.11.23. Class ip::tcp
9.11.23.1. ip::tcp comparisons
9.11.24. Class ip::tcp::no_delay
9.11.25. Class ip::udp
9.11.25.1. ip::udp comparisons
9.11.26. Class ip::v6_only
9.11.27. Class ip::unicast::hops
9.11.28. Multicast group management socket options
9.11.28.1. Multicast group management socket option constructors
9.11.28.2. Multicast group management socket option members (extensible implementations)
9.11.29. Class ip::multicast::outbound_interface
9.11.29.1. ip::multicast::outbound_interface constructors
9.11.29.2. ip::multicast::outbound_interface members (extensible implementations)
9.11.30. Class ip::multicast::hops
9.11.31. Class ip::multicast::enable_loopback

This clause describes components that C++ programs may use to perform network operations.

The following subclauses describe components for executors, I/O services, timers, buffer management, sockets, endpoint resolution, iostreams, and internet protocols, as summarized in the table below:

Table 1. Networking library summary

Subclause

Header(s)

Asynchronous model

<experimental/type_traits>
<experimental/memory>
<experimental/executor>
<experimental/strand>
<experimental/future>

Basic I/O services

<experimental/io_service>

Timers

<experimental/timer>

Buffers

<experimental/buffer>

Sockets
Socket streams

<experimental/socket>

Internet protocol

<experimental/internet>


Throughout this clause, the names of the template parameters are used to express type requirements, as listed in the table below.

Table 2. Template parameters and type requirements

template parameter name

type requirements

AsyncReadStream

buffer-oriented asynchronous read stream

AsyncWriteStream

buffer-oriented asynchronous write stream

ConstBufferSequence

constant buffer sequence

ConvertibleToConstBuffer

convertible to a constant buffer

ConvertibleToMutableBuffer

convertible to a mutable buffer

DynamicBufferSequence

dynamic buffer sequence

GettableSocketOption

gettable socket option

InternetProtocol

Internet protocol

IoControlCommand

I/O control command

MutableBufferSequence

mutable buffer sequence

Protocol

protocol

Service

service

SettableSocketOption

settable socket option

SyncReadStream

buffer-oriented synchronous read stream

SyncWriteStream

buffer-oriented synchronous write stream

WaitTraits

wait traits


9.1. Definitions

9.1.1. host byte order

See section 1.4 of N3783 Network Byte Order Conversion.

9.1.2. network byte order

See section 1.4 of N3783 Network Byte Order Conversion.

9.1.3. synchronous operation

A synchronous operation is logically executed in the context of the initiating thread. Control is not returned to the initiating thread until the operation completes.

9.1.4. asynchronous operation

An asynchronous operation is logically executed in parallel to the context of the initiating thread. Control is returned immediately to the initiating thread without waiting for the operation to complete. Multiple asynchronous operations may be executed in parallel by a single initiating thread.

9.2. Error reporting

9.2.1. Synchronous operations

Synchronous network library functions often provide two overloads, one that throws an exception to report system errors, and another that sets an error_code.

[Note: This supports two common use cases:

— Uses where system errors are truly exceptional and indicate a serious failure. Throwing an exception is the most appropriate response. This is the preferred default for most everyday programming.

— Uses where system errors are routine and do not necessarily represent failure. Returning an error code is the most appropriate response. This allows application specific error handling, including simply ignoring the error.

end note]

Functions not having an argument of type error_code& report errors as follows, unless otherwise specified:

— When a call by the implementation to an operating system or other underlying API results in an error that prevents the function from meeting its specifications, an exception of type system_error shall be thrown.

— Failure to allocate storage is reported by throwing an exception as described in the C++ standard (C++14 [res.on.exception.handling]).

— Destructors throw nothing.

Functions having an argument of type error_code& report errors as follows, unless otherwise specified:

— If a call by the implementation to an operating system or other underlying API results in an error that prevents the function from meeting its specifications, the error_code& argument is set as appropriate for the specific error. Otherwise, clear() is called on the error_code& argument.

Where a function is specified as two overloads, with and without an argument of type error_code&:

R f(A1 a1, A2 a2, ..., AN aN);
R f(A1 a1, A2 a2, ..., AN aN, error_code& ec);

then, when R is non-void, the effects of the first overload shall be as if:

error_code ec;
R r(f(a1, a2, ..., aN, ec));
if (ec) throw system_error(ec, __func__);
return r;

Otherwise, when R is void, the effects of the first overload shall be as if:

error_code ec;
f(a1, a2, ..., aN, ec);
if (ec) throw system_error(ec, __func__);

9.2.2. Asynchronous operations

Asynchronous network library functions are identified by having the prefix async_. These asynchronous operations report errors as follows:

— If a call by the implementation to an operating system or other underlying API results in an error that prevents the asynchronous operation from meeting its specifications, the handler shall be invoked with an error_code value ec that is set as appropriate for the specific error. Otherwise, the error_code value ec is set such that !ec is true.

— Asynchronous operations shall not fail with an error condition that indicates interruption by a signal [Note: Such as POSIX EINTRend note] . Asynchronous operations shall not fail with any error condition associated with non-blocking operations [Note: Such as POSIX EWOULDBLOCK, EAGAIN or EINPROGRESS; Windows WSAEWOULDBLOCK or WSAEINPROGRESSend note] .

9.2.3. Error conditions

Unless otherwise specified, when the behavior of a synchronous or asynchronous operation is defined "as if" implemented by a POSIX function, the error_code produced by the function shall meet the following requirements:

— If the failure condition is one that is listed by POSIX for that function, the error_code shall compare equal to the error's corresponding enum class errc (C++14 [syserr]) or enum class resolver_errc constant.

— Otherwise, the error_code shall be set to an implementation-defined value that reflects the underlying operating system error.

[Example: The POSIX specification for shutdown() lists EBADF as one of its possible errors. If a function that is specified "as if" implemented by shutdown() fails with EBADF then the following condition holds for the error_code value ec: ec == errc::bad_file_descriptorend example]

When the description of a function contains the element Error conditions, this lists conditions where the operation may fail. The conditions are listed, together with a suitable explanation, as enum class constants. Unless otherwise specified, this list is a subset of the failure conditions associated with the function.

9.3. Asynchronous model

9.3.1. Header <experimental/type_traits> synopsis

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class CompletionToken, class Signature, class = void>
        struct handler_type;

      template<class CompletionToken, class Signature>
        using handler_type_t =
          typename handler_type<CompletionToken, Signature>::type;

      template<class Handler> class async_result;

      template<class CompletionToken, class Signature>
        struct async_completion;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

9.3.2. Header <experimental/memory> synopsis

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Alloc = allocator<void>>
        struct associated_allocator;

      template<class T, class Alloc = allocator<void>>
        using associated_allocator_t = typename associated_allocator<T, Alloc>::type;

      // get_associated_allocator:

      template<class T>
        associated_allocator_t<T> get_associated_allocator(const T& t);
      template<class T, class Alloc>
        associated_allocator_t<T, Alloc>
          get_associated_allocator(const T& t, const Alloc& a);

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

9.3.3. Header <experimental/executor> synopsis

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      enum class fork_event {
        prepare,
        parent,
        child
      };

      class execution_context;

      class service_already_exists;

      template<class Service> Service& use_service(execution_context& ctx);
      template<class Service, class... Args> Service&
        make_service(execution_context& ctx, Args&&... args);
      template<class Service> bool has_service(execution_context& ctx) noexcept;

      template<class T> struct is_executor : false_type {};

      struct executor_arg_t { };
      constexpr executor_arg_t executor_arg = executor_arg_t();

      template<class T, class Executor> struct uses_executor;

      template<class T, class Executor = system_executor>
        struct associated_executor;

      template<class T, class Executor = system_executor>
        using associated_executor_t = typename associated_executor<T, Executor>::type;

      // get_associated_executor:

      template<class T>
        associated_executor_t<T> get_associated_executor(const T& t);
      template<class T, class Executor>
        associated_executor_t<T, Executor>
          get_associated_executor(const T& t, const Executor& ex);
      template<class T, class ExecutionContext>
        associated_executor_t<T, typename ExecutionContext::executor_type>
          get_associated_executor(const T& t, ExecutionContext& ctx);

      template<class T, class Executor> struct executor_wrapper;

      template<class T, class Executor, class Signature>
        struct handler_type<executor_wrapper<T, Executor>, Signature>;

      template<class T, class Executor>
        class async_result<executor_wrapper<T, Executor>>;

      template<class T, class Executor, class Allocator>
        struct associated_allocator<executor_wrapper<T, Executor>, Allocator>;

      template<class T, class Executor, class Executor1>
        struct associated_executor<executor_wrapper<T, Executor>, Executor1>;

      // wrap:

      template<class Executor, class T>
        executor_wrapper<decay_t<T>, Executor> wrap(const Executor& ex, T&& t);
      template<class ExecutionContext, class T>
        executor_wrapper<decay_t<T>, typename ExecutionContext::executor_type>
          wrap(ExecutionContext& ctx, T&& t);

      template<class T, class Executor> struct executor_work;

      // make_work:

      template<class Executor>
        executor_work<Executor>
          make_work(const Executor& ex);
      template<class ExecutionContext>
        executor_work<typename ExecutionContext::executor_type>
          make_work(ExecutionContext& ctx);
      template<class T>
        executor_work<associated_executor_t<T>>
          make_work(const T& t);
      template<class T, class Executor>
        executor_work<associated_executor_t<T, Executor>>
          make_work(const T& t, const Executor& ex);
      template<class T, class ExecutionContext>
        executor_work<associated_executor_t<T, typename ExecutionContext::executor_type>>
          make_work(const T& t, ExecutionContext& ctx);

      class system_executor;

      bool operator==(const system_executor&, const system_executor&);
      bool operator!=(const system_executor&, const system_executor&);

      template<> struct is_executor<system_executor> : true_type {};

      class bad_executor;

      class executor;

      template <> struct is_executor<executor> : true_type {};

      bool operator==(const executor& a, const executor& b) noexcept;
      bool operator==(const executor& e, nullptr_t) noexcept;
      bool operator==(nullptr_t, const executor& e) noexcept;
      bool operator!=(const executor& a, const executor& b) noexcept;
      bool operator!=(const executor& e, nullptr_t) noexcept;
      bool operator!=(nullptr_t, const executor& e) noexcept;

      // dispatch:

      template<class CompletionToken>
        auto dispatch(CompletionToken&& token);
      template<class Executor, class CompletionToken>
        auto dispatch(const Executor& ex, CompletionToken&& token);
      template<class ExecutionContext, class CompletionToken>
        auto dispatch(ExecutionContext& ctx, CompletionToken&& token);

      // post:

      template<class CompletionToken>
        auto post(CompletionToken&& token);
      template<class Executor, class CompletionToken>
        auto post(const Executor& ex, CompletionToken&& token);
      template<class ExecutionContext, class CompletionToken>
        auto post(ExecutionContext& ctx, CompletionToken&& token);

      // defer:

      template<class CompletionToken>
        auto defer(CompletionToken&& token);
      template<class Executor, class CompletionToken>
        auto defer(const Executor& ex, CompletionToken&& token);
      template<class ExecutionContext, class CompletionToken>
        auto defer(ExecutionContext& ctx, CompletionToken&& token);

    } // inline namespace network_v1
  } // namespace experimental

  template<class Alloc>
    struct uses_allocator<std::experimental::network_v1::executor, Alloc>
      : true_type {};

} // namespace std

9.3.4. Header <experimental/strand> synopsis

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Executor>
        class strand;

      template<class Executor>
        bool operator==(const strand<Executor>& a, const strand<Executor>& b);
      template<class Executor>
        bool operator!=(const strand<Executor>& a, const strand<Executor>& b);

      template<class Executor>
        struct is_executor<strand<Executor>> : true_type {};

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

9.3.5. Header <experimental/future> synopsis

#include <future>

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Allocator = allocator<void>>
        class use_future_t;

      constexpr use_future_t<> use_future = use_future_t<>();

      template<class Allocator, class R, class... Args>
        struct handler_type<use_future_t<Allocator>, R(Args...)>;

      template<class R, class... Args>
        class async_result<packaged_task<R(Args...)>>;

      template<class Signature, class Alloc>
        class packaged_handler;

      template<class Signature, class Alloc>
        class async_result<packaged_handler<Signature, Alloc>>;

      template<class Func, class Alloc = allocator<void>>
        class packaged_token;

      template<class Func, class Alloc, class R, class... Args>
        struct handler_type<packaged_token<Func, Alloc>, R(Args...)>;

      template<class Func, class Alloc = allocator<void>>
        packaged_token<decay_t<Func>, Alloc> package(Func&& f, const Alloc& a = Alloc());

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

9.3.6. Requirements

9.3.6.1. Requirements on asynchronous operations

In this clause, an asynchronous operation is initiated by a function that is named with the prefix async_. These functions shall be known as initiating functions.

9.3.6.1.1. Completion tokens and handlers

All initiating functions in this clause:

— are function templates with template parameter CompletionToken;

— accept, as the final parameter, a completion token object token of type CompletionToken;

— specify a Completion signature element that defines a call signature Signature.

A handler is a function object that will be invoked, at most once, with the result of an asynchronous operation.

An initiating function determines the type Handler of its handler function object by performing handler_type_t<CompletionToken, Signature>. The handler object handler is initialized with handler(forward<CompletionToken>(token)).

The type Handler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with the specified completion signature. The Completion signature elements in this clause have named parameters, and the result of an asynchronous operation is specified in terms of these names.

9.3.6.1.2. Automatic deduction of initiating function return type

All initiating functions in this clause are specified using automatic return type deduction. The function return type shall be determined as if by typename async_result<Handler>::type.

9.3.6.1.3. Production of initiating function return value

All initiating functions in this clause produce their return type as follows:

— constructing an object result of type async_result<Handler>, initializing the object as result(handler); and

— using result.get() as the return expression.

[Example: Given an asynchronous operation with Completion signature void(R1 r1, R2 r2), an initiating function meeting these requirements may be implemented as follows:

template<class CompletionToken>
auto async_xyz(T1 t1, T2 t2, CompletionToken&& token)
{
  handler_type_t<CompletionToken, void(R1 r1, R2 r2)>
    handler(forward<CompletionToken>(token));

  async_result<decltype(handler)> result(handler);

  // initiate the operation and cause handler to be invoked with the result

  return result.get();
}

For convenience, initiating functions may be implemented using the async_completion template:

template<class CompletionToken>
auto async_xyz(T1 t1, T2 t2, CompletionToken&& token)
{
  async_completion<CompletionToken, void(R1 r1, R2 r2)> init(token);

  // initiate the operation and cause init.handler to be invoked with the result

  return init.result.get();
}

end example]

9.3.6.1.4. Lifetime of initiating function arguments

Unless otherwise specified, the lifetime of arguments to initiating functions shall be treated as follows:

— If the parameter is declared as a const reference, rvalue reference, or by-value, the implementation must not assume the validity of the argument after the initiating function completes. [Note: In other words, the program is not required to guarantee the validity of the argument after the initiating function completes. —end note] The implementation may make copies of the argument, and all copies shall be destroyed no later than immediately after invocation of the handler.

— If the parameter is declared as a non-const reference, const pointer or non-const pointer, the implementation may assume the validity of the argument until the handler is invoked. [Note: In other words, the program must guarantee the validity of the argument until the handler is invoked. —end note]

9.3.6.1.5. I/O executor

All asynchronous operations in this clause have an associated executor object satisfying Executor requirements. Where the initiating function is a member function, the associated executor is that returned by the get_executor member function on the same object. Where the initiating function is not a member function, the associated executor is that returned by the get_executor member function of the first argument to the initiating function. Let Executor1 be the type of the associated executor, and ex1 be the associated executor object obtained as described above.

9.3.6.1.6. Handler executor

All handler objects have an associated executor object satisfying Executor requirements. The type Executor2 of the handler's associated executor shall be determined by associated_executor_t<Handler, Executor1>. The handler's associated executor object ex2 shall be obtained by performing associated_executor<Handler, Executor1>::get(handler, ex1).

9.3.6.1.7. Outstanding work

The implementation of an asynchronous operation shall maintain an object work1 of type executor_work<Executor1>, initialized with work1(ex1) and with work1.owns_work() == true, until the effects of the asynchronous operation have been realized.

The implementation of an asynchronous operation shall maintain an object work2 of type executor_work<Executor2>, initialized with work2(ex2) and with work2.owns_work() == true, until handler has been submitted for execution.

9.3.6.1.8. Allocation of intermediate storage

Asynchronous operations may allocate memory. [Note: Such as a data structure to store copies of the handler object and the initiating function's arguments. —end note]

Let Alloc1 be a type, satisfying Allocator requirements (C++ Std, [allocator.requirements]), that represents the asynchronous operation's default allocation strategy. [Note: Typically std::allocator<void>. —end note] Let alloc1 be an object of type Alloc1.

All handlers have an associated allocator object satisfying Allocator requirements. The type Alloc2 of the handler's associated allocator shall be determined by associated_allocator_t<Handler, Alloc1>. The handler's associated allocator object alloc2 shall be obtained by performing associated_allocator<Handler, Executor1>::get(handler, alloc1).

The asynchronous operations defined in this clause:

— May allocate memory using the handler's associated allocator.

— Shall deallocate all memory allocated using the handler's associated allocator prior to handler execution.

— Shall ensure that calls to the handler's associated allocator, or to copies of the handler's associated allocator, are not performed concurrently in a way that would introduce a data race.

9.3.6.1.9. Execution of handler on completion of asynchronous operation

When an asynchronous operation completes, the implementation constructs a zero-argument function object bound_handler to invoke handler with results of the operation.

If an asynchonous operation completes immediately (that is, within the thread calling the initiating function, and before the initiating function returns), the handler shall be submitted for execution as if by performing ex2.post(bound_handler, alloc2). Otherwise, the handler shall be submitted for execution as if by performing ex2.dispatch(bound_handler, alloc2).

9.3.6.2. Executor requirements

The library describes a standard set of requirements for executors. A type meeting Executor requirements shall embody a set of rules for determining how submitted function objects are to be executed.

An executor type X shall satisfy the requirements of CopyConstructible (C++ Std, [copyconstructible]) types. No constructor, comparison operator, copy operation, move operation, swap operation, or member functions context, on_work_started and on_work_finished on these types shall exit via an exception.

The executor copy constructor, comparison operators, and member functions defined in these requirements shall not introduce data races as a result of concurrent calls to those functions from different threads.

In the table below, X denotes an executor class, x denotes a value of type X&, x1 and x2 denote values of type const X&, x3 denotes a value of type X&&, f denotes a MoveConstructible (C++ Std, [moveconstructible]) function object callable with zero arguments, a denotes a value of type A meeting Allocator requirements (C++ Std, [allocator.requirements]), t denotes an object of type T, and u denotes an identifier.

Table 3. Executor requirements

expression

type

assertion/note
pre/post-conditions

X u(x1);

Shall not exit via an exception.

post: u == x1

X u(x3);

Shall not exit via an exception.

post: u equals the prior value of x3.

x1 == x2

bool

Shall not exit via an exception.

Returns true only if x1 and x2 can be interchanged with identical effects in any of the expressions defined in these type requirements. [Note: false does not necessarily imply that the effects are not identical. —end note]

operator== shall be reflexive, symmetric, and transitive, and shall not exit via an exception.

x1 != x2

bool

Shall not exit via an exception.

Same as !(x1 == x2).

x.context()

execution_context&, or a type that is convertible to execution_context&.

Shall not exit via an exception.

x.on_work_started()

Shall not exit via an exception.

x.on_work_finished()

Shall not exit via an exception.

Requires: A preceding call x1.on_work_started() where x == x1.

x.dispatch(std::move(f),a)

Effects: Calls DECAY_COPY(forward<Func>(f))() at most once. The executor may invoke f in the current thread, prior to returning from dispatch. The call to DECAY_COPY() is evaluated in the thread that called dispatch.

Executor implementations are encouraged to use the supplied allocator to allocate any memory required to store the function object. The executor shall deallocate all memory prior to invoking the function object.

Synchronization: The invocation of dispatch synchronizes with (C++ Std, [intro.multithread]) the invocation of f.

x.post(std::move(f),a)

Effects: Calls DECAY_COPY(forward<Func>(f))() at most once. The executor may not invoke f in the current thread, prior to returning from post. The call to DECAY_COPY() is evaluated in the thread that called post.

Executor implementations are encouraged to use the supplied allocator to allocate any memory required to store the function object. The executor shall deallocate all memory prior to invoking the function object.

Synchronization: The invocation of post synchronizes with (C++ Std, [intro.multithread]) the invocation of f.

x.defer(std::move(f),a)

Effects: Calls DECAY_COPY(forward<Func>(f))() at most once. The executor may not invoke f in the current thread, prior to returning from defer. The call to DECAY_COPY() is evaluated in the thread that called defer.

Executor implementations are encouraged to use the supplied allocator to allocate any memory required to store the function object. The executor shall deallocate all memory prior to invoking the function object.

Synchronization: The invocation of defer synchronizes with (C++ Std, [intro.multithread]) the invocation of f.

Note: Although the requirements placed on defer are identical to post, a separate function is used to convey the intention of the caller that the submitted function is a continuation of the current call context. The executor may use this information to optimize or otherwise adjust the way in which f is invoked.


9.3.6.3. Service requirements

A class is a service if it is publicly derived from another service, or if it is a class publicly derived from execution_context::service.

A service may contain a publicly-accessible nested typedef named key_type. If the nested typedef key_type exists, the service class shall be the same type as key_type, or otherwise publicly and unambiguously derived from key_type.

All services define a one-argument constructor that takes a reference to the execution_context object that owns the service. This constructor is explicit, preventing its participation in automatic conversions.

A service may provide additional constructors with two or more arguments, where the first argument is a reference to the execution_context object that owns the service. [Note: These constructors may be called by the make_service function. —end note]

[Example:

class my_service : public execution_context::service
{
public:
  typedef my_service key_type;
  explicit my_service(execution_context& ctx);
private:
  virtual void shutdown_service();
  ...
};

end example]

A service's shutdown_service member function must cause all copies of user-defined function objects that are held by the service to be destroyed.

9.3.7. Class template handler_type

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class CompletionToken, class Signature, class = void>
      struct handler_type
      {
        typedef see below type;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Template parameter CompletionToken specifies the model used to obtain the result of the asynchronous operation. Template parameter Signature is the call signature (C++ Std, [func.def]) for the handler type invoked on completion of the asynchronous operation.

A program may specialize this trait if the CompletionToken template parameter in the specialization is a user-defined type.

Specializations of handler_type shall define a nested handler type type that satisfies the MoveConstructible requirements, and objects of type type shall be constructible from an lvalue or rvalue of the type specified by the CompletionToken template parameter.

9.3.7.1. handler_type members
typedef see below type;

Type: CompletionToken if CompletionToken and decay_t<CompletionToken> are the same type; otherwise, handler_type_t<decay_t<CompletionToken>, Signature>.

9.3.8. Class template async_result

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Handler>
      class async_result
      {
      public:
        typedef void type;

        explicit async_result(Handler&);
        async_result(const async_result&) = delete;
        async_result& operator=(const async_result&) = delete;

        type get();
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Template argument Handler is a handler type produced by handler_type_t<T, S> for some completion token type T and call signature S.

A program may specialize this template if the Handler template parameter in the specialization is a user-defined type.

Specializations of async_result shall satisfy the Destructible requirements (C++ Std, [destructible]) in addition to the requirements in the table below. In this table, R is a specialization of async_result for the template parameter Handler; r is a modifiable lvalue of type R; and h is a modifiable lvalue of type Handler.

Table 4. async_result specialization requirements

Expression

Return type

Note

R::type

void; or a type satisfying MoveConstructible requirements (C++ Std, [moveconstructible])

R r(h);

r.get()

R::type

The get() member function shall be used only as a return expression.


9.3.8.1. async_result members
explicit async_result(Handler&);

Effects: Does nothing.

type get();

Effects: Does nothing.

9.3.9. Class template async_completion

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class CompletionToken, class Signature>
      struct async_completion
      {
        typedef handler_type_t<CompletionToken, Signature> handler_type;

        explicit async_completion(remove_reference_t<CompletionToken>& t);
        async_completion(const async_completion&) = delete;
        async_completion& operator=(const async_completion&) = delete;

        see below handler;
        async_result<handler_type> result;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Template parameter CompletionToken specifies the model used to obtain the result of the asynchronous operation. Template parameter Signature is the call signature (C++ Std, [func.def]) for the handler type invoked on completion of the asynchronous operation.

9.3.9.1. async_completion members
explicit async_completion(remove_reference_t<CompletionToken>& t);

Effects: If CompletionToken and handler_type are the same type, binds handler to t; otherwise, initializes handler with the result of forward<CompletionToken>(t). Initializes result with handler.

see below handler;

Type: handler_type& if CompletionToken and handler_type are the same type; otherwise, handler_type.

9.3.10. Class template associated_allocator

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Alloc = allocator<void>>
      struct associated_allocator
      {
        typedef see below type;

        static type get(const T& t, const Alloc& a = Alloc()) noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

A program may specialize this traits type if the T template parameter in the specialization is a user-defined type. The template parameter Alloc shall be a type meeting Allocator requirements (C++ Std, [allocator.requirements]).

Specializations of associated_allocator shall satisfy the requirements in the table below. In this table, X is a specialization of associated_allocator for the template parameter T; t is a const reference to an object of type T; and a is an object of type Alloc.

Table 5. associated_allocator specialization requirements

Expression

Return type

Note

typename X::type

A type meeting Allocator requirements (C++ Std, [allocator.requirements]).

X::get(t)

X::type

Shall not exit via an exception.
Equivalent to X::get(t, Alloc()).

X::get(t, a)

X::type

Shall not exit via an exception.


9.3.10.1. associated_allocator members
typedef see below type;

Type: If T has a nested type allocator_type, typename T::allocator_type. Otherwise Alloc.

type get(const T& t, const Alloc& a = Alloc()) noexcept;

Returns: If T has a nested type allocator_type, t.get_allocator(). Otherwise a.

9.3.11. Function get_associated_allocator

template<class T>
  associated_allocator_t<T> get_associated_allocator(const T& t);

Returns: associated_allocator<T>::get(t).

template<class T, class Alloc>
  associated_allocator_t<T, Alloc>
    get_associated_allocator(const T& t, const Alloc& a);

Returns: associated_allocator<T, Alloc>::get(t, a).

9.3.12. Class execution_context

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class execution_context
      {
      public:
        class service;

        // construct / copy / destroy:

        execution_context();
        execution_context(const execution_context&) = delete;
        execution_context& operator=(const execution_context&) = delete;
        virtual ~execution_context();

        // execution context operations:

        void notify_fork(fork_event e);

      protected:

        // execution context protected operations:

        void shutdown_context();
        void destroy_context();
      };

      // service access:
      template<class Service> Service& use_service(execution_context& ctx);
      template<class Service, class... Args> Service&
        make_service(execution_context& ctx, Args&&... args);
      template<class Service> bool has_service(execution_context& ctx) noexcept;
      class service_already_exists : public logic_error { ... };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Class execution_context implements an extensible, type-safe, polymorphic set of services, indexed by service type.

Access to the services of an execution_context is via three function templates, use_service<>, make_service<> and has_service<>.

In a call to use_service<Service>(), the type argument chooses a service, making available all members of the named type. If the service is not present in an execution_context, an object of type Service is created and added to the execution_context. A C++ program can check if an execution_context implements a particular service with the function template has_service<Service>().

Service objects may be explicitly added to an execution_context using the function template make_service<Service>(). If the service is already present, the service_already_exists exception is thrown.

Once a service reference is obtained from an execution_context object by calling use_service<>, that reference remains usable until a call to destroy_context().

9.3.12.1. execution_context constructor
execution_context();

Effects: Creates an object of class execution_context.

9.3.12.2. execution_context destructor
~execution_context();

Effects: Destroys an object of class execution_context. Performs shutdown_context() followed by destroy_context().

9.3.12.3. execution_context operations
void notify_fork(fork_event e);

Effects: For each service object svc in the set:
— If e == fork_event::prepare, performs svc->notify_fork(e) in reverse order of the beginning of service object lifetime (C++ Std, [basic.life]).
— Otherwise, performs svc->notify_fork(e) in order of the beginning of service object lifetime.

9.3.12.4. execution_context protected operations
void shutdown_context();

Effects: For each service object svc in the execution_context set, in reverse order of the beginning of service object lifetime (C++ Std, [basic.life]), performs svc->shutdown_service().

[Note: shutdown_context is an idempotent operation. —end note]

void destroy_context();

Effects: Destroys each service object in the execution_context set, in reverse order of the beginning of service object lifetime (C++ Std, [basic.life]).

[Note: destroy_context is an idempotent operation. —end note]

9.3.12.5. execution_context globals

The functions use_service, make_service and has_service shall not introduce data races as a result of concurrent calls to those functions from different threads.

template<class Service> Service& use_service(execution_context& ctx);

Let Key be Service::key_type if the nested typedef Service::key_type exists; otherwise, let Key be Service.

Requires: Service is a service class that is publicly and unambiguously derived from execution_context::service. If the nested typedef Service::key_type exists, Service is the same type as Service::key_type, or Service is publicly and unambiguously derived from Service::key_type, and Service::key_type is publicly and unambiguously derived from execution_context::service.

Effects: If an object of type Key does not already exist in the execution_context set identified by ctx, creates an object of type Service, initializing it with Service(ctx), and adds it to the set.

Returns: A reference to the corresponding service of ctx.

Notes: The reference returned remains valid until a call to destroy_context.

template<class Service, class... Args> Service&
  make_service(execution_context& ctx, Args&&... args);

Let Key be Service::key_type if the nested typedef Service::key_type exists; otherwise, let Key be Service.

Requires: Service is a service class that is publicly and unambiguously derived from execution_context::service. If the nested typedef Service::key_type exists, Service is the same type as Service::key_type, or Service is publicly and unambiguously derived from Service::key_type, and Service::key_type is publicly and unambiguously derived from execution_context::service. A service object of type Key does not already exist in the execution_context set identified by ctx.

Effects: Creates an object of type Service, initializing it with Service(ctx, forward<Args>(args)...), and adds it to the execution_context set identified by ctx.

Throws: service_already_exists if a corresponding service object of type Key is already present in the set.

Notes: The reference returned remains valid until a call to destroy_context.

template<class Service> bool has_service(execution_context& ctx) noexcept;

Let Key be Service::key_type if the nested typedef Service::key_type exists; otherwise, let Key be Service.

Requires: Service is a service class that is publicly and unambiguously derived from execution_context::service. If the nested typedef Service::key_type exists, Service is the same type as Service::key_type, or Service is publicly and unambiguously derived from Service::key_type, and Service::key_type is publicly and unambiguously derived from execution_context::service.

Returns: If an object of type Key is present in ctx, true; otherwise, false.

9.3.13. Class execution_context::service

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class execution_context::service
      {
      protected:
        // construct / copy / destroy:

        service(execution_context& owner);
        service(const service&) = delete;
        service& operator=(const service&) = delete;
        virtual ~service();

        // service observers:

        execution_context& context() noexcept;

      private:
        friend class execution_context; // exposition only

        // service operations:

        virtual void shutdown_service() = 0;
        virtual void notify_fork(fork_event e);

        execution_context& context_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
9.3.13.1. execution_context::service constructors
service(execution_context& owner);

Postconditions: &context_ == &owner.

9.3.13.2. execution_context::service observers
execution_context& context() noexcept;

Returns: context_.

9.3.13.3. execution_context::service operations
void notify_fork(fork_event e);

Effects: Does nothing.

9.3.14. Class template is_executor

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T> struct is_executor : false_type {};

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

is_executor can be used to detect executor types satisfying the Executor type requirements.

Instantiations of the is_executor template shall meet the UnaryTypeTrait requirements (C++ Std, [meta.rqmts]). A program may specialize this template for a user-defined type T to have a BaseCharacteristic of integral_constant<int, N> with N > 0 to indicate that T should be treated as an executor type.

9.3.15. Executor argument tag

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      struct executor_arg_t { };
      constexpr executor_arg_t executor_arg = executor_arg_t();

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The executor_arg_t struct is an empty structure type used as a unique type to disambiguate constructor and function overloading. Specifically, types may have constructors with executor_arg_t as the first argument, immediately followed by an argument of a type that satisfies the Executor requirements.

9.3.16. uses_executor

9.3.16.1. uses_executor trait
namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor> struct uses_executor;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Remark: Detects whether T has a nested executor_type that is convertible from Executor. Meets the BinaryTypeTrait requirements (C++ Std, [meta.rqmts]). The implementation shall provide a definition that is derived from false_type. A program may specialize this template to derive from true_type for a user-defined type T that does not have a nested executor_type but nonetheless can be constructed with an executor where either:

— the first argument of a constructor has type executor_type and the second argument has type Executor; or

— the last argument of a constructor has type Executor.

9.3.16.2. uses-executor construction

Uses-executor construction with executor Executor refers to the construction of an object obj of type T, using constructor arguments v1, v2, ..., vN of types V1, V2, ..., VN, respectively, and an executor ex of type Executor, according to the following rules:

— if uses_executor<T, Executor>::value is false and is_constructible<T, V1, V2, ..., VN>::value is true, then obj is initialized as obj(v1, v2, ..., vN);

— otherwise, if uses_executor<T, Executor>::value is true and is_constructible<T, executor_arg_t, Executor, V1, V2, ..., VN>::value is true, then obj is initialized as obj(executor_arg, ex, v1, v2, ..., vN);

— otherwise, if uses_executor<T, Executor>::value is true and is_constructible<T, V1, V2, ..., VN, Executor>::value is true, then obj is initialized as obj(v1, v2, ..., vN, ex);

— otherwise, the request for uses-executor construction is ill-formed. [Note: An error will result if uses_executor<T, Executor>::value is true but the specific constructor does not take an executor. This definition prevents a silent failure to pass the executor to an element. —end note]

9.3.17. Class template associated_executor

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor = system_executor>
      struct associated_executor
      {
        typedef see below type;

        static type get(const T& t, const Executor& e = Executor()) noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

A program may specialize this traits type if the T template parameter in the specialization is a user-defined type. The template parameter Executor shall be a type meeting Executor requirements.

Specializations of associated_executor shall satisfy the requirements in the table below. In this table, X is a specialization of associated_executor for the template parameter T; t is a const reference to an object of type T; and e is an object of type Executor.

Table 6. associated_executor specialization requirements

Expression

Return type

Note

typename X::type

A type meeting Executor requirements.

X::get(t)

X::type

Shall not exit via an exception.
Equivalent to X::get(t, Executor()).

X::get(t, e)

X::type

Shall not exit via an exception.


9.3.17.1. associated_executor members
typedef see below type;

Type: If T has a nested type executor_type, typename T::executor_type. Otherwise Executor.

type get(const T& t, const Executor& e = Executor()) noexcept;

Returns: If T has a nested type executor_type, t.get_executor(). Otherwise e.

9.3.18. Function get_associated_executor

template<class T>
  associated_executor_t<T> get_associated_executor(const T& t);

Returns: associated_executor<T>::get(t).

template<class T, class Executor>
  associated_executor_t<T, Executor>
    get_associated_executor(const T& t, const Executor& ex);

Returns: associated_executor<T, Executor>::get(t, ex).

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class T, class ExecutionContext>
  associated_executor_t<T, typename ExecutionContext::executor_type>
    get_associated_executor(const T& t, ExecutionContext& ctx);

Returns: associated_executor<T, typename ExecutionContext::executor_type>::get(t, ctx.get_executor()).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

9.3.19. Class template executor_wrapper

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor>
      class executor_wrapper
      {
      public:
        // types:

        typedef T wrapped_type;
        typedef Executor executor_type;
        typedef see below result_type;          // not always defined
        typedef see below argument_type;        // not always defined
        typedef see below first_argument_type;  // not always defined
        typedef see below second_argument_type; // not always defined

        // construct / copy / destroy:

        executor_wrapper(T t, const Executor& ex);
        executor_wrapper(const executor_wrapper& other) = default;
        executor_wrapper(executor_wrapper&& other) = default;
        template<class U, class OtherExecutor>
          executor_wrapper(const executor_wrapper<U, OtherExecutor>& other);
        template<class U, class OtherExecutor>
          executor_wrapper(executor_wrapper<U, OtherExecutor>&& other);
        template<class U, class OtherExecutor>
          executor_wrapper(executor_arg_t, const Executor& ex,
            const executor_wrapper<U, OtherExecutor>& other);
        template<class U, class OtherExecutor>
          executor_wrapper(executor_arg_t, const Executor& ex,
            executor_wrapper<U, OtherExecutor>&& other);

        ~executor_wrapper();

        // executor wrapper access:

        T& unwrap() noexcept;
        const T& unwrap() const noexcept;
        executor_type get_executor() const noexcept;

        // executor wrapper invocation:

        template<class... Args>
          result_of_t<cv T&(Args&&...)> operator()(Args&&... args) cv;

      private:
        Executor ex_; // exposition only
        T wrapped_; // exposition only
      };

      template<class T, class Executor, class Signature>
      struct handler_type<executor_wrapper<T, Executor>, Signature>
      {
        typedef executor_wrapper<handler_type_t<T, Signature>, Executor> type;
      };

      template<class T, class Executor>
        class async_result<executor_wrapper<T, Executor>>;

      template<class T, class Executor, class Alloc>
        struct associated_allocator<executor_wrapper<T, Executor>, Alloc>;

      template<class T, class Executor, class Executor1>
        struct associated_executor<executor_wrapper<T, Executor>, Executor1>;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

executor_wrapper<T, Executor> is a wrapper around an object or function of type T, and an executor object of type Executor satisfying Executor requirements.

executor_wrapper<T, Executor> has a weak result type (C++ Std, [func.require]). If T is a function type, result_type shall be a synonym for the return type of T.

The template instantiation executor_wrapper<T, Executor> shall define a nested type named argument_type as a synonym for T1 only if the type T is any of the following:

— a function type or a pointer to function type taking one argument of type T1

— a pointer to member function R T0::f cv (where cv represents the member function’s cv-qualifiers); the type T1 is cv T0*

— a class type with a member type argument_type; the type T1 is T::argument_type.

The template instantiation executor_wrapper<T, Executor> shall define two nested types named first_argument_type and second_argument_type as synonyms for T1 and T2, respectively, only if the type T is any of the following:

— a function type or a pointer to function type taking two arguments of types T1 and T2

— a pointer to member function R T0::f(T2) cv (where cv represents the member function’s cv-qualifiers); the type T1 is cv T0*

— a class type with member types first_argument_type and second_argument_type; the type T1 is T::first_argument_type. and the type T2 is T::second_argument_type.

9.3.19.1. executor_wrapper constructors
executor_wrapper(T t, const Executor& ex);

Effects: Constructs an object of type executor_wrapper<T, Executor>. Initializes ex_ with the value ex. If uses_executor<T, Executor>::value is true, performs uses-executor construction to initialize wrapped_ with wrapped_(executor_arg, ex_, std::move(t)); otherwise, initializes wrapped_ with wrapped_(std::move(t)).

template<class U, class OtherExecutor>
  executor_wrapper(const executor_wrapper<U, OtherExecutor>& other);

Requires: U is T or convertible to T. OtherExecutor is Executor or convertible to Executor.

Effects: Constructs an object of type executor_wrapper<T, Executor>. Initializes ex_ with other.get_executor(). If uses_executor<T, Executor>::value is true, performs uses-executor construction to initialize wrapped_ with wrapped_(executor_arg, ex_, other.unwrap()); otherwise, initializes wrapped_ with wrapped_(other.unwrap()).

template<class U, class OtherExecutor>
  executor_wrapper(executor_wrapper<U, OtherExecutor>&& other);

Requires: U is T or convertible to T. OtherExecutor is Executor or convertible to Executor.

Effects: Constructs an object of type executor_wrapper<T, Executor>. Initializes ex_ with other.get_executor(). If uses_executor<T, Executor>::value is true, performs uses-executor construction to initialize wrapped_ with wrapped_(executor_arg, ex_, std::move(other.unwrap())); otherwise, initializes wrapped_ with wrapped_(std::move(other.unwrap())).

template<class U, class OtherExecutor>
  executor_wrapper(executor_arg_t, const Executor& ex,
    const executor_wrapper<U, OtherExecutor>& other);

Requires: U is T or convertible to T.

Effects: Constructs an object of type executor_wrapper<T, Executor>. Initializes ex_ with ex. If uses_executor<T, Executor>::value is true, performs uses-executor construction to initialize wrapped_ with wrapped_(executor_arg, ex_, other.unwrap()); otherwise, initializes wrapped_ with wrapped_(other.unwrap()).

template<class U, class OtherExecutor>
  executor_wrapper(executor_arg_t, const Executor& ex,
    executor_wrapper<U, OtherExecutor>&& other);

Requires: U is T or convertible to T.

Effects: Constructs an object of type executor_wrapper<T, Executor>. Initializes ex_ with ex. If uses_executor<T, Executor>::value is true, performs uses-executor construction to initialize wrapped_ with wrapped_(executor_arg, ex_, std::move(other.unwrap())); otherwise, initializes wrapped_ with wrapped_(std::move(other.unwrap())).

9.3.19.2. executor_wrapper access
T& unwrap() noexcept;
const T& unwrap() const noexcept;

Returns: wrapped_.

executor_type get_executor() const noexcept;

Returns: executor_.

9.3.19.3. executor_wrapper invocation
template<class... Args>
  result_of_t<cv T&(Args&&...)> operator()(Args&&... args) cv;

Returns: INVOKE(unwrap(), forward<Args>(args)...) (C++ Std, [func.require]).

Remarks: operator() is described for exposition only. Implementations are not required to provide an actual executor_wrapper::operator(). Implementations are permitted to support executor_wrapper function invocation through multiple overloaded operators or through other means.

9.3.19.4. Class template specialization async_result
namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor>
      class async_result<executor_wrapper<T, Executor>>
      {
      public:
        typedef typename async_result<T>::type type;

        explicit async_result(executor_wrapper<T, Executor>& wrapper);
        async_result(const async_result&) = delete;
        async_result& operator=(const async_result&) = delete;

        type get();

      private:
        async_result<T> wrapped_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The implementation shall provide a specialization of async_result that meets the async_result specialization requirements.

explicit async_result(executor_wrapper<T, Executor>& wrapper);

Effects: Initializes wrapped_ with wrapped_(wrapper.unwrap()).

type get();

Returns: wrapped_.get().

9.3.19.5. Class template specialization associated_allocator
namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor, class Alloc>
        struct associated_allocator<executor_wrapper<T, Executor>, Alloc>
      {
        typedef associated_allocator_t<T, Alloc> type;

        static type get(const executor_wrapper<T, Executor>& w,
                        const Alloc& a = Alloc()) noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The implementation shall provide a specialization of associated_allocator that meets the associated_allocator specialization requirements.

static type get(const executor_wrapper<T, Executor>& w,
                const Alloc& a = Alloc()) noexcept;

Returns: associated_allocator<T, Alloc>::get(w.unwrap(), a).

9.3.19.6. Class template specialization associated_executor
namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Executor, class Executor1>
        struct associated_executor<executor_wrapper<T, Executor>, Executor1>
      {
        typedef Executor type;

        static type get(const executor_wrapper<T, Executor>& w,
                        const Executor1& e = Executor1()) noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The implementation shall provide a specialization of associated_executor that meets the associated_executor specialization requirements.

static type get(const executor_wrapper<T, Executor>& w,
                const Executor1& e = Executor1()) noexcept;

Returns: w.get_executor().

9.3.20. Function wrap

template<class Executor, class T>
  executor_wrapper<decay_t<T>, Executor> wrap(const Executor& ex, T&& t);

Returns: executor_wrapper<decay_t<T>, Executor>(forward<T>(t), ex).

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class ExecutionContext, class CompletionToken>
  executor_wrapper<decay_t<T>, typename ExecutionContext::executor_type>
    wrap(ExecutionContext& ctx, T&& t);

Returns: executor_wrapper<decay_t<T>, typename ExecutionContext::executor_type>(forward<T>(t), ctx.get_executor()).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

9.3.21. Class template executor_work

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Executor>
      class executor_work
      {
      public:
        // types:

        typedef Executor executor_type;

        // construct / copy / destroy:

        explicit executor_work(const executor_type& ex) noexcept;
        executor_work(const executor_work& other) noexcept;
        executor_work(executor_work&& other) noexcept;

        executor_work operator=(const executor_type&) = delete;

        ~executor_work();

        // executor work observers:

        executor_type get_executor() const noexcept;
        bool owns_work() const noexcept;

        // executor work modifiers:

        void reset() noexcept;

      private:
        Executor ex_; // exposition only
        bool owns_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
9.3.21.1. executor_work constructors
explicit executor_work(const executor_type& ex) noexcept;

Effects: Constructs an object of class executor_work, initializing ex_ with ex, and then performing ex_.on_work_started().

Postconditions: ex == ex_ and owns_ == true.

executor_work(const executor_work& other) noexcept;

Effects: Constructs an object of class executor_work, initializing ex_ with other.ex. If other.owns_ == true, performs ex_.on_work_started().

Postconditions: ex == other.ex_ and owns_ == other.owns_.

executor_work(executor_work&& other) noexcept;

Effects: Constructs an object of class executor_work, initializing ex_ with other.ex and owns_ with other.owns_.

Postconditions: ex is equal to the prior value of other.ex_, owns_ is equal to the prior value of other.owns_, and other.owns_ == false.

9.3.21.2. executor_work destructor

Effects: If owns_ is true, performs ex.on_work_finished().

9.3.21.3. executor_work observers
executor_type get_executor() const noexcept;

Returns: ex_.

bool owns_work() const noexcept;

Returns: owns_.

9.3.21.4. executor_work modifiers
void reset() noexcept;

Effects: If owns_ is true, performs ex.on_work_finished().

Postconditions: owns_ == false.

9.3.22. Function make_work

template<class Executor>
  executor_work<Executor>
    make_work(const Executor& ex);

Returns: executor_work<Executor>(ex).

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class ExecutionContext>
  executor_work<typename ExecutionContext::executor_type>
    make_work(ExecutionContext& ctx);

Returns: An object of type executor_work<typename ExecutionContext::executor_type> initialized with the result of ctx.get_executor().

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

template<class T>
  executor_work<associated_executor_t<T>>
    make_work(const T& t);

Returns: An object of type executor_work<associated_executor_t<T>> initialized with the result of associated_executor<T>::get(t).

Remarks: This function shall not participate in overload resolution unless is_executor<T>::value is false and is_convertible<T&, execution_context&>::value is false.

template<class T, class Executor>
  executor_work<associated_executor_t<T, Executor>>
    make_work(const T& t, const Executor& ex);

Returns: An object of type executor_work<associated_executor_t<T, Executor>> initialized with the result of associated_executor<T, Executor>::get(t, ex).

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class T, class ExecutionContext>
  executor_work<associated_executor_t<T, typename ExecutionContext::executor_type>>
    make_work(const T& t, ExecutionContext& ctx);

Returns: An object of type executor_work<associated_executor_t<T, typename ExecutionContext::executor_type>> initialized with the result of associated_executor<T, typename ExecutionContext::executor_type>::get(t, ctx.get_executor()).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

9.3.23. Class system_executor

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class system_executor
      {
      public:

        // executor operations:

        execution_context& context() noexcept;

        void on_work_started() noexcept;
        void on_work_finished() noexcept;

        template<class Func, class Alloc>
          void dispatch(Func&& f, const Alloc& a);
        template<class Func, class Alloc>
          void post(Func&& f, const Alloc& a);
        template<class Func, class Alloc>
          void defer(Func&& f, const Alloc& a);
      };

      bool operator==(const system_executor&, const system_executor&) noexcept;
      bool operator!=(const system_executor&, const system_executor&) noexcept;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Class system_executor is a DefaultConstructible type (C++ Std, [defaultconstructible]) satisfying Executor requirements. It represents a set of rules where function objects are permitted to execute on any thread.

To satisfy the executor requirements for the post and defer member functions, the system executor may allocate thread objects to run the submitted function objects. If std::exit is called, and there remain unexecuted functions objects that have been submitted using post or defer, the implementation shall discard these function objects without calling them.

9.3.23.1. system_executor operations
execution_context& context() noexcept;

Returns: A reference to a static-duration object of a type derived from execution_context.

void on_work_started() noexcept;

Effects: Does nothing.

void on_work_finished() noexcept;

Effects: Does nothing.

template<class Func, class Alloc>
  void dispatch(Func&& f, const Alloc& a);

Effects: Calls DECAY_COPY(forward<Func>(f))().

template<class Func, class Alloc>
  void post(Func&& f, const Alloc& a);

Effects: Calls DECAY_COPY(forward<Func>(f))() as if in a thread of execution represented by a thread object, with the call to DECAY_COPY() being evaluated in the thread that called post. Any exception propagated from the execution of DECAY_COPY(forward<Func>(f))() shall result in a call to std::terminate.

template<class Func, class Alloc>
  void defer(Func&& f, const Alloc& a);

Effects: Calls DECAY_COPY(forward<Func>(f))() as if in a thread of execution represented by a thread object, with the call to DECAY_COPY() being evaluated in the thread that called defer. Any exception propagated from the execution of DECAY_COPY(forward<Func>(f))() shall result in a call to std::terminate.

9.3.23.2. system_executor comparisons
bool operator==(const system_executor&, const system_executor&) noexcept;

Returns: true.

bool operator!=(const system_executor&, const system_executor&) noexcept;

Returns: false.

9.3.24. Class bad_executor

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class bad_executor : public exception
      {
      public:
        // constructor:
        bad_executor() noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

An exception of type bad_executor is thrown by executor member functions dispatch, post and defer when the executor object has no target.

9.3.24.1. bad_executor constructor
bad_executor() noexcept;

Effects: Constructs a bad_executor object.

9.3.25. Class executor

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class executor
      {
      public:
        // construct / copy / destroy:

        executor() noexcept;
        executor(nullptr_t) noexcept;
        executor(const executor& e) noexcept;
        executor(executor&& e) noexcept;
        template<class Executor> executor(Executor e);
        template<class Executor, class Alloc>
          executor(allocator_arg_t, const Alloc& a, Executor e);

        executor& operator=(const executor& e) noexcept;
        executor& operator=(executor&& e) noexcept;
        executor& operator=(nullptr_t) noexcept;
        template<class Executor> executor& operator=(Executor e);

        ~executor();

        // executor modifiers:

        void swap(executor& other) noexcept;
        template<class Executor, class Alloc>
          void assign(Executor e, const Alloc& e);

        // executor operations:

        execution_context& context() noexcept;

        void on_work_started() noexcept;
        void on_work_finished() noexcept;

        template<class Func, class Alloc>
          void dispatch(Func&& f, const Alloc& a);
        template<class Func, class Alloc>
          void post(Func&& f, const Alloc& a);
        template<class Func, class Alloc>
          void defer(Func&& f, const Alloc& a);

        // executor capacity:

        explicit operator bool() const noexcept;

        // executor target access:

        const type_info& target_type() const noexcept;
        template<class Executor> Executor* target() noexcept;
        template<class Executor> const Executor* target() const noexcept;
      };

      template<> struct is_executor<executor> : true_type {};

      // executor comparisons:

      bool operator==(const executor& a, const executor& b) noexcept;
      bool operator==(const executor& e, nullptr_t) noexcept;
      bool operator==(nullptr_t, const executor& e) noexcept;
      bool operator!=(const executor& a, const executor& b) noexcept;
      bool operator!=(const executor& e, nullptr_t) noexcept;
      bool operator!=(nullptr_t, const executor& e) noexcept;

      // executor specialized algorithms:

      void swap(executor& a, executor& b) noexcept;

    } // inline namespace network_v1
  } // namespace experimental

  template<class Alloc>
    struct uses_allocator<std::experimental::network_v1::executor, Alloc>
      : true_type {};

} // namespace std

The executor class provides a polymorphic wrapper for types that satisfy the Executor requirements. The target object is the executor object that is held by the wrapper. The executor type itself meets the requirements for an Executor.

[Note: To meet the noexcept requirements for executor copy constructors and move constructors, implementations may share a target between two or more executor objects. —end note]

9.3.25.1. executor constructors
executor() noexcept;

Postconditions: !*this.

executor(nullptr_t) noexcept;

Postconditions: !*this.

executor(const executor& e) noexcept;

Postconditions: !*this if !e; otherwise, *this targets e.target() or a copy of e.target().

executor(executor&& e) noexcept;

Effects: If !e, *this has no target; otherwise, moves e.target() or move-constructs the target of e into the target of *this, leaving e in a valid state with an unspecified value.

template<class Executor> executor(Executor e);

Requires: Executor shall satisfy the Executor requirements.

Effects: *this targets a copy of e initialized with std::move(e).

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class Executor, class Alloc>
  executor(allocator_arg_t, const Alloc& a, Executor e);

Requires: Executor shall satisfy the Executor requirements. Allocator conforms to the Allocator requirements (C++ Std, [allocator.requirements]).

Effects: *this targets a copy of e initialized with std::move(e).

A copy of the allocator argument is used to allocate memory, if necessary, for the internal data structures of the constructed executor object.

9.3.25.2. executor assignment
executor& operator=(const executor& e) noexcept;

Effects: executor(e).swap(*this).

Returns: *this.

executor& operator=(executor&& e) noexcept;

Effects: Replaces the target of *this with the target of e, leaving e in a valid state with an unspecified value.

Returns: *this.

executor& operator=(nullptr_t) noexcept;

Effects: executor(nullptr).swap(*this).

Returns: *this.

template<class Executor> executor& operator=(Executor e);

Effects: executor(std::move(e)).swap(*this).

Returns: *this.

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

9.3.25.3. executor destructor
~executor();

Effects: If *this != nullptr, releases shared ownership of, or destroys, the target of *this.

9.3.25.4. executor modifiers
void swap(executor& other) noexcept;

Effects: Interchanges the targets of *this and other.

template<class Executor, class Alloc>
  void assign(Executor e, const Alloc& e);

Effects: executor(allocator_arg, a, std::move(e)).swap(*this).

9.3.25.5. executor operations
execution_context& context() noexcept;

Returns: e.context(), where e is the target object of *this.

void on_work_started() noexcept;

Effects: e.on_work_started(), where e is the target object of *this.

void on_work_finished() noexcept;

Effects: e.on_work_finished(), where e is the target object of *this.

template<class Func, class Alloc>
  void dispatch(Func&& f, const Alloc& a);

Effects: e.dispatch(g, a), where e is the target object of *this, and g is a function object of unspecified type that, when called as g(), performs DECAY_COPY(f)().

template<class Func, class Alloc>
  void post(Func&& f, const Alloc& a);

Effects: e.post(g, a), where e is the target object of *this, and g is a function object of unspecified type that, when called as g(), performs DECAY_COPY(f)().

template<class Func, class Alloc>
  void defer(Func&& f, const Alloc& a);

Effects: e.defer(g, a), where e is the target object of *this, and g is a function object of unspecified type that, when called as g(), performs DECAY_COPY(f)().

9.3.25.6. executor capacity
explicit operator bool() const noexcept;

Returns: true if *this has a target, otherwise false,

9.3.25.7. executor target access
const type_info& target_type() const noexcept;

Returns: If *this has a target of type T, typeid(T); otherwise, typeid(void).

template<class Executor> Executor* target() noexcept;
template<class Executor> const Executor* target() const noexcept;

Requires: Executor shall satisfy the Executor requirements.

Returns: If target_type() == typeid(Executor) a pointer to the stored executor target; otherwise a null pointer.

9.3.25.8. executor comparisons
bool operator==(const executor& a, const executor& b) noexcept;

Returns:
true if !a and !b;
true if a and b share a target;
true if e and f are the same type and e == f, where e is the target object of a and f is the target object of b;
— otherwise false.

bool operator==(const executor& e, nullptr_t) noexcept;
bool operator==(nullptr_t, const executor& e) noexcept;

Returns: !e.

bool operator!=(const executor& a, const executor& b) noexcept;

Returns: !(a == b).

bool operator!=(const executor& e, nullptr_t) noexcept;
bool operator!=(nullptr_t, const executor& e) noexcept;

Returns: (bool) e.

9.3.25.9. executor specialized algorithms
void swap(executor& a, executor& b) noexcept;

Effects: a.swap(b).

9.3.26. Function dispatch

template<class CompletionToken>
  auto dispatch(CompletionToken&& token);

Let the type Handler be the handler function object type determined by performing handler_type_t<CompletionToken, void()>.

Requires: The type Handler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object handler of type Handler, initialized with handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<Handler>, initializing the object as result(handler).
— Obtains the handler's associated executor object ex by performing get_associated_executor(handler).
— Obtains the handler's associated allocator object alloc by performing get_associated_allocator(handler).
— Performs ex.dispatch(std::move(handler), alloc).

Returns: result.get().

template<class Executor, class CompletionToken>
  auto dispatch(const Executor& ex, CompletionToken&& token);

Let the type Handler be the handler function object type determined by performing handler_type_t<CompletionToken, void()>.

Requires: The type Handler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object handler of type Handler, initialized with handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<Handler>, initializing the object as result(handler).
— Obtains the handler's associated executor object ex1 by performing get_associated_executor(handler).
— Creates a work object w by performing make_work(ex1).
— Obtains the handler's associated allocator object alloc by performing get_associated_allocator(handler).
— Constructs a function object f with a function call operator that performs ex1.dispatch(std::move(handler), alloc) followed by w.reset().
— Performs ex.dispatch(std::move(f), alloc).

Returns: result.get().

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class ExecutionContext, class CompletionToken>
  auto dispatch(ExecutionContext& ctx, CompletionToken&& token);

Returns: std::experimental::network_v1::dispatch(ctx.get_executor(), forward<CompletionToken>(token)).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

9.3.27. Function post

template<class CompletionToken>
  auto post(CompletionToken&& token);

Let the type Handler be the handler function object type determined by performing handler_type_t<CompletionToken, void()>.

Requires: The type Handler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object handler of type Handler, initialized with handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<Handler>, initializing the object as result(handler).
— Obtains the handler's associated executor object ex by performing get_associated_executor(handler).
— Obtains the handler's associated allocator object alloc by performing get_associated_allocator(handler).
— Performs ex.post(std::move(handler), alloc).

Returns: result.get().

template<class Executor, class CompletionToken>
  auto post(const Executor& ex, CompletionToken&& token);

Let the type Handler be the handler function object type determined by performing handler_type_t<CompletionToken, void()>.

Requires: The type Handler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object handler of type Handler, initialized with handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<Handler>, initializing the object as result(handler).
— Obtains the handler's associated executor object ex1 by performing get_associated_executor(handler).
— Creates a work object w by performing make_work(ex1).
— Obtains the handler's associated allocator object alloc by performing get_associated_allocator(handler).
— Constructs a function object f with a function call operator that performs ex1.dispatch(std::move(handler), alloc) followed by w.reset().
— Performs ex.post(std::move(f), alloc).

Returns: result.get().

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class ExecutionContext, class CompletionToken>
  auto post(ExecutionContext& ctx, CompletionToken&& token);

Returns: std::experimental::network_v1::post(ctx.get_executor(), forward<CompletionToken>(token)).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

9.3.28. Function defer

template<class CompletionToken>
  auto defer(CompletionToken&& token);

Let the type Handler be the handler function object type determined by performing handler_type_t<CompletionToken, void()>.

Requires: The type Handler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object handler of type Handler, initialized with handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<Handler>, initializing the object as result(handler).
— Obtains the handler's associated executor object ex by performing get_associated_executor(handler).
— Obtains the handler's associated allocator object alloc by performing get_associated_allocator(handler).
— Performs ex.defer(std::move(handler), alloc).

Returns: result.get().

template<class Executor, class CompletionToken>
  auto defer(const Executor& ex, CompletionToken&& token);

Let the type Handler be the handler function object type determined by performing handler_type_t<CompletionToken, void()>.

Requires: The type Handler must satisfy the MoveConstructible requirements (C++ Std, [moveconstructible]) and be callable with zero arguments.

Effects:
— Constructs a function object handler of type Handler, initialized with handler(forward<CompletionToken>(token)).
— Constructs an object result of type async_result<Handler>, initializing the object as result(handler).
— Obtains the handler's associated executor object ex1 by performing get_associated_executor(handler).
— Creates a work object w by performing make_work(ex1).
— Obtains the handler's associated allocator object alloc by performing get_associated_allocator(handler).
— Constructs a function object f with a function call operator that performs ex1.dispatch(std::move(handler), alloc) followed by w.reset().
— Performs ex.defer(std::move(f), alloc).

Returns: result.get().

Remarks: This function shall not participate in overload resolution unless is_executor<Executor>::value is true.

template<class ExecutionContext, class CompletionToken>
  auto defer(ExecutionContext& ctx, CompletionToken&& token);

Returns: std::experimental::network_v1::defer(ctx.get_executor(), forward<CompletionToken>(token)).

Remarks: This function shall not participate in overload resolution unless is_convertible<ExecutionContext&, execution_context&>::value is true.

9.3.29. Class template strand

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Executor>
      class strand
      {
      public:
        // types:

        typedef Executor inner_executor_type;

        // construct / copy / destroy:

        strand();
        explicit strand(Executor ex);
        strand(const strand& other);
        strand(strand&& other);
        template<class OtherExecutor> strand(const strand<OtherExecutor>& other);
        template<class OtherExecutor> strand(strand<OtherExecutor>&& other);

        strand& operator=(const strand& other);
        strand& operator=(strand&& other);
        template<class OtherExecutor> strand& operator=(const strand<OtherExecutor>& other);
        template<class OtherExecutor> strand& operator=(strand<OtherExecutor>&& other);

        ~strand();

        // strand operations:

        inner_executor_type get_inner_executor() const noexcept;

        bool running_in_this_thread() const noexcept;

        execution_context& context() noexcept;

        void on_work_started() noexcept;
        void on_work_finished() noexcept;

        template<class Func, class Alloc>
          void dispatch(Func&& f, const Alloc& a);
        template<class Func, class Alloc>
          void post(Func&& f, const Alloc& a);
        template<class Func, class Alloc>
          void defer(Func&& f, const Alloc& a);

      private:
        Executor inner_ex_; // exposition only
      };

      bool operator==(const strand<Executor>& a, const strand<Executor>& b);
      bool operator!=(const strand<Executor>& a, const strand<Executor>& b);

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

strand<Executor> is a wrapper around an object of type Executor satisfying Executor requirements. strand<Executor> satisfies the Executor requirements.

A strand provides guarantees of ordering and non-concurrency. Given:

— strand objects s1 and s2 such that s1 == s2

— a function object f1 added to the strand s1 using post or defer, or using dispatch when s1.running_in_this_thread() == false

— a function object f2 added to the strand s2 using post or defer, or using dispatch when s2.running_in_this_thread() == false

then the implementation shall invoke f1 and f2 such that:

— the invocation of f1 is not concurrent with the invocation of f2

— the invocation of f1 synchronizes with the invocation of f2.

Furthermore, if the addition of f1 happens before the addition of f2, then the invocation of f1 happens before the invocation of f2.

The strand copy constructors, comparison operators, and member functions shall not introduce data races as a result of concurrent calls to those functions from different threads.

If any function f executed by the strand throws an exception, the subsequent strand state shall be as if f had exited without throwing an exception.

9.3.29.1. strand constructors
strand();

Effects: Constructs an object of class strand<Executor> that represents a unique ordered, non-concurrent state. Initializes inner_ex_ with inner_ex_().

Remarks: This overload shall not participate in overload resolution unless Executor satisfies the DefaultConstructible requirements (C++ Std, [defaultconstructible]).

explicit strand(Executor ex);

Effects: Constructs an object of class strand<Executor> that represents a unique ordered, non-concurrent state. Initializes inner_ex_ with inner_ex_(ex).

strand(const strand& other);

Effects: Constructs an object of class strand<Executor>. Initalizes inner_ex_ with inner_ex_(other.inner_ex_).

Postconditions:
*this == other
get_inner_executor() == other.get_inner_executor()

strand(strand&& other);

Effects: Constructs an object of class strand<Executor>. Initalizes inner_ex_ with inner_ex_(std::move(other.inner_ex_)).

Postconditions:
*this is equal to the prior value of other
get_inner_executor() == other.get_inner_executor()

template<class OtherExecutor> strand(const strand<OtherExecutor>& other);

Requires: OtherExecutor is convertible to Executor.

Effects: Constructs an object of class strand<Executor>. Initalizes inner_ex_ with inner_ex_(other.inner_ex_).

Postconditions: *this == other.

template<class OtherExecutor> strand(strand<OtherExecutor>&& other);

Requires: OtherExecutor is convertible to Executor.

Effects: Constructs an object of class strand<Executor>. Initalizes inner_ex_ with inner_ex_(other.inner_ex_).

Postconditions: *this is equal to the prior value of other.

9.3.29.2. strand assignment
strand& operator=(const strand& other);

Requires: Executor is Assignable (C++ Std [assignable]).

Postconditions:
*this == other
get_inner_executor() == other.get_inner_executor()

Returns: *this.

strand& operator=(strand&& other);

Requires: Executor is Assignable (C++ Std [assignable]).

Postconditions:
*this is equal to the prior value of other
get_inner_executor() == other.get_inner_executor()

Returns: *this.

template<class OtherExecutor> strand& operator=(const strand<OtherExecutor>& other);

Requires: OtherExecutor is convertible to Executor. Executor is Assignable (C++ Std [assignable]).

Effects: Equivalent to strand<Executor>::operator=(Executor(other)).

Returns: *this.

template<class OtherExecutor> strand& operator=(strand<OtherExecutor>&& other);

Requires: OtherExecutor is convertible to Executor. Executor is Assignable (C++ Std [assignable]).

Effects: Equivalent to strand<Executor>::operator=(Executor(std::move(other))).

Returns: *this.

9.3.29.3. strand destructor
~strand();

Effects: Destroys an object of class strand<Executor>. Function objects that were added to the strand but have not yet been executed shall still be executed in a way that meets the guarantees of ordering and non-concurrency.

9.3.29.4. strand operations
inner_executor_type get_inner_executor() const noexcept;

Returns: inner_ex_.

bool running_in_this_thread() const noexcept;

Returns: true if the current thread of execution is invoking a function that was submitted to the strand, or to any other strand object s such that s == *this, using dispatch, post or defer; otherwise false.

execution_context& context() noexcept;

Returns: inner_ex_.context().

void on_work_started() noexcept;

Effects: Calls inner_ex_.on_work_started().

void on_work_finished() noexcept;

Effects: Calls inner_ex_.on_work_finished().

template<class Func, class Alloc>
  void dispatch(Func&& f, const Alloc& a);

Effects: If running_in_this_thread() is true, calls DECAY_COPY(forward<Func>(f))(). Otherwise, requests invocation of f, as if by forwarding the function object f and allocator a to the executor inner_ex_, such that the guarantees of ordering and non-concurrency are met.

If f exits via an exception, and the execution of f is performed in the current thread and before dispatch returns, the exception shall propagate to the caller of dispatch()

template<class Func, class Alloc>
  void post(Func&& f, const Alloc& a);

Effects: Requests invocation of f, as if by forwarding the function object f and allocator a to the executor inner_ex_, such that the guarantees of ordering and non-concurrency are met.

template<class Func, class Alloc>
  void defer(Func&& f, const Alloc& a);

Effects: Requests invocation of f, as if by forwarding the function object f and allocator a to the executor inner_ex_, such that the guarantees of ordering and non-concurrency are met.

9.3.29.5. strand comparisons
bool operator==(const strand<Executor>& a, const strand<Executor>& b);

Returns: true, if the strand objects share the same ordered, non-concurrent state; otherwise false.

bool operator!=(const strand<Executor>& a, const strand<Executor>& b);

Returns: !(a == b).

9.3.30. Class template use_future_t

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Allocator = allocator<void>>
      class use_future_t
      {
      public:
        // use_future_t types:
        typedef Allocator allocator_type;

        // use_future_t members:
        constexpr use_future_t() noexcept;
        explicit use_future_t(const Allocator& a) noexcept;
        template<class OtherAllocator> use_future_t<OtherAllocator>
          operator[](const OtherAllocator& a) const noexcept;
        allocator_type get_allocator() const noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The class template use_future_t defines a set of completion token types for use with asynchronous operations.

9.3.30.1. use_future_t constructors
constexpr use_future_t() noexcept;

Effects: Constructs a use_future_t with default-constructed allocator.

explicit use_future_t(const Allocator& a) noexcept;

Effects: Constructs an object of type use_future_t with post-condition get_allocator() == a.

9.3.30.2. use_future_t members
template<class OtherAllocator> use_future_t<OtherAllocator>
  operator[](const OtherAllocator& a) const noexcept;

Returns: A use_future_t object where get_allocator() == a.

allocator_type get_allocator() const noexcept;

Returns: The associated allocator object.

9.3.30.3. use_future_t traits
template<class Allocator, class R, class... Args>
struct handler_type<use_future_t<Allocator>, R(Args...)>
{
  typedef see below type;
};

An object t1 of the nested function object type type is an asynchronous provider with an associated shared state (C++Std, [futures.state]). The type type provides type::operator() such that the expression t1(declval<Args>()...) is well formed.

The implementation shall specialize associated_executor for type. For function objects executed using the associated executor's dispatch(), post() or defer() functions, any exception thrown is caught by the executor and stored in the associated shared state.

The implementation shall specialize async_result for type such that, when an async_result object r1 is constructed from t1, the expression r1.get() returns a future with the same shared state as t1.

The semantics of async_result::type and type::operator() are defined in the table below. In this table, N is the value of sizeof...(Args); let i be in the range [0..N) and let Ti be the ith type in Args; let Ui be decay<Ti>::type for each type Ti in Args; and let ai be the ith argument to type::operator().

Table 7. handler_type<use_future_t<Allocator>, R(Args...)>::type semantics

N

U0

async_result::type

type::operator effects

0

future<void>

Makes the shared state ready.

1

error_code

future<void>

If a0 evaluates to true, atomically stores the exception pointer produced by make_exception_ptr(system_error(a0)) in the shared state. The shared state is made ready.

1

exception_ptr

future<void>

If a0 is non-null, atomically stores the exception pointer a0 in the shared state. The shared state is made ready.

1

all other types

future<U0>

Atomically stores a0 in the shared state and makes that state ready.

2

error_code

future<U1>

If a0 evaluates to true, atomically stores the exception pointer produced by make_exception_ptr(system_error(a0)) in the shared state; otherwise, atomically stores a1 in the shared state. The shared state is made ready.

2

exception_ptr

future<U1>

If a0 is non-null, atomically stores the exception pointer in the shared state; otherwise, atomically stores a1 in the shared state. The shared state is made ready.

2

all other types

future<tuple<U0,U1>>

Atomically stores the result of make_tuple(a0,a1) in the shared state and makes that state ready.

>2

error_code

future<tuple<U1,...,UN-1>>

If a0 evaluates to true, atomically stores the exception pointer produced by make_exception_ptr(system_error(a0)) in the shared state; otherwise, atomically stores the result of make_tuple(a1,...,aN-1) in the shared state. The shared state is made ready.

>2

exception_ptr

future<tuple<U1,...,UN-1>>

If a0 is non-null, atomically stores the exception pointer in the shared state; otherwise, atomically stores the result of make_tuple(a1,...,aN-1) in the shared state. The shared state is made ready.

>2

all other types

future<tuple<U0,...,UN-1>>

Atomically stores the result of make_tuple(a0,...,aN-1) in the shared state and makes that state ready.


9.3.31. Class template specialization async_result for packaged_task

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class R, class... Args>
      class async_result<packaged_task<R(Args...)>>
      {
      public:
        typedef future<R> type;

        async_result(packaged_task<R(Args...)>& t);
        async_result(const async_result&) = delete;
        async_result& operator=(const async_result&) = delete;

        type get();

      private:
        type future_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The implementation shall provide a specialization of async_result that meets the async_result specialization requirements.

async_result(packaged_task<R(Args...)>& t);

Effects: Initializes future_ with t.get_future().

type get();

Returns: std::move(future_).

9.3.32. Class template packaged_handler

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Signature, class Alloc>
      class packaged_handler
        : public packaged_task<Signature>
      {
      public:
        // packaged_handler types:

        typedef Alloc allocator_type;

        // packaged_handler constructors:

        template<class Func>
          explicit packaged_handler(packaged_token<Func, Alloc>&& token);

        // packaged_handler operations:

        allocator_type get_allocator() const noexcept;

      private:
        Alloc allocator_; // exposition only
      };

      template<class Signature, class Alloc>
        class async_result<packaged_handler<Signature, Alloc>>;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
9.3.32.1. packaged_handler constructors
template<class Func>
  explicit packaged_handler(packaged_token<Func, Alloc>&& token);

Effects: Constructs an object of class packaged_handler<Signature, Alloc>, initializing the base class with packaged_task<Signature>(std::move(token.f_)) and initializing allocator_ with token.allocator_.

9.3.32.2. packaged_handler operations
allocator_type get_allocator() const noexcept;

Returns: allocator_.

9.3.32.3. Class template specialization async_result
namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Signature, class Alloc>
      class async_result<packaged_handler<Signature, Alloc>>
        : public async_result<packaged_task<Signature>>
      {
      public:
        explicit async_result(packaged_handler<Signature, Alloc>& h);
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The implementation shall provide a specialization of async_result that meets the async_result specialization requirements.

explicit async_result(packaged_handler<Signature, Alloc>& h);

Effects: Initializes the base class with h.

9.3.33. Class template packaged_token

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Func, class Alloc = allocator<void>>
      class packaged_token
      {
      public:
        // packaged_token types:

        typedef Alloc allocator_type;

        // packaged_token constructors:

        explicit packaged_token(Func f);
        packaged_token(Func f, const Alloc& a);

        // packaged_token operations:

        allocator_type get_allocator() const noexcept;

      private:
        Func f_; // exposition only
        Alloc allocator_; // exposition only
      };

      template<class Func, class Alloc, class R, class... Args>
      struct handler_type<packaged_token<Func, Alloc>, R(Args...)>
      {
        typedef packaged_handler<result_of_t<Func(Args...)>(Args...), Alloc> type;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
9.3.33.1. packaged_token constructors
explicit packaged_token(Func f);

Effects: Constructs an object of class packaged_token<Func, Alloc>, initializing f_ with std::move(f) and default constructing allocator_.

packaged_token(Func f, const Alloc& a);

Effects: Constructs an object of class packaged_token<Func, Alloc>, initializing f_ with std::move(f) and allocator_ with a.

9.3.33.2. packaged_token operations
allocator_type get_allocator() const noexcept;

Returns: allocator_.

9.3.34. Function package

template<class Func, class Alloc = allocator<void>>
  packaged_token<decay_t<Func>, Alloc> package(Func&& f, const Alloc& a = Alloc());

Returns: packaged_token<decay_t<Func>, Alloc>(forward<Func>(f), a).

9.4. Basic I/O services

9.4.1. Header <experimental/io_service> synopsis

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class io_service;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

9.4.2. Class io_service

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class io_service : public execution_context
      {
      public:
        // types:

        class executor_type;

        // construct / copy / destroy:

        io_service();
        explicit io_service(std::size_t concurrency_hint);
        io_service(const io_service&) = delete;
        io_service& operator=(const io_service&) = delete;
        ~io_service();

        // io_service operations:

        executor_type get_executor() noexcept;

        size_t run();
        template<class Rep, class Period>
          size_t run_for(const chrono::duration<Rep, Period>& rel_time);
        template<class Clock, class Duration>
          size_t run_until(const chrono::time_point<Clock, Duration>& abs_time);

        size_t run_one();
        template<class Rep, class Period>
          size_t run_one_for(const chrono::duration<Rep, Period>& rel_time);
        template<class Clock, class Duration>
          size_t run_one_until(const chrono::time_point<Clock, Duration>& abs_time);

        size_t poll();

        size_t poll_one();

        void stop();

        bool stopped() const;

        void restart();
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Synchronous operations on I/O objects implicitly run the io_service object for an individual operation. The io_service functions run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one must be called for the io_service to perform asynchronous operations on behalf of a C++ program. Notification that an asynchronous operation has completed is delivered by execution of the associated handler function object, as determined by the requirements for asynchronous operations.

An object of type io_service has an associated executor object, meeting the Executor type requirements, of type io_service::executor_type and obtainable via the io_service object's get_executor member function.

For an object of type io_service, outstanding work is defined as the sum of:

— the total number of calls to the io_service executor's on_work_started function, less the total number of calls to the on_work_finished function;

— the number of function objects that have been added to the io_service via the io_service executor, but not yet executed; and

— the number of function objects that are currently being executed by the io_service.

If at any time the outstanding work falls to 0, the io_service is stopped as if by stop().

The io_service member functions get_executor, run, run_for, run_until, run_one, run_one_for, run_one_until, poll, poll_one, stop, and stopped, and the io_service::executor_type copy constructors, member functions and comparison operators, shall not introduce data races as a result of concurrent calls to those functions from different threads. [Note: The restart member function is excluded from these thread safety requirements. —end note]

9.4.2.1. io_service constructors/destructor
io_service();
explicit io_service(std::size_t concurrency_hint);

Effects: Creates an object of class io_service.

Remarks: The concurrency_hint parameter is a suggestion to the implementation on the number of threads that should process asynchronous operations and execute function objects.

~io_service();

Effects: Destroys an object of class io_service.

9.4.2.2. io_service members
executor_type get_executor() noexcept;

Returns: An executor that may be used for submitting function objects to the io_service.

size_t run();

Requires: Must not be called from a thread that is currently calling one of run, run_for, run_until, run_one, run_one_for, run_one_until, poll, or poll_one.

Effects: Equivalent to:

size_t n = 0;
while (run_one())
  if (n != numeric_limits<size_t>::max())
    ++n;

Returns: n.

template<class Rep, class Period>
  size_t run_for(const chrono::duration<Rep, Period>& rel_time);

Effects: Equivalent to:

return run_until(chrono::steady_clock::now() + rel_time);

template<class Clock, class Duration>
  size_t run_until(const chrono::time_point<Clock, Duration>& abs_time);

Effects: Equivalent to:

size_t n = 0;
while (run_one_until(abs_time))
  if (n != numeric_limits<size_t>::max())
    ++n;

Returns: n.

size_t run_one();

Requires: Must not be called from a thread that is currently calling one of run, run_for, run_until, run_one, run_one_for, run_one_until, poll, or poll_one.

Effects: If the io_service object has no oustanding work, performs stop(). Otherwise, blocks while the io_service has outstanding work, or until the io_service is stopped, or until one function object has been executed.

If an executed function object throws an exception, the exception shall be allowed to propagate to the caller of run_one(). The io_service state shall be as if the function object had returned normally.

Returns: 1 if a function object was executed, otherwise 0.

Notes: This function may invoke additional handlers through nested calls to the io_service executor's dispatch member function. These do not count towards the return value.

template<class Rep, class Period>
  size_t run_one_for(const chrono::duration<Rep, Period>& rel_time);

Effects: Equivalent to:

return run_until(chrono::steady_clock::now() + rel_time);

Returns: 1 if a function object was executed, otherwise 0.

template<class Clock, class Duration>
  size_t run_one_until(const chrono::time_point<Clock, Duration>& abs_time);

Effects: If the io_service object has no oustanding work, performs stop(). Otherwise, blocks while the io_service has outstanding work, or until the expiration of the absolute timeout (C++ Std, [thread.req.timing]) specified by abs_time, or until the io_service is stopped, or until one function object has been executed.

If an executed function object throws an exception, the exception shall be allowed to propagate to the caller of run_one(). The io_service state shall be as if the function object had returned normally.

Returns: 1 if a function object was executed, otherwise 0.

Notes: This function may invoke additional handlers through nested calls to the io_service executor's dispatch member function. These do not count towards the return value.

size_t poll();

Effects: Equivalent to:

size_t n = 0;
while (poll_one())
  if (n != numeric_limits<size_t>::max())
    ++n;

Returns: n.

size_t poll_one();

Effects: If the io_service object has no oustanding work, performs stop(). Otherwise, if there is a function object ready for immediate execution, executes it.

If an executed function object throws an exception, the exception shall be allowed to propagate to the caller of poll_one(). The io_service state shall be as if the function object had returned normally.

Returns: 1 if a handler was invoked, otherwise 0.

Notes: This function may invoke additional handlers through nested calls to the io_service executor's dispatch member function. These do not count towards the return value.

void stop();

Effects: Stops the io_service. Concurrent calls to run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one will end as soon as possible. If a call to run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one is currently executing a function object, the call will end only after completion of that function object. The call to stop() returns without waiting for concurrent calls to run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one to complete.

Postconditions: stopped() == true.

[Note: When stopped() == true, subsequent calls to run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one will exit immediately with a return value of 0, without executing any function objects. An io_service remains in the stopped state until a call to restart(). —end note]

void restart();

Postconditions: stopped() == false.

9.4.3. Class io_service::executor_type

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class io_service::executor_type
      {
      public:
        // construct / copy / destroy:

        executor_type(const executor_type& other) noexcept;
        executor_type(executor_type&& other) noexcept;

        executor_type& operator=(const executor_type& other) noexcept;
        executor_type& operator=(executor_type&& other) noexcept;

        ~executor_type();

        // executor operations:

        bool running_in_this_thread() const noexcept;

        io_service& context() noexcept;

        void on_work_started() noexcept;
        void on_work_finished() noexcept;

        template<class Func, class Alloc>
          void dispatch(Func&& f, const Alloc& a);
        template<class Func, class Alloc>
          void post(Func&& f, const Alloc& a);
        template<class Func, class Alloc>
          void defer(Func&& f, const Alloc& a);
      };

      bool operator==(const io_service::executor_type& a,
                      const io_service::executor_type& b) noexcept;
      bool operator!=(const io_service::executor_type& a,
                      const io_service::executor_type& b) noexcept;

      template<> struct is_executor<io_service::executor_type> : true_type {};

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

io_service::executor_type is a type satisfying Executor requirements. Objects of type io_service::executor_type are associated with an io_service, and function objects submitted using the dispatch, post or defer member functions will be executed by the io_service from within the run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one functions.

9.4.3.1. io_service::executor_type constructors
executor_type(const executor_type& other) noexcept;

Effects: Constructs an object of class io_service::executor_type.

Postconditions: *this == other.

executor_type(executor_type&& other) noexcept;

Effects: Constructs an object of class io_service::executor_type.

Postconditions: *this is equal to the prior value of other.

9.4.3.2. io_service::executor_type assignment
executor_type& operator=(const executor_type& other) noexcept;

Postconditions: *this == other.

Returns: *this.

executor_type& operator=(executor_type&& other) noexcept;

Postconditions: *this is equal to the prior value of other.

Returns: *this.

9.4.3.3. executor_type operations
bool running_in_this_thread() const noexcept;

Returns: true if the current thread of execution is invoking the run, run_for, run_until, run_one, run_one_for, run_one_until, poll or poll_one function of the associated io_service object.

io_service& context() noexcept;

Returns: A reference to the associated io_service object.

void on_work_started() noexcept;

Effects: Increases the count of outstanding work associated with the io_service.

void on_work_finished() noexcept;

Effects: Decreases the count of outstanding work associated with the io_service.

template<class Func, class Alloc>
  void dispatch(Func&& f, const Alloc& a);

Effects: If running_in_this_thread() is true, calls DECAY_COPY(forward<Func>(f))(). Otherwise, requests execution of f.

If f exits via an exception, and the execution of f is performed in the current thread and before dispatch returns, the exception shall propagate to the caller of dispatch.

template<class Func, class Alloc>
  void post(Func&& f, const Alloc& a);

Effects: Requests execution of f.

template<class Func, class Alloc>
  void defer(Func&& f, const Alloc& a);

Effects: Requests execution of f.

9.4.3.4. executor_type comparisons
bool operator==(const io_service::executor_type& a,
                const io_service::executor_type& b) noexcept;

Returns: &a.context() == &b.context().

bool operator!=(const io_service::executor_type& a,
                const io_service::executor_type& b) noexcept;

Returns: !(a == b).

9.5. Timers

This subclause defines components for performing timer operations.

[Example: Performing a synchronous wait operation on a timer:

io_service i;
steady_timer t(i);
t.expires_after(seconds(5));
t.wait();

end example]

[Example: Performing an asynchronous wait operation on a timer:

void handler(error_code ec) { ... }
...
io_service i;
steady_timer t(i);
t.expires_after(seconds(5));
t.async_wait(handler);
i.run();

end example]

9.5.1. Header <experimental/timer> synopsis

#include <chrono>

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Clock> struct wait_traits;

      template<class Clock, class WaitTraits = wait_traits<Clock>>
        class basic_waitable_timer;

      typedef basic_waitable_timer<chrono::system_clock> system_timer;
      typedef basic_waitable_timer<chrono::steady_clock> steady_timer;
      typedef basic_waitable_timer<chrono::high_resolution_clock> high_resolution_timer;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

9.5.2. Requirements

9.5.2.1. Wait traits requirements

In the table below, X denotes a wait traits class for a type Clock meeting the Clock requirements (C++ Std [time.clock.req]); t denotes a value of type Clock::time_point; and d denotes a value of type Clock::duration.

Table 8. WaitTraits requirements

expression

return type

assertion/note
pre/post-condition

X::to_wait_duration(d);

Clock::duration

Returns a Clock::duration value that represents the duration d.

X::to_wait_duration(t);

Clock::duration

Returns a Clock::duration value that represents the time point t.


9.5.3. Class template wait_traits

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Clock>
      struct wait_traits
      {
        static typename Clock::duration to_wait_duration(
          const typename Clock::duration& d);

        static typename Clock::duration to_wait_duration(
          const typename Clock::time_point& t);
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

Class template wait_traits satisfies the WaitTraits type requirements. Template argument Clock is a type meeting the Clock requirements (C++ Std [time.clock.req]).

A program may specialize this template if the Clock template parameter in the specialization is a user-defined type.

9.5.3.1. Class template wait_traits members
static typename Clock::duration to_wait_duration(
  const typename Clock::duration& d);

Returns: d.

static typename Clock::duration to_wait_duration(
  const typename Clock::time_point& t);

Returns: If Clock::now() + Clock::duration::max() < t, Clock::duration::max(); if Clock::now() + Clock::duration::min() > t, Clock::duration::min(); otherwise, t - Clock::now().

9.5.4. Class template basic_waitable_timer

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class Clock, class WaitTraits = wait_traits<Clock>>
      class basic_waitable_timer
      {
      public:
        // types:

        typedef io_service::executor_type executor_type;
        typedef Clock clock_type;
        typedef typename Clock::duration duration;
        typedef typename Clock::time_point time_point;
        typedef WaitTraits traits_type;

        // construct / copy / destroy:

        explicit basic_waitable_timer(io_service& ios);
        basic_waitable_timer(io_service& ios, const time_point& t);
        basic_waitable_timer(io_service& ios, const duration& d);
        basic_waitable_timer(const basic_waitable_timer&) = delete;
        basic_waitable_timer(basic_waitable_timer&& rhs);

        ~basic_waitable_timer();

        basic_waitable_timer& operator=(const basic_waitable_timer&) = delete;
        basic_waitable_timer& operator=(basic_waitable_timer&& rhs);

        // basic_waitable_timer operations:

        executor_type get_executor() noexcept;

        size_t cancel();
        size_t cancel_one();

        time_point expiry() const;
        size_t expires_at(const time_point& t);
        size_t expires_after(const duration& d);

        void wait();
        void wait(error_code& ec);

        template<class CompletionToken>
          auto async_wait(CompletionToken&& token);
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
9.5.4.1. basic_waitable_timer constructors
explicit basic_waitable_timer(io_service& ios);

Effects: Constructs an object of class basic_waitable_timer<Clock, WaitTraits>.

Postconditions:
get_executor() == ios.get_executor().
expiry() == Clock::time_point().

basic_waitable_timer(io_service& ios, const time_point& t);

Effects: Constructs an object of class basic_waitable_timer<Clock, WaitTraits>, setting the expiry time as if by calling this->expires_at(t).

Postconditions: get_executor() == ios.get_executor().

basic_waitable_timer(io_service& ios, const duration& d);

Effects: Constructs an object of class basic_waitable_timer<Clock, WaitTraits>, setting the expiry time as if by calling this->expires_at(d).

Postconditions: get_executor() == ios.get_executor().

basic_waitable_timer(basic_waitable_timer&& rhs);

Effects: Move constructs an object of class basic_waitable_timer<Clock, WaitTraits> that refers to the state originally represented by rhs.

Postconditions:
get_executor() == rhs.get_executor().
expiry() returns the same value as rhs.expiry() prior to the constructor invocation.
rhs.expiry() == Clock::time_point().

9.5.4.2. basic_waitable_timer destructor
~basic_waitable_timer();

Effects: Destroys the timer, cancelling any asynchronous wait operations associated with the timer as if by calling cancel().

9.5.4.3. basic_waitable_timer assignment
basic_waitable_timer& operator=(basic_waitable_timer&& rhs);

Effects: Cancels any outstanding asynchronous operations associated with *this as if by calling cancel(), then moves into *this the state originally represented by rhs.

Postconditions:
get_executor() == rhs.get_executor().
expiry() returns the same value as rhs.expiry() prior to the assignment.
rhs.expiry() == Clock::time_point().

Returns: *this.

9.5.4.4. basic_waitable_timer operations
executor_type get_executor() noexcept;

Returns: The associated executor.

size_t cancel();

Effects: Causes any outstanding asynchronous wait operations to complete as soon as possible. Handlers for cancelled operations shall be passed an error code ec such that ec == errc::operation_canceled holds true.

Returns: The number of operations that were cancelled.

size_t cancel_one();

Effects: Causes the oldest outstanding asynchronous wait operation, if any, to complete as soon as possible. The handler for the cancelled operation shall be passed an error code ec such that ec == errc::operation_canceled holds true.

Returns: The number of operations that were cancelled.

time_point expiry() const;

Returns: The expiry time associated with the timer, as previously set using expires_at() or expires_after().

Returns: this->service.expires_at(this->implementation).

size_t expires_at(const time_point& t);

Effects: Sets the expiry time associated with the timer. Implicitly cancels asynchronous wait operations, as if by calling cancel().

Returns: The number of operations that were cancelled.

Postconditions: expiry() == t.

size_t expires_after(const duration& d);

Returns: expires_at(Clock::now() + d).

void wait();
void wait(error_code& ec);

Effects: Establishes the postcondition as if by repeatedly blocking the calling thread for the relative time produced by WaitTraits::to_wait_duration(expiry()).

Postconditions: !!ec || !(Clock::now() < expiry()).

template<class CompletionToken>
  auto async_wait(CompletionToken&& token);

Completion signature: void(error_code ec).

Effects: Initiates an asynchronous wait operation such that the handler is submitted for execution only when the condition !!ec || !(Clock::now() < expiry()) holds.

9.6. Buffers

9.6.1. Header <experimental/buffer> synopsis

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      enum class stream_errc {
        eof = implementation defined,
        not_found = implementation defined
      };

      const error_category& stream_category() noexcept;

      error_code make_error_code(stream_errc e) noexcept;
      error_condition make_error_condition(stream_errc e) noexcept;

      class mutable_buffer;

      class const_buffer;

      class mutable_buffers_1;

      class const_buffers_1;

      // buffer type traits:

      template<class T> is_mutable_buffer_sequence;
      template<class T> is_const_buffer_sequence;
      template<class T> is_dynamic_buffer_sequence;

      // buffer conversions:

      template<class T> T buffer_cast(const mutable_buffer& b) noexcept;
      template<class T> T buffer_cast(const const_buffer& b) noexcept;

      // buffer size:

      size_t buffer_size(const mutable_buffer& b) noexcept;
      size_t buffer_size(const const_buffer& b) noexcept;
      template<class ConstBufferSequence>
        size_t buffer_size(const ConstBufferSequence& buffers) noexcept;

      // buffer copy:

      size_t buffer_copy(const mutable_buffer& dest,
                         const const_buffer& source) noexcept;
      size_t buffer_copy(const mutable_buffer& dest,
                         const const_buffer& source,
                         size_t max_size) noexcept;
      template<class ConstBufferSequence>
        size_t buffer_copy(const mutable_buffer& dest,
                           const ConstBufferSequence& source) noexcept;
      template<class ConstBufferSequence>
        size_t buffer_copy(const mutable_buffer& dest,
                           const ConstBufferSequence& source,
                           size_t max_size) noexcept;
      template<class MutableBufferSequence>
        size_t buffer_copy(const MutableBufferSequence& dest,
                           const const_buffer& source) noexcept;
      template<class MutableBufferSequence>
        size_t buffer_copy(const MutableBufferSequence& dest,
                           const const_buffer& source,
                           size_t max_size) noexcept;
      template<class MutableBufferSequence, class ConstBufferSequence>
        size_t buffer_copy(const MutableBufferSequence& dest,
                           const ConstBufferSequence& source) noexcept;
      template<class MutableBufferSequence, class ConstBufferSequence>
        size_t buffer_copy(const MutableBufferSequence& dest,
                           const ConstBufferSequence& source,
                           max_size) noexcept;

      // buffer arithmetic:

      mutable_buffer operator+(const mutable_buffer& b, size_t n) noexcept;
      mutable_buffer operator+(size_t n, const mutable_buffer& b) noexcept;
      const_buffer operator+(const const_buffer&, size_t n) noexcept;
      const_buffer operator+(size_t, const const_buffer&) noexcept;
      mutable_buffers_1 operator+(const mutable_buffers_1& b, size_t n) noexcept;
      mutable_buffers_1 operator+(size_t n, const mutable_buffers_1& b) noexcept;
      const_buffers_1 operator+(const const_buffers_1&, size_t n) noexcept;
      const_buffers_1 operator+(size_t, const const_buffers_1&) noexcept;

      // buffer creation:

      mutable_buffers_1 buffer(void* p, size_t n) noexcept;
      const_buffers_1 buffer(const void* p, size_t n) noexcept;

      mutable_buffers_1 buffer(const mutable_buffer& b) noexcept;
      mutable_buffers_1 buffer(const mutable_buffer& b, size_t n) noexcept;
      const_buffers_1 buffer(const const_buffer& b) noexcept;
      const_buffers_1 buffer(const const_buffer& b, size_t n) noexcept;

      template<class T, size_t N>
        mutable_buffers_1 buffer(T (&arr)[N]) noexcept;
      template<class T, size_t N>
        mutable_buffers_1 buffer(T (&arr)[N], size_t n) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(const T (&arr)[N]) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(const T (&arr)[N], size_t n) noexcept;

      template<class T, size_t N>
        mutable_buffers_1 buffer(array<T, N>& arr) noexcept;
      template<class T, size_t N>
        mutable_buffers_1 buffer(array<T, N>& arr, size_t n) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(array<const T, N>& arr) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(array<const T, N>& arr, size_t n) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(const array<T, N>& arr) noexcept;
      template<class T, size_t N>
        const_buffers_1 buffer(const array<T, N>& arr, size_t n) noexcept;

      template<class T, class Allocator>
        mutable_buffers_1 buffer(vector<T, Allocator>& vec) noexcept;
      template<class T, class Allocator>
        mutable_buffers_1 buffer(vector<T, Allocator>& vec, size_t n) noexcept;
      template<class T, class Allocator>
        const_buffers_1 buffer(const vector<T, Allocator>& vec) noexcept;
      template<class T, class Allocator>
        const_buffers_1 buffer(const vector<T, Allocator>& vec, size_t n) noexcept;

      template<class CharT, class Traits, class Allocator>
        mutable_buffers_1 buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;
      template<class CharT, class Traits, class Allocator>
        mutable_buffers_1 buffer(basic_string<CharT, Traits, Allocator>& str,
                                 size_t n) noexcept;
      template<class CharT, class Traits, class Allocator>
        const_buffers_1 buffer(const basic_string<CharT, Traits, Allocator>& str) noexcept;
      template<class CharT, class Traits, class Allocator>
        const_buffers_1 buffer(const basic_string<CharT, Traits, Allocator>& str,
                               size_t n) noexcept;

      template<class T, Allocator>
        class dynamic_vector_buffer;

      template<class CharT, class Traits, Allocator>
        class dynamic_string_buffer;

      // dynamic buffer creation:

      template<class T, class Allocator>
        dynamic_vector_buffer<T, Allocator>
          dynamic_buffer(vector<T, Allocator>& vec) noexcept;
      template<class T, class Allocator>
        dynamic_vector_buffer<T, Allocator>
          dynamic_buffer(vector<T, Allocator>& vec, size_t n) noexcept;

      template<class CharT, class Traits, class Allocator>
        dynamic_string_buffer<CharT, Traits, Allocator>
          dynamic_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;
      template<class CharT, class Traits, class Allocator>
        dynamic_string_buffer<CharT, Traits, Allocator>
          dynamic_buffer(basic_string<CharT, Traits, Allocator>& str, size_t n) noexcept;

      class transfer_all;
      class transfer_at_least;
      class transfer_exactly;

      // synchronous read operations:

      template<class SyncReadStream, class MutableBufferSequence>
        size_t read(SyncReadStream& stream,
                    const MutableBufferSequence& buffers);
      template<class SyncReadStream, class MutableBufferSequence>
        size_t read(SyncReadStream& stream,
                    const MutableBufferSequence& buffers, error_code& ec);
      template<class SyncReadStream, class MutableBufferSequence,
        class CompletionCondition>
          size_t read(SyncReadStream& stream,
                      const MutableBufferSequence& buffers,
                      CompletionCondition completion_condition);
      template<class SyncReadStream, class MutableBufferSequence,
        class CompletionCondition>
          size_t read(SyncReadStream& stream,
                      const MutableBufferSequence& buffers,
                      CompletionCondition completion_condition,
                      error_code& ec);
      template<class SyncReadStream, class DynamicBufferSequence>
        size_t read(SyncReadStream& stream, DynamicBufferSequence&& b);
      template<class SyncReadStream, class DynamicBufferSequence>
        size_t read(SyncReadStream& stream, DynamicBufferSequence&& b,
                    error_code& ec);
      template<class SyncReadStream, class DynamicBufferSequence,
        class CompletionCondition>
          size_t read(SyncReadStream& stream, DynamicBufferSequence&& b,
                      CompletionCondition completion_condition);
      template<class SyncReadStream, class DynamicBufferSequence,
        class CompletionCondition>
          size_t read(SyncReadStream& stream, DynamicBufferSequence&& b,
                      CompletionCondition completion_condition,
                      error_code& ec);

      // asynchronous read operations:

      template<class AsyncReadStream, class MutableBufferSequence,
        class CompletionToken>
          auto async_read(AsyncReadStream& stream,
                          const MutableBufferSequence& buffers,
                          CompletionToken&& token);
      template<class AsyncReadStream, class MutableBufferSequence,
        class CompletionCondition, class CompletionToken>
          auto async_read(AsyncReadStream& stream,
                          const MutableBufferSequence& buffers,
                          CompletionCondition completion_condition,
                          CompletionToken&& token);
      template<class AsyncReadStream, class DynamicBufferSequence,
        class CompletionToken>
          auto async_read(AsyncReadStream& stream,
                          DynamicBufferSequence&& b,
                          CompletionToken&& token);
      template<class AsyncReadStream, class DynamicBufferSequence,
        class CompletionCondition, class CompletionToken>
          auto async_read(AsyncReadStream& stream,
                          DynamicBufferSequence&& b,
                          CompletionCondition completion_condition,
                          CompletionToken&& token);

      // synchronous write operations:

      template<class SyncWriteStream, class ConstBufferSequence>
        size_t write(SyncWriteStream& stream,
                     const ConstBufferSequence& buffers);
      template<class SyncWriteStream, class ConstBufferSequence>
        size_t write(SyncWriteStream& stream,
                     const ConstBufferSequence& buffers, error_code& ec);
      template<class SyncWriteStream, class ConstBufferSequence,
        class CompletionCondition>
          size_t write(SyncWriteStream& stream,
                       const ConstBufferSequence& buffers,
                       CompletionCondition completion_condition);
      template<class SyncWriteStream, class ConstBufferSequence,
        class CompletionCondition>
          size_t write(SyncWriteStream& stream,
                       const ConstBufferSequence& buffers,
                       CompletionCondition completion_condition,
                       error_code& ec);
      template<class SyncWriteStream, class DynamicBufferSequence>
        size_t write(SyncWriteStream& stream, DynamicBufferSequence&& b);
      template<class SyncWriteStream, class DynamicBufferSequence>
        size_t write(SyncWriteStream& stream, DynamicBufferSequence&& b,
                     error_code& ec);
      template<class SyncWriteStream, class DynamicBufferSequence,
        class CompletionCondition>
          size_t write(SyncWriteStream& stream,
                       DynamicBufferSequence&& b,
                       CompletionCondition completion_condition);
      template<class SyncWriteStream, class DynamicBufferSequence,
        class CompletionCondition>
          size_t write(SyncWriteStream& stream,
                       DynamicBufferSequence&& b,
                       CompletionCondition completion_condition,
                       error_code& ec);

      // asynchronous write operations:

      template<class AsyncWriteStream, class ConstBufferSequence,
        class CompletionToken>
          auto async_write(AsyncWriteStream& stream,
                           const ConstBufferSequence& buffers,
                           CompletionToken&& token);
      template<class AsyncWriteStream, class ConstBufferSequence,
        class CompletionCondition, class CompletionToken>
          auto async_write(AsyncWriteStream& stream,
                           const ConstBufferSequence& buffers,
                           CompletionCondition completion_condition,
                           CompletionToken&& token);
      template<class AsyncWriteStream, class DynamicBufferSequence,
        class CompletionToken>
          auto async_write(AsyncWriteStream& stream,
                           DynamicBufferSequence&& b,
                           CompletionToken&& token);
      template<class AsyncWriteStream, class DynamicBufferSequence,
        class CompletionCondition, class CompletionToken>
          auto async_write(AsyncWriteStream& stream,
                           DynamicBufferSequence&& b,
                           CompletionCondition completion_condition,
                           CompletionToken&& token);

      // synchronous delimited read operations:

      template<class SyncReadStream, class DynamicBufferSequence>
        size_t read_until(SyncReadStream& s, DynamicBufferSequence&& b,
                          char delim);
      template<class SyncReadStream, class DynamicBufferSequence>
        size_t read_until(SyncReadStream& s, DynamicBufferSequence&& b,
                          char delim, error_code& ec);
      template<class SyncReadStream, class DynamicBufferSequence>
        size_t read_until(SyncReadStream& s, DynamicBufferSequence&& b,
                          const string& delim);
      template<class SyncReadStream, class DynamicBufferSequence>
        size_t read_until(SyncReadStream& s, DynamicBufferSequence&& b,
                          const string& delim, error_code& ec);

      // asynchronous delimited read operations:

      template<class AsyncReadStream, class DynamicBufferSequence,
        class CompletionToken>
          auto async_read_until(AsyncReadStream& s,
                                DynamicBufferSequence&& b, char delim,
                                CompletionToken&& token);
      template<class AsyncReadStream, class DynamicBufferSequence,
        class CompletionToken>
          auto async_read_until(AsyncReadStream& s,
                                DynamicBufferSequence&& b,
                                const string& delim, CompletionToken&& token);

    } // inline namespace network_v1
  } // namespace experimental

  template<> struct is_error_code_enum<
    experimental::network_v1::stream_errc>
      : public true_type {};

} // namespace std

9.6.2. Requirements

9.6.2.1. Convertible to mutable buffer requirements

A type that meets the requirements for convertibility to a mutable buffer must meet the requirements of CopyConstructible types (C++ Std, 20.1.3), and the requirements of Assignable types (C++ Std, 23.1).

In the table below, X denotes a class meeting the requirements for convertibility to a mutable buffer, a and b denote values of type X, and u, v and w denote identifiers.

Table 9. ConvertibleToMutableBuffer requirements

expression

postcondition

mutable_buffer u(a);
mutable_buffer v(a);

buffer_cast<void*>(u) == buffer_cast<void*>(v)
  && buffer_size(u) == buffer_size(v)

mutable_buffer u(a);
mutable_buffer v = a;

buffer_cast<void*>(u) == buffer_cast<void*>(v)
  && buffer_size(u) == buffer_size(v)

mutable_buffer u(a);
mutable_buffer v; v = a;

buffer_cast<void*>(u) == buffer_cast<void*>(v)
  && buffer_size(u) == buffer_size(v)

mutable_buffer u(a);
const X& v = a;
mutable_buffer w(v);

buffer_cast<void*>(u) == buffer_cast<void*>(w)
  && buffer_size(u) == buffer_size(w)

mutable_buffer u(a);
X v(a);
mutable_buffer w(v);

buffer_cast<void*>(u) == buffer_cast<void*>(w)
  && buffer_size(u) == buffer_size(w)

mutable_buffer u(a);
X v = a;
mutable_buffer w(v);

buffer_cast<void*>(u) == buffer_cast<void*>(w)
  && buffer_size(u) == buffer_size(w)

mutable_buffer u(a);
X v(b); v = a;
mutable_buffer w(v);

buffer_cast<void*>(u) == buffer_cast<void*>(w)
  && buffer_size(u) == buffer_size(w)


9.6.2.2. Mutable buffer sequence requirements

In the table below, X denotes a class containing objects of type T, a denotes a value of type X and u denotes an identifier.

Table 10. MutableBufferSequence requirements

expression

return type

assertion/note
pre/post-condition

X::value_type

T

T meets the requirements for ConvertibleToMutableBuffer.

X::const_iterator

iterator type pointing to T

const_iterator meets the requirements for bidirectional iterators (C++ Std, [bidirection.iterators]).

X(a);
X u(a);

post:

equal(begin(), end(), a.begin(), a.end(),
  [](const typename X::value_type& v1,
     const typename X::value_type& v2)
   {
     mutable_buffer b1(v1);
     mutable_buffer b2(v2);
     return buffer_cast<void*>(b1)
       == buffer_cast<void*>(b2)
         && buffer_size(b1) == buffer_size(b2);
   });

(&a)->~X();

void

note: the destructor is applied to every element of a; all the memory is deallocated.

a.begin();

const_iterator or convertible to const_iterator

a.end();

const_iterator or convertible to const_iterator


9.6.2.3. Convertible to const buffer requirements

A type that meets the requirements for convertibility to a const buffer must meet the requirements of CopyConstructible types (C++ Std, 20.1.3), and the requirements of Assignable types (C++ Std, 23.1).

In the table below, X denotes a class meeting the requirements for convertibility to a const buffer, a and b denote values of type X, and u, v and w denote identifiers.

Table 11. ConvertibleToConstBuffer requirements

expression

postcondition

const_buffer u(a);
const_buffer v(a);

buffer_cast<const void*>(u) == buffer_cast<const void*>(v)
  && buffer_size(u) == buffer_size(v)

const_buffer u(a);
const_buffer v = a;

buffer_cast<const void*>(u) == buffer_cast<const void*>(v)
  && buffer_size(u) == buffer_size(v)

const_buffer u(a);
const_buffer v; v = a;

buffer_cast<const void*>(u) == buffer_cast<const void*>(v)
  && buffer_size(u) == buffer_size(v)

const_buffer u(a);
const X& v = a;
const_buffer w(v);

buffer_cast<const void*>(u) == buffer_cast<const void*>(w)
  && buffer_size(u) == buffer_size(w)

const_buffer u(a);
X v(a);
const_buffer w(v);

buffer_cast<const void*>(u) == buffer_cast<const void*>(w)
  && buffer_size(u) == buffer_size(w)

const_buffer u(a);
X v = a;
const_buffer w(v);

buffer_cast<const void*>(u) == buffer_cast<const void*>(w)
  && buffer_size(u) == buffer_size(w)

const_buffer u(a);
X v(b); v = a;
const_buffer w(v);

buffer_cast<const void*>(u) == buffer_cast<const void*>(w)
  && buffer_size(u) == buffer_size(w)


9.6.2.4. Constant buffer sequence requirements

In the table below, X denotes a class containing objects of type T, a denotes a value of type X and u denotes an identifier.

Table 12. ConstBufferSequence requirements

expression

return type

assertion/note
pre/post-condition

X::value_type

T

T meets the requirements for ConvertibleToConstBuffer.

X::const_iterator

iterator type pointing to T

const_iterator meets the requirements for bidirectional iterators (C++ Std, [bidirection.iterators]).

X(a);
X u(a);

post:

equal(begin(), end(), a.begin(), a.end(),
  [](const typename X::value_type& v1,
     const typename X::value_type& v2)
   {
     const_buffer b1(v1);
     const_buffer b2(v2);
     return buffer_cast<const void*>(b1)
       == buffer_cast<const void*>(b2)
         && buffer_size(b1) == buffer_size(b2);
   });

(&a)->~X();

void

note: the destructor is applied to every element of a; all the memory is deallocated.

a.begin();

const_iterator or convertible to const_iterator

a.end();

const_iterator or convertible to const_iterator


9.6.2.5. Dynamic buffer sequence requirements

A dynamic buffer sequence encapsulates memory storage that may be automatically resized as required, where the memory is divided into an input sequence followed by an output sequence. These memory regions are internal to the dynamic buffer sequence, but direct access to the elements is provided to permit them to be efficiently used with I/O operations, such as the send or receive operations of a socket. Data written to the output sequence of a dynamic buffer sequence object is appended to the input sequence of the same object.

A dynamic buffer sequence type X shall satisfy the requirements of MoveConstructible (C++ Std, [moveconstructible]) types in addition to those listed below.

In the table below, X denotes a dynamic buffer sequence class, x denotes a value of type X&, x1 denotes values of type const X&, and n denotes a value of type size_t, and u denotes an identifier.

Table 13. DynamicBufferSequence requirements

expression

type

assertion/note
pre/post-conditions

X::const_buffers_type

type meeting ConstBufferSequence requirements.

This type represents the memory associated with the input sequence.

X::mutable_buffers_type

type meeting MutableBufferSequence requirements.

This type represents the memory associated with the output sequence.

x1.size()

size_t

Returns the size, in bytes, of the input sequence.

x1.max_size()

size_t

Returns the permitted maximum of the sum of the sizes of the input sequence and output sequence.

x1.capacity()

size_t

Returns the maximum sum of the sizes of the input sequence and output sequence that the dynamic buffer sequence can hold without requiring reallocation.

x1.data()

X::const_buffers_type

Returns a constant buffer sequence u that represents the memory associated with the input sequence, and where buffer_size(u) == size().

x.prepare(n)

X::mutable_buffers_type

Requires: size() + n <= max_size().

Returns a mutable buffer sequence u representing the output sequence, and where buffer_size(u) == n. The dynamic buffer sequence reallocates memory as required. All constant or mutable buffer sequences previously obtained using data() or prepare() are invalidated.

Throws: length_error if size() + n > max_size().

x.commit(n)

Appends n bytes from the start of the output sequence to the end of the input sequence. The remainder of the output sequence is discarded. If n is greater than the size of the output sequence, the entire output sequence is appended to the input sequence. All constant or mutable buffer sequences previously obtained using data() or prepare() are invalidated.

x.consume(n)

Removes n bytes from beginning of the input sequence. If n is greater than the size of the input sequence, the entire input sequence is removed. All constant or mutable buffer sequences previously obtained using data() or prepare() are invalidated.


9.6.2.6. Requirements on synchronous read operations

In this clause, a synchronous read operation is a function that reads data into a mutable buffer sequence argument of a type meeting MutableBufferSequence requirements.

The mutable buffer sequence specifies memory where the data should be placed. A synchronous read operation shall always fill a buffer in the sequence completely before proceeding to the next.

9.6.2.7. Requirements on asynchronous read operations

In this clause, an asynchronous read operation is an asynchronous operation that reads data into a mutable buffer sequence argument of a type meeting MutableBufferSequence requirements.

The mutable buffer sequence specifies memory where the data should be placed. An asynchronous read operation shall always fill a buffer in the sequence completely before proceeding to the next.

The read operation's implementation shall maintain one or more copies of the buffer sequence until such time as the read operation no longer requires access to the memory specified by the buffers in the sequence. The program must ensure the memory is valid until:

— the last copy of the buffer sequence is destroyed, or

— the handler for the asynchronous operation is invoked,

whichever comes first.

9.6.2.8. Requirements on synchronous write operations

In this clause, a synchronous write operation is a function that writes data from a constant buffer sequence argument of a type meeting ConstBufferSequence requirements.

The constant buffer sequence specifies memory where the data to be written is located. A synchronous write operation shall always write a buffer in the sequence completely before proceeding to the next.

9.6.2.9. Requirements on asynchronous write operations

In this clause, an asynchronous write operation is an asynchronous operation that writes data from a constant buffer sequence argument of a type meeting ConstBufferSequence requirements.

The constant buffer sequence specifies memory where the data to be written is located. An asynchronous write operation shall always write a buffer in the sequence completely before proceeding to the next.

The write operation's implementation shall maintain one or more copies of the buffer sequence until such time as the write operation no longer requires access to the memory specified by the buffers in the sequence. The program must ensure the memory is valid until:

— the last copy of the buffer sequence is destroyed, or

— the handler for the asynchronous operation is invoked,

whichever comes first.

9.6.2.10. Buffer-oriented synchronous read stream requirements

In the table below, a denotes a synchronous read stream object, mb denotes an object satisfying mutable buffer sequence requirements, and ec denotes an object of type error_code.

Table 14. Buffer-oriented synchronous read stream requirements

operation

type

semantics, pre/post-conditions

a.read_some(mb);

size_t

Equivalent to:

error_code ec;
size_t s = a.read_some(mb, ec);
if (ec) throw system_error(ec, __func__);
return s;

a.read_some(mb,ec);

size_t

Meets the requirements for a synchronous read operation.

Reads one or more bytes of data from the stream a.

If successful, returns the number of bytes read and sets ec such that !ec is true. If an error occurred, returns 0 and sets ec such that !!ec is true. If all data has been read from the stream and the stream has been shut down in an orderly manner, sets ec such that ec == stream_errc::eof.

The operation shall not block if buffer_size(mb) == 0.


9.6.2.11. Buffer-oriented asynchronous read stream requirements

In the table below, a denotes an asynchronous read stream object, mb denotes an object satisfying mutable buffer sequence requirements, and t is a completion token.

Table 15. Buffer-oriented asynchronous read stream requirements

operation

type

semantics, pre/post-conditions

a.get_executor();

A type satisfying the Executor requirements.

Returns the associated I/O executor.

a.async_read_some(mb,t);

The return type is determined according to the requirements for an asynchronous operation.

Meets the requirements for an asynchronous read operation with completion signature void(error_code ec, size_t n).

Initiates an asynchronous operation to read one or more bytes of data from the stream a.

If successful, n is the number of bytes read and ec is set such that !ec is true. If an error occurred, n is 0 and ec is set such that !!ec is true. If all data has been read from the stream and the stream has been shut down in an orderly manner, n is 0 and ec is set such that ec == stream_errc::eof.

The operation shall complete immediately if buffer_size(mb) == 0.


9.6.2.12. Buffer-oriented synchronous write stream requirements

In the table below, a denotes a synchronous write stream object, cb denotes an object satisfying constant buffer sequence requirements, and ec denotes an object of type error_code.

Table 16. Buffer-oriented synchronous write stream requirements

operation

type

semantics, pre/post-conditions

a.write_some(cb);

size_t

Equivalent to:

error_code ec;
size_t s = a.write_some(cb, ec);
if (ec) throw system_error(ec, __func__);
return s;

a.write_some(cb,ec);

size_t

Meets the requirements for a synchronous write operation.

Writes one or more bytes of data to the stream a.

If successful, returns the number of bytes written and sets ec such that !ec is true. If an error occurred, returns 0 and sets ec such that !!ec is true.

The operation shall not block if buffer_size(cb) == 0.


9.6.2.13. Buffer-oriented asynchronous write stream requirements

In the table below, a denotes an asynchronous write stream object, cb denotes an object satisfying constant buffer sequence requirements, and t is a completion token.

Table 17. Buffer-oriented asynchronous write stream requirements

operation

type

semantics, pre/post-conditions

a.get_executor();

A type satisfying the Executor requirements.

Returns the associated I/O executor.

a.async_write_some(cb,t);

The return type is determined according to the requirements for an asynchronous operation.

Meets the requirements for an asynchronous write operation with completion signature void(error_code ec, size_t n).

Initiates an asynchronous operation to write one or more bytes of data to the stream a.

If successful, n is the number of bytes written and ec is set such that !ec is true. If an error occurred, n is 0 and ec is set such that !!ec is true.

The operation shall complete immediately if buffer_size(cb) == 0.


9.6.3. Class mutable_buffer

The mutable_buffer class meets the requirements for ConvertibleToMutableBuffer and ConvertibleToConstBuffer.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class mutable_buffer
      {
      public:
        // constructors:
        mutable_buffer() noexcept;
        mutable_buffer(void* p, size_t n) noexcept;

      private:
        void* data_; // exposition only
        size_t size_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
9.6.3.1. mutable_buffer constructors
mutable_buffer() noexcept;

Postconditions: data_ == nullptr and size_ == 0.

mutable_buffer(void* p, size_t n) noexcept;

Postconditions: data_ == p and size_ == n.

9.6.4. Class const_buffer

The const_buffer class meets the requirements for ConvertibleToConstBuffer.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class const_buffer
      {
      public:
        // constructors:
        const_buffer() noexcept;
        const_buffer(const void* p, size_t n) noexcept;
        const_buffer(const mutable_buffer& b) noexcept;

      private:
        const void* data_; // exposition only
        size_t size_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std
9.6.4.1. const_buffer constructors
const_buffer() noexcept;

Postconditions: data_ == nullptr and size_t == 0.

const_buffer(const void* p, size_t n) noexcept;

Postconditions: data_ == p and size_ == n.

const_buffer(const mutable_buffer& b);

Postconditions: data_ == b.data_ and size_ == b.size_.

9.6.5. Class mutable_buffers_1

The mutable_buffers_1 class meets the requirements for MutableBufferSequence, ConstBufferSequence, ConvertibleToMutableBuffer, and ConvertibleToConstBuffer.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class mutable_buffers_1 :
        public mutable_buffer
      {
      public:
        // types:
        typedef mutable_buffer value_type;
        typedef unspecified const_iterator;

        // constructors:
        mutable_buffers_1(void* p, size_t n) noexcept;
        explicit mutable_buffers_1(const mutable_buffer& b) noexcept;

        // members:
        const_iterator begin() const noexcept;
        const_iterator end() const noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

An object of class mutable_buffers_1 represents a sequence of exactly one mutable_buffer object.

9.6.5.1. mutable_buffers_1 constructors
mutable_buffers_1(const void* p, size_t n) noexcept;

Effects: Constructs an object of class mutable_buffers_1, initializing the base class with mutable_buffer(p, n).

explicit mutable_buffers_1(const mutable_buffer& b) noexcept;

Effects: Constructs an object of class mutable_buffers_1, initializing the base class with mutable_buffer(b).

9.6.5.2. mutable_buffers_1 members
const_iterator begin() const noexcept;

Returns: An iterator referring to the first (and only) mutable_buffer object in the sequence.

const_iterator end() const noexcept;

Returns: An iterator which is the past-the-end value.

9.6.6. Class const_buffers_1

The const_buffers_1 class meets the requirements for ConstBufferSequence, and ConvertibleToConstBuffer.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class const_buffers_1 :
        public const_buffer
      {
      public:
        // types:
        typedef const_buffer value_type;
        typedef unspecified const_iterator;

        // constructors:
        const_buffers_1(const void* p, size_t n) noexcept;
        explicit const_buffers_1(const const_buffer& b) noexcept;

        // members:
        const_iterator begin() const noexcept;
        const_iterator end() const noexcept;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

An object of class const_buffers_1 represents a sequence of exactly one const_buffer object.

9.6.6.1. const_buffers_1 constructors
const_buffers_1(const void* p, size_t n) noexcept;

Effects: Constructs an object of class const_buffers_1, initializing the base class with const_buffer(p, n).

explicit const_buffers_1(const const_buffer& b) noexcept;

Effects: Constructs an object of class const_buffers_1, initializing the base class with const_buffer(b).

9.6.6.2. const_buffers_1 members
const_iterator begin() const noexcept;

Returns: An iterator referring to the first (and only) const_buffer object in the sequence.

const_iterator end() const noexcept;

Returns: An iterator which is the past-the-end value.

9.6.7. Buffer type traits

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T> is_mutable_buffer_sequence;
      template<class T> is_const_buffer_sequence;
      template<class T> is_dynamic_buffer_sequence;

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

This sub-clause contains templates that may be used to query the properties of a type at compile time. Each of these templates shall be a UnaryTypeTrait (C++ Std, [meta.rqmts]) with a BaseCharacteristic of true_type if the corresponding condition is true, otherwise false_type.

Table 18. Buffer type traits

Template

Condition

Preconditions

template<class T> is_mutable_buffer_sequence

T meets the requirements for mutable buffer sequence.

T is a complete type.

template<class T> is_const_buffer_sequence

T meets the requirements for constant buffer sequence.

T is a complete type.

template<class T> is_dynamic_buffer_sequence

T meets the requirements for dynamic buffer sequence.

T is a complete type.


9.6.8. Function buffer_cast

template<class T> T buffer_cast(const mutable_buffer& b) noexcept;
template<class T> T buffer_cast(const const_buffer& b) noexcept;

Returns: static_cast<T>(b.data_).

9.6.9. Function buffer_size

size_t buffer_size(const mutable_buffer& b) noexcept;
size_t buffer_size(const const_buffer& b) noexcept;

Returns: b.size_.

template<class ConstBufferSequence>
  size_t buffer_size(const ConstBufferSequence& buffers) noexcept;

Returns: The total size of all buffers in the sequence, as if computed as follows:

size_t total_size = 0;
for (const auto& v: buffers)
{
  const_buffer b(v);
  total_size += b.size_;
}
return total_size;

Remarks: This function overload shall not participate in overload resolution unless is_const_buffer_sequence<ConstBufferSequence>::value is true.

9.6.10. Function buffer_copy

size_t buffer_copy(const mutable_buffer& dest,
                   const const_buffer& source) noexcept;
size_t buffer_copy(const mutable_buffer& dest,
                   const const_buffer& source,
                   size_t max_size) noexcept;
template<class ConstBufferSequence>
  size_t buffer_copy(const mutable_buffer& dest,
                     const ConstBufferSequence& source) noexcept;
template<class ConstBufferSequence>
  size_t buffer_copy(const mutable_buffer& dest,
                     const ConstBufferSequence& source,
                     size_t max_size) noexcept;
template<class MutableBufferSequence>
  size_t buffer_copy(const MutableBufferSequence& dest,
                     const const_buffer& source) noexcept;
template<class MutableBufferSequence>
  size_t buffer_copy(const MutableBufferSequence& dest,
                     const const_buffer& source,
                     size_t max_size) noexcept;
template<class MutableBufferSequence, class ConstBufferSequence>
  size_t buffer_copy(const MutableBufferSequence& dest,
                     const ConstBufferSequence& source) noexcept;
template<class MutableBufferSequence, class ConstBufferSequence>
  size_t buffer_copy(const MutableBufferSequence& dest,
                     const ConstBufferSequence& source,
                     max_size) noexcept;

Effects: Copies bytes from the buffer or buffer sequence source to the buffer or buffer sequence dest, as if by calls to memcpy.

The number of bytes copied is the lesser of:
buffer_size(dest);
buffer_size(source); and
max_size, if specified.

The mutable buffer or mutable buffer sequence dest specifies memory where the data should be placed. The operation shall always fill a buffer in the sequence completely before proceeding to the next.

The constant buffer or constant buffer sequence source specifies memory where the data to be written is located. The operation shall always copy a buffer in the sequence completely before proceeding to the next.

Returns: The number of bytes copied from source to dest.

Remarks: Where an overload accepts a template parameter MutableBufferSequence, the overload shall not participate in overload resolution unless is_mutable_buffer_sequence<MutableBufferSequence>::value is true. Where an overload accepts a template parameter ConstBufferSequence, the overload shall not participate in overload resolution unless is_const_buffer_sequence<ConstBufferSequence>::value is true.

9.6.11. Buffer arithmetic

mutable_buffer operator+(const mutable_buffer& b, size_t n) noexcept;
mutable_buffer operator+(size_t n, const mutable_buffer& b) noexcept;

Returns: A mutable_buffer equivalent to

mutable_buffer(
  buffer_cast<char*>(b) + min(n, buffer_size(b)),
  buffer_size(b) - min(n, buffer_size(b)));

const_buffer operator+(const const_buffer& b, size_t n) noexcept;
const_buffer operator+(size_t n, const const_buffer& b) noexcept;

Returns: A const_buffer equivalent to

const_buffer(
  buffer_cast<const char*>(b) + min(n, buffer_size(b)),
  buffer_size(b) - min(n, buffer_size(b)));

mutable_buffers_1 operator+(const mutable_buffers_1& b, size_t n) noexcept;
mutable_buffers_1 operator+(size_t n, const mutable_buffers_1& b) noexcept;

Returns: A mutable_buffers_1 equivalent to

mutable_buffers_1(
  buffer_cast<char*>(b) + min(n, buffer_size(b)),
  buffer_size(b) - min(n, buffer_size(b)));

const_buffers_1 operator+(const const_buffers_1& b, size_t n) noexcept;
const_buffers_1 operator+(size_t n, const const_buffers_1& b) noexcept;

Returns: A const_buffers_1 equivalent to

const_buffers_1(
  buffer_cast<const char*>(b) + min(n, buffer_size(b)),
  buffer_size(b) - min(n, buffer_size(b)));

9.6.12. Buffer creation functions

In the functions below, T must be a POD type.

For the function overloads below that accept an argument of type vector<>, the buffer objects returned are invalidated by any vector operation that also invalidates all references, pointers and iterators referring to the elements in the sequence (C++ Std, [vector]).

For the function overloads below that accept an argument of type basic_string<>, the buffer objects returned are invalidated according to the rules defined for invalidation of references, pointers and iterators referring to elements of the sequence (C++ Std, [string.require]).

mutable_buffers_1 buffer(void* p, size_t n) noexcept;

Returns: mutable_buffers_1(p, n).

const_buffers_1 buffer(const void* p, size_t n) noexcept;

Returns: const_buffers_1(p, n).

mutable_buffers_1 buffer(const mutable_buffer& b) noexcept;

Returns: mutable_buffers_1(b).

mutable_buffers_1 buffer(const mutable_buffer& b, size_t n) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  buffer_cast<void*>(b),
  min(buffer_size(b), n));

const_buffers_1 buffer(const const_buffer& b) noexcept;

Returns: const_buffers_1(b).

const_buffers_1 buffer(const const_buffer& b, size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  buffer_cast<const void*>(b),
  min(buffer_size(b), n));

template<class T, size_t N>
  mutable_buffers_1 buffer(T (&arr)[N]) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  static_cast<void*>(arr),
  N * sizeof(T));

template<class T, size_t N>
  mutable_buffers_1 buffer(T (&arr)[N], size_t n) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  static_cast<void*>(arr),
  min(N * sizeof(T), n));

template<class T, size_t N>
  const_buffers_1 buffer(const T (&arr)[N]) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  static_cast<const void*>(arr),
  N * sizeof(T));

template<class T, size_t N>
  const_buffers_1 buffer(const T (&arr)[N], size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  static_cast<const void*>(arr),
  min(N * sizeof(T), n));

template<class T, size_t N>
  mutable_buffers_1 buffer(array<T, N>& arr) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  arr.data(),
  arr.size() * sizeof(T));

template<class T, size_t N>
  mutable_buffers_1 buffer(array<T, N>& arr, size_t n) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  arr.data(),
  min(arr.size() * sizeof(T), n));

template<class T, size_t N>
  const_buffers_1 buffer(array<const T, N>& arr) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  arr.data(),
  arr.size() * sizeof(T));

template<class T, size_t N>
  const_buffers_1 buffer(array<const T, N>& arr, size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  arr.data(),
  min(arr.size() * sizeof(T), n));

template<class T, size_t N>
  const_buffers_1 buffer(const array<T, N>& arr) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  arr.data(),
  arr.size() * sizeof(T));

template<class T, size_t N>
  const_buffers_1 buffer(const array<T, N>& arr, size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  arr.data(),
  min(arr.size() * sizeof(T), n));

template<class T, class Allocator>
  mutable_buffers_1 buffer(vector<T, Allocator>& vec) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  vec.size() ? &vec[0] : nullptr,
  vec.size() * sizeof(T));

template<class T, class Allocator>
  mutable_buffers_1 buffer(vector<T, Allocator>& vec, size_t n) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  vec.size() ? &vec[0] : nullptr,
  min(vec.size() * sizeof(T), n));

template<class T, class Allocator>
  const_buffers_1 buffer(const vector<T, Allocator>& vec) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  vec.size() ? &vec[0] : nullptr,
  vec.size() * sizeof(T));

template<class T, class Allocator>
  const_buffers_1 buffer(const vector<T, Allocator>& vec, size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  vec.size() ? &vec[0] : nullptr,
  min(vec.size() * sizeof(T), n));

template<class CharT, class Traits, class Allocator>
  mutable_buffers_1 buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  str.size() ? &str[0] : nullptr,
  str.size() * sizeof(CharT));

template<class CharT, class Traits, class Allocator>
  mutable_buffers_1 buffer(basic_string<CharT, Traits, Allocator>& str,
                           size_t n) noexcept;

Returns: A mutable_buffers_1 value equivalent to:

mutable_buffers_1(
  str.size() ? &str[0] : nullptr,
  min(str.size() * sizeof(CharT), n));

template<class CharT, class Traits, class Allocator>
  const_buffers_1 buffer(const basic_string<CharT, Traits, Allocator>& str) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  str.data()
  str.size() * sizeof(CharT));

template<class CharT, class Traits, class Allocator>
  const_buffers_1 buffer(const basic_string<CharT, Traits, Allocator>& str,
                         size_t n) noexcept;

Returns: A const_buffers_1 value equivalent to:

const_buffers_1(
  str.data()
  min(str.size() * sizeof(CharT), n));

9.6.13. Class template dynamic_vector_buffer

The dynamic_vector_buffer class template meets the requirements for DynamicBufferSequence.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class T, class Allocator>
      class dynamic_vector_buffer
      {
      public:
        // types:
        typedef const_buffers_1 const_buffers_type;
        typedef mutable_buffers_1 mutable_buffers_type;

        // constructors:
        explicit dynamic_vector_buffer(vector<T, Allocator>& vec) noexcept;
        dynamic_vector_buffer(vector<T, Allocator>& vec,
                              size_t maximum_size) noexcept;
        dynamic_vector_buffer(dynamic_vector_buffer&&) = default;

        // members:
        size_t size() const noexcept;
        size_t max_size() const noexcept;
        size_t capacity() const noexcept;
        const_buffers_type data() const noexcept;
        mutable_buffers_type prepare(size_t n);
        void commit(size_t n);
        void consume(size_t n);

      private:
        vector<T, Allocator>& vec_; // exposition only
        size_t size_; // exposition only
        const size_t max_size_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The dynamic_vector_buffer class template requires that T is a POD type and that sizeof(T) == 1.

9.6.13.1. dynamic_vector_buffer constructors
explicit dynamic_vector_buffer(vector<T, Allocator>& vec) noexcept;

Effects: Constructs an object of type dynamic_vector_buffer, binding vec_ to vec, initializing size_ with vec.size(), and initializing max_size_ with vec.max_size().

dynamic_vector_buffer(vector<T, Allocator>& vec,
                      size_t maximum_size) noexcept;

Requires: vec.size() <= maximum_size.

Effects: Constructs an object of type dynamic_vector_buffer, binding vec_ to vec, initializing size_ with vec.size(), and initializing max_size_ with maximum_size.

9.6.13.2. dynamic_vector_buffer members
size_t size() const noexcept;

Returns: size_.

size_t max_size() const noexcept;

Returns: max_size_.

size_t capacity() const noexcept;

Returns: vec_.capacity().

const_buffers_type data() const noexcept;

Returns: buffer(vec_, size_).

mutable_buffers_type prepare(size_t n);

Requires: size() + n <= max_size().

Effects: Performs str.resize(size_ + n).

Returns: buffer(buffer(vec_) + size_, n).

Throws: length_error if size() + n > max_size().

void commit(size_t n);

Effects: Performs:

size_ += min(n, vec_.size() - size_);
vec_.resize(size_);

void consume(size_t n);

Effects: Performs:

size_t m = min(n, size_);
vec_.erase(vec_.begin(), vec_.begin() + m);
size_ -= m;

9.6.14. Class template dynamic_string_buffer

The dynamic_string_buffer class template meets the requirements for DynamicBufferSequence.

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      template<class CharT, class Traits, class Allocator>
      class dynamic_string_buffer
      {
      public:
        // types:
        typedef const_buffers_1 const_buffers_type;
        typedef mutable_buffers_1 mutable_buffers_type;

        // constructors:
        explicit dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;
        dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str,
                              size_t maximum_size) noexcept;
        dynamic_string_buffer(dynamic_string_buffer&&) = default;

        // members:
        size_t size() const noexcept;
        size_t max_size() const noexcept;
        size_t capacity() const noexcept;
        const_buffers_type data() const noexcept;
        mutable_buffers_type prepare(size_t n);
        void commit(size_t n) noexcept;
        void consume(size_t n);

      private:
        basic_string<CharT, Traits, Allocator>& str_; // exposition only
        size_t size_; // exposition only
        const size_t max_size_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The dynamic_string_buffer class template requires that sizeof(CharT) == 1.

9.6.14.1. dynamic_string_buffer constructors
explicit dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;

Effects: Constructs an object of type dynamic_string_buffer, binding str_ to str, initializing size_ with str.size(), and initializing max_size_ with str.max_size().

dynamic_string_buffer(basic_string<CharT, Traits, Allocator>& str,
                      size_t maximum_size) noexcept;

Requires: str.size() <= maximum_size.

Effects: Constructs an object of type dynamic_string_buffer, binding str_ to str, initializing size_ with str.size(), and initializing max_size_ with maximum_size.

9.6.14.2. dynamic_string_buffer members
size_t size() const noexcept;

Returns: size_.

size_t max_size() const noexcept;

Returns: max_size_.

size_t capacity() const noexcept;

Returns: str_.capacity().

const_buffers_type data() const noexcept;

Returns: buffer(str_, size_).

mutable_buffers_type prepare(size_t n);

Requires: size() + n <= max_size().

Effects: Performs str.resize(size_ + n).

Returns: buffer(buffer(str_) + size_, n).

Throws: length_error if size() + n > max_size().

void commit(size_t n) noexcept;

Effects: Performs:

size_ += min(n, str_.size() - size_);
str_.resize(size_);

void consume(size_t n);

Effects: Performs:

size_t m = min(n, size_);
str_.erase(m);
size_ -= m;

9.6.15. Dynamic buffer creation functions

template<class T, class Allocator>
  dynamic_vector_buffer<T, Allocator>
    dynamic_buffer(vector<T, Allocator>& vec) noexcept;

Requires: T is a POD type and sizeof(T) == 1.

Returns: dynamic_vector_buffer<T, Allocator>(vec).

template<class T, class Allocator>
  dynamic_vector_buffer<T, Allocator>
    dynamic_buffer(vector<T, Allocator>& vec, size_t n) noexcept;

Requires: T is a POD type and sizeof(T) == 1.

Returns: dynamic_vector_buffer<T, Allocator>(vec, n).

template<class CharT, class Traits, class Allocator>
  dynamic_string_buffer<CharT, Traits, Allocator>
    dynamic_buffer(basic_string<CharT, Traits, Allocator>& str) noexcept;

Requires: sizeof(CharT) == 1.

Returns: dynamic_string_buffer<CharT, Traits, Allocator>(str).

template<class CharT, class Traits, class Allocator>
  dynamic_string_buffer<CharT, Traits, Allocator>
    dynamic_buffer(basic_string<CharT, Traits, Allocator>& str, size_t n) noexcept;

Requires: sizeof(CharT) == 1.

Returns: dynamic_string_buffer<CharT, Traits, Allocator>(str, n).

9.6.16. Class transfer_all

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class transfer_all
      {
      public:
        size_t operator()(const error_code& ec, size_t) const;
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The class transfer_all is a function object type for use as a CompletionCondition argument to synchronous read, asynchronous read, synchronous write, or asynchronous write operations.

size_t operator()(const error_code& ec, size_t) const;

Returns: If !ec, an unspecified non-zero value. Otherwise 0.

9.6.17. Class transfer_at_least

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class transfer_at_least
      {
      public:
        explicit transfer_at_least(size_t m);
        size_t operator()(const error_code& ec, size_t s) const;
      private:
        size_t minimum_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The class transfer_at_least is a function object type for use as a CompletionCondition argument to synchronous read, asynchronous read, synchronous write, or asynchronous write operations.

explicit transfer_at_least(size_t m);

Postconditions: minimum_ == m.

size_t operator()(const error_code& ec, size_t n) const;

Returns: If !ec && n < minimum_, an unspecified non-zero value. Otherwise 0.

9.6.18. Class transfer_exactly

namespace std {
  namespace experimental {
    inline namespace network_v1 {

      class transfer_exactly
      {
      public:
        explicit transfer_exactly(size_t e);
        size_t operator()(const error_code& ec, size_t s) const;
      private:
        size_t exact_; // exposition only
      };

    } // inline namespace network_v1
  } // namespace experimental
} // namespace std

The class transfer_exactly is a function object type for use as a CompletionCondition argument to synchronous read, asynchronous read, synchronous write, or asynchronous write operations.

explicit transfer_exactly(size_t e);

Postconditions: exact_ == e.

size_t operator()(const error_code& ec, size_t n) const;

Returns: If !ec && n < exact_, the result of min(exact_ - n, N), where N is an unspecified non-zero value. Otherwise 0.

9.6.19. Synchronous read operations

template<class SyncReadStream, class MutableBufferSequence>
  size_t read(SyncReadStream& stream,
              const MutableBufferSequence& buffers);
template<class SyncReadStream, class MutableBufferSequence>
  size_t read(SyncReadStream& stream,
              const MutableBufferSequence& buffers, error_code& ec);
template<class SyncReadStream, class MutableBufferSequence,
  class CompletionCondition>
    size_t read(SyncReadStream& stream,
                const MutableBufferSequence& buffers,
                CompletionCondition completion_condition);
template<class SyncReadStream, class MutableBufferSequence,
  class CompletionCondition>
    size_t read(SyncReadStream& stream,
                const MutableBufferSequence& buffers,
                CompletionCondition completion_condition,
                error_code& ec);

Effects: Reads data from the buffer-oriented synchronous read stream object stream by performing zero or more calls to the stream's read_some member function.

The completion_condition parameter specifies a function object to be called prior to each call to the stream's read_some member function. The function object is passed the error_code value from the most recent read_some call, and the total number of bytes transferred in the synchronous read operation so far. The function object return value specifies the maximum number of bytes to be read on the subsequent read_some call. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The synchronous read operation continues until:

— the total number of bytes transferred is equal to buffer_size(buffers); or

— the completion condition returns 0.

On return, ec contains the error_code value from the most recent read_some call.

Returns: The total number of bytes transferred in the synchronous read operation.

Remarks: This function shall not participate in overload resolution unless is_mutable_buffer_sequence<MutableBufferSequence>::value is true.

template<class SyncReadStream, class DynamicBufferSequence>
  size_t read(SyncReadStream& stream, DynamicBufferSequence&& b);
template<class SyncReadStream, class DynamicBufferSequence>
  size_t read(SyncReadStream& stream, DynamicBufferSequence&& b,
              error_code& ec);
template<class SyncReadStream, class DynamicBufferSequence,
  class CompletionCondition>
    size_t read(SyncReadStream& stream, DynamicBufferSequence&& b,
                CompletionCondition completion_condition);
template<class SyncReadStream, class DynamicBufferSequence,
  class CompletionCondition>
    size_t read(SyncReadStream& stream, DynamicBufferSequence&& b,
                CompletionCondition completion_condition,
                error_code& ec);

Effects: Reads data from the synchronous read stream object stream by performing zero or more calls to the stream's read_some member function.

Data is placed into the dynamic buffer sequence object b. A mutable buffer sequence is obtained prior to each read_some call using b.prepare(N), where N is an unspecified value such that N <= max_size() - size(). [Note: Implementations are encouraged to use b.capacity() when determining N, to minimize the number of read_some calls performed on the stream. —end note] After each read_some call, the implementation performs b.commit(n), where n is the return value from read_some.

The completion_condition parameter specifies a function object to be called prior to each call to the stream's read_some member function. The function object is passed the error_code value from the most recent read_some call, and the total number of bytes transferred in the synchronous read operation so far. The function object return value specifies the maximum number of bytes to be read on the subsequent read_some call. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The synchronous read operation continues until:

b.size() == b.max_size(); or

— the completion condition returns 0.

On return, ec contains the error_code value from the most recent read_some call.

Returns: The total number of bytes transferred in the synchronous read operation.

Remarks: This function shall not participate in overload resolution unless is_dynamic_buffer_sequence<DynamicBufferSequence>::value is true.

9.6.20. Asynchronous read operations

template<class AsyncReadStream, class MutableBufferSequence,
  class CompletionToken>
    auto async_read(AsyncReadStream& stream,
                    const MutableBufferSequence& buffers,
                    CompletionToken&& token);
template<class AsyncReadStream, class MutableBufferSequence,
  class CompletionCondition, class CompletionToken>
    auto async_read(AsyncReadStream& stream,
                    const MutableBufferSequence& buffers,
                    CompletionCondition completion_condition,
                    CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to read data from the buffer-oriented asynchronous read stream object stream by performing zero or more asynchronous operations on the stream using the stream's async_read_some member function (henceforth referred to as asynchronous read_some operations).

The completion_condition parameter specifies a function object to be called prior to each asynchronous read_some operation. The function object is passed the error_code value from the most recent asynchronous read_some operation, and the total number of bytes transferred in the asynchronous read operation so far. The function object return value specifies the maximum number of bytes to be read on the subsequent asynchronous read_some operation. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The asynchronous read operation continues until:

— the total number of bytes transferred is equal to buffer_size(buffers); or

— the completion condition returns 0.

The program must ensure the AsyncReadStream object stream is valid until the handler for the asynchronous operation is invoked.

On completion of the asynchronous operation, ec is the error_code value from the most recent asynchronous read_some operation, and n is the total number of bytes transferred.

Remarks: This function shall not participate in overload resolution unless is_mutable_buffer_sequence<MutableBufferSequence>::value is true.

template<class AsyncReadStream, class DynamicBufferSequence,
  class CompletionToken>
    auto async_read(AsyncReadStream& stream,
                    DynamicBufferSequence&& b,
                    CompletionToken&& token);
template<class AsyncReadStream, class DynamicBufferSequence,
  class CompletionCondition, class CompletionToken>
    auto async_read(AsyncReadStream& stream,
                    DynamicBufferSequence&& b,
                    CompletionCondition completion_condition,
                    CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to read data from the buffer-oriented asynchronous read stream object stream by performing one or more asynchronous read_some operations on the stream.

Data is placed into the dynamic buffer sequence object b. A mutable buffer sequence is obtained prior to each async_read_some call using b.prepare(N), where N is an unspecified value such that N <= max_size() - size(). [Note: Implementations are encouraged to use b.capacity() when determining N, to minimize the number of asynchronous read_some operations performed on the stream. —end note] After the completion of each asynchronous read_some operation, the implementation performs b.commit(n), where n is the value passed to the asynchronous read_some operation's completion handler.

The completion_condition parameter specifies a function object to be called prior to each asynchronous read_some operation. The function object is passed the error_code value from the most recent asynchronous read_some operation, and the total number of bytes transferred in the asynchronous read operation so far. The function object return value specifies the maximum number of bytes to be read on the subsequent asynchronous read_some operation. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The asynchronous read operation continues until:

b.size() == b.max_size(); or

— the completion condition returns 0.

The program must ensure both the AsyncReadStream object stream and the memory associated with the dynamic buffer sequence b are valid until the handler for the asynchronous operation is invoked.

On completion of the asynchronous operation, ec is the error_code value from the most recent asynchronous read_some operation, and n is the total number of bytes transferred.

Remarks: This function shall not participate in overload resolution unless is_dynamic_buffer_sequence<DynamicBufferSequence>::value is true.

9.6.21. Synchronous write operations

template<class SyncWriteStream, class ConstBufferSequence>
  size_t write(SyncWriteStream& stream,
               const ConstBufferSequence& buffers);
template<class SyncWriteStream, class ConstBufferSequence>
  size_t write(SyncWriteStream& stream,
               const ConstBufferSequence& buffers, error_code& ec);
template<class SyncWriteStream, class ConstBufferSequence,
  class CompletionCondition>
    size_t write(SyncWriteStream& stream,
                 const ConstBufferSequence& buffers,
                 CompletionCondition completion_condition);
template<class SyncWriteStream, class ConstBufferSequence,
  class CompletionCondition>
    size_t write(SyncWriteStream& stream,
                 const ConstBufferSequence& buffers,
                 CompletionCondition completion_condition,
                 error_code& ec);

Effects: Writes data to the buffer-oriented synchronous write stream object stream by performing zero or more calls to the stream's write_some member function.

The completion_condition parameter specifies a function object to be called prior to each call to the stream's write_some member function. The function object is passed the error_code value from the most recent write_some call, and the total number of bytes transferred in the synchronous write operation so far. The function object return value specifies the maximum number of bytes to be write on the subsequent write_some call. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The synchronous write operation continues until:

— the total number of bytes transferred is equal to buffer_size(buffers); or

— the completion condition returns 0.

On return, ec contains the error_code value from the most recent write_some call.

Returns: The total number of bytes transferred in the synchronous write operation.

Remarks: This function shall not participate in overload resolution unless is_const_buffer_sequence<ConstBufferSequence>::value is true.

template<class SyncWriteStream, class DynamicBufferSequence>
  size_t write(SyncWriteStream& stream, DynamicBufferSequence&& b);
template<class SyncWriteStream, class DynamicBufferSequence>
  size_t write(SyncWriteStream& stream, DynamicBufferSequence&& b,
               error_code& ec);
template<class SyncWriteStream, class DynamicBufferSequence,
  class CompletionCondition>
    size_t write(SyncWriteStream& stream,
                 DynamicBufferSequence&& b,
                 CompletionCondition completion_condition);
template<class SyncWriteStream, class DynamicBufferSequence,
  class CompletionCondition>
    size_t write(SyncWriteStream& stream,
                 DynamicBufferSequence&& b,
                 CompletionCondition completion_condition,
                 error_code& ec);

Effects: Writes data to the synchronous write stream object stream by performing zero or more calls to the stream's write_some member function.

Data is written from the dynamic buffer sequence object b. A constant buffer sequence is obtained using b.data(). After the data has been written to the stream, the implementation performs b.consume(n), where n is the number of bytes successfully written.

The completion_condition parameter specifies a function object to be called after each call to the stream's write_some member function. The function object is passed the error_code value from the most recent write_some call, and the total number of bytes transferred in the synchronous write operation so far. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The synchronous write operation continues until:

b.size() == 0; or

— the completion condition returns 0.

On return, ec contains the error_code value from the most recent write_some call.

Returns: The total number of bytes transferred in the synchronous write operation.

Remarks: This function shall not participate in overload resolution unless is_dynamic_buffer_sequence<DynamicBufferSequence>::value is true.

9.6.22. Asynchronous write operations

template<class AsyncWriteStream, class ConstBufferSequence,
  class CompletionToken>
    auto async_write(AsyncWriteStream& stream,
                     const ConstBufferSequence& buffers,
                     CompletionToken&& token);
template<class AsyncWriteStream, class ConstBufferSequence,
  class CompletionCondition, class CompletionToken>
    auto async_write(AsyncWriteStream& stream,
                     const ConstBufferSequence& buffers,
                     CompletionCondition completion_condition,
                     CompletionToken&& token);

Completion signature: void(error_code ec, size_t n).

Effects: Initiates an asynchronous operation to write data to the buffer-oriented asynchronous write stream object stream by performing zero or more asynchronous operations on the stream using the stream's async_write_some member function (henceforth referred to as asynchronous write_some operations).

The completion_condition parameter specifies a function object to be called prior to each asynchronous write_some operation. The function object is passed the error_code value from the most recent asynchronous write_some operation, and the total number of bytes transferred in the asynchronous write operation so far. The function object return value specifies the maximum number of bytes to be write on the subsequent asynchronous write_some operation. Overloads where a completion condition is not specified behave as if called with an object of class transfer_all.

The asynchronous write operation continues until:

— the total number of bytes transferred is equal to buffer_size(buffers); or

— the completion condition returns 0.

The program must ensure the AsyncWriteStream object stream is valid until the handler for the asynchronous operation is invoked.

On completion of the asynchronous operation, ec is the error_code value from the most recent asynchronous write_some operation, and n is the total number of bytes transferred.

Remarks: This function shall not participate in overload resolution unless is_const_buffer_sequence<ConstBufferSequence>::value is true.