Document number: P0958R3 Date: 2021-02-06 Project: Programming Language C++ Audience: SG4 - Networking Reply-to: Christopher Kohlhoff <chris@kohlhoff.com>
The purpose of this paper is to illustrate the changes to the Networking TS to conform to the proposed Executors TS in P0443R13.
All changes are relative to N4711.
This paper proposes the following changes to the Networking TS:
executor_work_guard
and make_work_guard
, as these have been superseded by the executors proposal's execution::outstanding_work
property.is_executor
type trait.system_executor
and system_context
to conform to the new executors model.executor
and uses of it as a default executor. As a consequence of this change:
basic_
prefixes have been removed from the timer, socket, and resolver class templates, as users are now likely to utilise these directly.X::socket
) have been replaced with template type aliases taking an executor (such as X::socket_for
).
dispatch
, post
, and defer
in terms of the new executors model.strand
adapter to conform to the new executors model.use_future
completion token to conform to the new executors model.io_context
to conform to the new executors model.An implementation of the changes below, including a complete implementation of the executors-related specifications P0443R13, P1348R0, and P1393R0, can be found the Asio library at https://github.com/chriskohlhoff/asio and in Boost 1.74.
This implementation has been used to recompile libraries that depend on Asio, and has been tested in a number of applications. Some library modifications were required, but the majority of the applications needed minor or no modifications.
Add a reference to the executors proposal in -5- Namespaces and headers [namespaces]:
-2- Unless otherwise specified, references to other entities described in this Technical Specification are assumed to be qualified with std::experimental::net::v1::
, references to entities described in the C++ standard are assumed to be qualified with std::
, and references to entities described in C++ Extensions for Library Fundamentals are assumed to be qualified with std::experimental::fundamentals_v2::
, and references to entities described in P1393R0 A General Property Customization Mechanism and in P0443R13 A Unified Executors Proposal for C++ are assumed to be qualified with std::
.
executor_work_guard
and make_work_guard
Remove executor_work_guard
from -12.1- Header <experimental/netfwd> synopsis [fwd.decl.synop]:
template<class Executor> class executor_work_guard;
Remove executor_work_guard
and make_work_guard
from -13.1- Header <experimental/executor> synopsis [async.synop]:
template<class Executor> class executor_work_guard; // 13.17, make_work_guard: template<class Executor> executor_work_guard<Executor> make_work_guard(const Executor& ex); template<class ExecutionContext> executor_work_guard<typename ExecutionContext::executor_type> make_work_guard(ExecutionContext& ctx); template<class T> executor_work_guard<associated_executor_t<T>> make_work_guard(const T& t); template<class T, class U> auto make_work_guard(const T& t, U& u) -> decltype(make_work_guard(get_associated_executor(t, forward<U>(u))));
Remove sections -13.16- Class template executor_work_guard [async.exec.work.guard] and -13.17- Function make_work_guard [async.make.work.guard] in their entirety.
is_executor
type traitModify Table 3 - Template parameters and type requirements [summary] as follows:
Executor |
execution::executor concept (P0443R13) |
Remove is_executor
and is_executor_v
from -13.1- Header <experimental/executor> synopsis [async.synop]:
template<class T> struct is_executor; template<class T> constexpr bool is_executor_v = is_executor<T>::value;
Remove section -13.2.2- Executor requirements [async.reqmts.executor] in its entirety.
Modify Table 5 - ExecutionContext requirements [async.reqmts.executioncontext] as follows:
expression | return type | assertion/note pre/post-condition |
---|---|---|
X::executor_type |
Executor (13.2.2) requirementsA type that models execution::executor (P0443R13). |
Modify section -13.2.7.8- I/O executor [async.reqmts.async.io.exec] as follows.
-1- An asynchronous operation has an associated executor satisfying the whose type models Executor
(13.2.2) requirementsexecution::executor
(P0443R13). If not otherwise specified by the asynchronous operation, this associated executor is an object of type system_executor
.
[...]
-3- Let Executor1
be the type of the associated executor. Let ex1
be a value of type Executor1
, representing the associated executor object obtained as described above. can_query_v<Executor1, execution::context_t>
shall be true
, and std::query(ex1, execution::context_t)
shall yield a value of type execution_context&
or of type E&
, where E
satisifies the ExecutionContext
(13.2.3) requirements.
Modify section -13.2.7.9- Completion handler executor [async.reqmts.async.handler.exec] as follows.
-1- A completion handler object of type CompletionHandler
has an associated executor satisfying the Executor requirements (13.2.2)whose type models execution::executor
(P0443R13). The type of this associated executor is associated_executor_t<CompletionHandler, Executor1>
. Let Executor2
be the type associated_executor_t<CompletionHandler, Executor1>
. Let ex2
be a value of type Executor2
obtained by performing get_associated_executor(completion_handler, ex1)
. can_query_v<Executor2, execution::context_t>
shall be true
, and std::query(ex2, execution::context_t)
shall yield a value of type execution_context&
or of type E&
, where E
satisifies the ExecutionContext
(13.2.3) requirements.
Modify section -13.2.7.14- Composed asynchronous operations [async.reqmts.async.composed] as follows.
An intermediate operation's completion handler shall have an associated executor that is either:
Executor2
and object ex2
obtained from the completion handler type CompletionHandler
and object completion_handler
; orexecution::executor
(P0443R13), that delegates executor operations to the type Executor2
and object ex2
.Remove section -13.9- Class template is_executor [async.is.exec] in its entirety.
Modify section -13.10- Executor argument tag [async.executor.arg] as follows.
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 execution::executor
(P0443R13).
Modify section -13.12- Class template associated_executor [async.assoc.exec] as follows.
-1- Class template associated_executor
is an associator (13.2.6) for the executors, with default candidate type Executor
(13.2.2) type requirementssystem_executor
and default candidate object system_executor()
.
Modify Table 9 - associated_executor specialization requirements as follows:
Expression | Return type | Note |
---|---|---|
typename X::type |
Executor requirements (13.2.2)A type that models execution::executor (P0443R13). |
Modify section -13.13- Function get_associated_executor [async.assoc.exec.get] as follows.
-3- Remarks: This function shall not participate in overload resolution unless
is_executor_v<Executor>
is true
is_convertible<Executor&, execution_context&>::value
is false
.
Modify section -13.14- Class template executor_binder [async.exec.binder] as follows.
-1- The class template executor_binder
binds executors to objects. A specialization executor_binder<T, Executor>
binds an executor of type Executor
satisfying the Executor requirements (13.2.2)that models execution::executor
(P0443R13) to an object or function of type T
.
Modify section -13.15- Function bind_executor [async.bind.executor] as follows.
-2- Remarks: This function shall not participate in overload resolution unless
is_executor_v<Executor>
is true
is_convertible<Executor&, execution_context&>::value
is false
.
Modify section -13.22- Function dispatch [async.dispatch] as follows.
-8- Remarks: This function shall not participate in overload resolution unless
is_executor_v<Executor>
is true
is_convertible<Executor&, execution_context&>::value
is false
.
Modify section -13.23- Function post [async.post] as follows.
-8- Remarks: This function shall not participate in overload resolution unless
is_executor_v<Executor>
is true
is_convertible<Executor&, execution_context&>::value
is false
.
Modify section -13.24- Function defer [async.defer] as follows.
-8- Remarks: This function shall not participate in overload resolution unless
is_executor_v<Executor>
is true
is_convertible<Executor&, execution_context&>::value
is false
.
Modify section -13.25- Class template strand [async.strand] as follows.
-1- The class template strand
is a wrapper around an object of type Executor
satisfying the that models Executor
requirements (13.2.2)execution::executor
(P0443R13).
[...]
-2- strand<Executor>
satisfies the models Executor
(13.2.2) requirementsexecution::executor
(P0443R13).
Modify Table 17 - AsyncReadStream requirements [buffer.stream.reqmts.asyncreadstream] as follows:
operation | type | semantics, pre/post-conditions |
---|---|---|
a.get_executor() |
A type Executor requirements (13.2.2)execution::executor (P0443R13). |
Returns the associated I/O executor. |
Modify Table 19 - AsyncWriteStream requirements [buffer.stream.reqmts.asyncwritestream] as follows:
operation | type | semantics, pre/post-conditions |
---|---|---|
a.get_executor() |
A type Executor requirements (13.2.2)execution::executor (P0443R13). |
Returns the associated I/O executor. |
Modify section -13.2.7.10- Outstanding work [async.reqmts.async.work] as follows.
-1- Until the asynchronous operation has completed, the asynchronous operation shall maintain:
work1
of type executor_work_guard<Executor1>
, initialized as work1(ex1)
, and where work1.owns_work() == true
; andwork2
of type executor_work_guard<Executor2>
, initialized as work2(ex2)
, and where work2.owns_work() == true
.work1
, initialized as std::prefer(ex1, execution::outstanding_work.tracked)
; andwork2
, initialized as std::prefer(ex2, execution::outstanding_work.tracked)
.Modify section -13.2.7.12- Execution of completion handler on completion of asynchronous operation [async.reqmts.async.completion] as follows:
-3- If an asynchronous operation completes immediately (that is, within the thread of execution calling the initiating function, and before the initiating function returns), the completion handler shall be submitted for execution as if by performing:ex2.post(std::move(f), alloc2)
. Otherwise, the completion handler shall be submitted for execution as if by performing ex2.dispatch(std::move(f), alloc2)
.
execution::execute( std::prefer( std::require(ex2, execution::blocking.never), execution::allocator(alloc2)), std::move(f));
Otherwise, the completion handler shall be submitted for execution as if by performing:
execution::execute( std::prefer(work2, execution::blocking.possibly, execution::allocator(alloc2)), std::move(f));
system_executor
and system_context
to conform to the new executors modelRemove system_executor
from, and add system_context
to, -12.1- Header <experimental/netfwd> synopsis [fwd.decl.synop]:
class system_executor;class system_context;
Update system_executor
to be a type alias in -13.1- Header <experimental/executor> synopsis [async.synop]:
class system_executor;class system_context; using system_executor = system_context::executor_type;bool operator==(const system_executor&, const system_executor&); bool operator!=(const system_executor&, const system_executor&);
Remove section -13.18- Class system_executor [async.system.exec] in its entirety.
Modify section -13.19- Class system_context [async.system.context] as follows:
-1- Class system_context
implements the execution context associated with an execution context that represents the ability to run a submitted function object on any thread.
system_executor
objects
namespace std { namespace experimental { namespace net { inline namespace v1 { class system_context : public execution_context { public: // types: using executor_type =system_executorsee below;
[...]
-2- The class system_context
satisfies the ExecutionContext
(13.2.3) type requirements.
-?- executor_type
is an executor type conforming to the specification for system_context
executor types described below. Executor objects of type executor_type
have the following properties established:
execution::blocking.possibly
execution::relationship.fork
execution::mapping.thread
execution::allocator(std::allocator<void>())
-?- system_context
executors having a different set of established properties may be represented by distinct, unspecified types. Function objects submitted via a system_context
executor object are permitted to execute on any thread. To satisfy the requirements for the execution::blocking.never
property, a system_context
executor may create thread
objects to run the submitted function objects. These thread
objects are collectively referred to as system threads.
[...]
executor_type get_executor() noexcept;
-5- Returns: system_executor()
executor_type()
.
After section -13.19- Class system_context [async.system.context] insert a new section as follows:
system_context
executor types-1- Class system-context-executor is for exposition only. It is used to specify a bounded set of types that model execution::executor
(P0443R13). All executor types accessible through system_context::executor_type
, system_context::get_executor()
, and subsequent calls to the member function require
, are members of this set and conform to the specification of system-context-executor. [Note: An implementation may provide distinct types for executors that have different properties established. --end note]
namespace std { namespace experimental { namespace net { inline namespace v1 { class system-context-executor { public: // construct / copy / destroy: system-context-executor() {} // executor operations: see below require(execution::blocking_t::possibly_t) const; see below require(execution::blocking_t::never_t) const; see below require(execution::blocking_t::always_t) const; see below require(execution::relationship_t::fork_t) const; see below require(execution::relationship_t::continuation_t) const; see below require(execution::allocator_t<void>) const; template<class ProtoAllocator> see below require(const execution::allocator_t<ProtoAllocator>& a) const; static constexpr execution::mapping_t query(execution::mapping_t) noexcept; system_context& query(execution::context_t) const noexcept; execution::blocking_t query(execution::blocking_t) const noexcept; execution::relationship_t query(execution::relationship_t) const noexcept; see below query(execution::allocator_t<void>) const noexcept; template<class ProtoAllocator> see below query(const execution::allocator_t<ProtoAllocator>&) const noexcept; template<class Function> void execute(Function&& f) const; }; bool operator==(const system-context-executor& a, const system-context-executor& b) noexcept; bool operator!=(const system-context-executor& a, const system-context-executor& b) noexcept; } // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
system_context
executor operationssee below require(execution::blocking_t::possibly_t) const; see below require(execution::blocking_t::never_t) const; see below require(execution::blocking_t::always_t) const; see below require(execution::relationship_t::fork_t) const; see below require(execution::relationship_t::continuation_t) const;
-1- Returns: An object of a system-context-executor
class, with the requested property established. When the requested property is part of a group that is defined as a mutually exclusive set, any other properties in the group are removed from the returned executor object. All other properties of the returned executor object are identical to those of *this
.
see below require(execution::allocator_t<void>) const;
-2- Returns: require(execution::allocator(std::allocator<void>()))
.
template<class ProtoAllocator> see below require(const execution::allocator_t<ProtoAllocator>& a) const;
-3- Returns: An object of a system-context-executor
class, with the execution::allocator_t<ProtoAllocator>
property established such that allocation and deallocation associated with function submission will be performed using a copy of a.value()
. All other properties of the returned executor object are identical to those of *this
.
static constexpr execution::mapping_t query(execution::mapping_t) noexcept;
-4- Returns: true
.
system_context& query(execution::context_t) const;
-5- Returns: A reference to the system_context
object.
execution::blocking_t query(execution::blocking_t) const noexcept; execution::relationship_t query(execution::relationship_t) const noexcept;
-6- Returns: The established value of the property for the executor object *this
.
see below query(execution::allocator_t<void>) const noexcept; template<class ProtoAllocator> see below query(const execution::allocator_t<ProtoAllocator>&) const noexcept;
-7- Returns: The allocator object associated with the executor, with type and value as previously established by the execution::allocator_t<ProtoAllocator>
property.
template<class Function> void execute(Function&& f) const
-8- Effects: Submits the function f
for execution according to the execution::executor
concept and the properties established for *this
. If f
exits via an exception, calls std::terminate()
.
system_context
executor comparisonsbool operator==(const system-context-executor& a, const system-context-executor& b) noexcept;
-1- Returns: true
if a
and b
have identical properties, otherwise false
.
bool operator!=(const system-context-executor& a, const system-context-executor& b) noexcept;
-2- Returns: !(a == b)
.
executor
and uses of it as a default executorRemove executor
from -12.1- Header <experimental/netfwd> synopsis [fwd.decl.synop]:
class executor;
Assuming the changes in P1322 have been applied,
executor
as the default for Executor
template parameters,io_context::executor_type
as the default for the iostream class templates' Executor
tempalte parameters,basic_
prefixes, andsystem_timer
, steady_timer
, and high_resolution_timer
type aliasesin -12.1- Header <experimental/netfwd> synopsis [fwd.decl.synop]:
template<class Clock> struct wait_traits; template<class Clock, class Executor, class WaitTraits = wait_traits<Clock>, class Executor = executor> classbasic_waitable_timer;using system_timer = basic_waitable_timer<chrono::system_clock>; using steady_timer = basic_waitable_timer<chrono::steady_clock>; using high_resolution_timer = basic_waitable_timer<chrono::high_resolution_clock>;template<class Protocol, class Executor= executor> classbasic_socket; template<class Protocol, class Executor= executor> classbasic_datagram_socket; template<class Protocol, class Executor= executor> classbasic_stream_socket; template<class Protocol, class Executor= executor> classbasic_socket_acceptor; template<class Protocol, class Clock = chrono::steady_clock, class WaitTraits = wait_traits<Clock>, class Executor =executorio_context::executor_type> classbasic_socket_streambuf; template<class Protocol, class Clock = chrono::steady_clock, class WaitTraits = wait_traits<Clock>, class Executor =executorio_context::executor_type> classbasic_socket_iostream; namespace ip {
[...]
template<class InternetProtocol, class Executor= executor> classbasic_resolver;
Remove classes bad_executor
and executor
from -13.1- Header <experimental/executor> synopsis [async.synop]:
class bad_executor; class executor; 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;
[...]
} // inline namespace v1 } // namespace net } // namespace experimentaltemplate<class Allocator> struct uses_allocator<experimental::net::v1::executor, Allocator> : true_type {};} // namespace std
Remove sections -13.20- Class bad_executor [async.bad.exec] and -13.21- Class executor [async.executor] in their entirety.
Use the waitable_timer
class template directly, instead of the steady_timer
alias, in -15- Timers [timer]:
-1- This clause defines components for performing timer operations.
-2- [ Example: Performing a synchronous wait operation on a timer:
io_context c;-- end example ]steady_timerwaitable_timer<chrono::steady_clock> t(c); t.expires_after(seconds(5)); t.wait();
-3- [ Example: Performing an asynchronous wait operation on a timer:
void handler(error_code ec) { ... } ... io_context c;-- end example ]steady_timerwaitable_timer<chrono::steady_clock> t(c); t.expires_after(seconds(5)); t.async_wait(handler); c.run();
Assuming the changes in P1322 have been applied,
executor
as the default for the Executor
template parameter,basic_
prefix, andsystem_timer
, steady_timer
, and high_resolution_timer
type aliasesfrom -15.1- Header <experimental/timer>
synopsis [timer.synop]
#include <chrono> namespace std { namespace experimental { namespace net { inline namespace v1 { template<class Clock> struct wait_traits; template<class Clock, class Executor, class WaitTraits = wait_traits<Clock>, class Executor = executor> classbasic_waitable_timer;using system_timer = basic_waitable_timer<chrono::system_clock>;using steady_timer = basic_waitable_timer<chrono::steady_clock>;using high_resolution_timer = basic_waitable_timer<chrono::high_resolution_clock>;} // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
Remove the basic_
prefix from basic_waitable_timer
in -15.2.1- Wait traits requirements [timer.reqmts.waittraits] as follows:
-1- The
template uses wait traits to allow programs to customize waitable_timerbasic_
wait
and async_wait
behavior. [ Note: Possible uses of wait traits include:
Assuming the changes in P1322 have been applied,
executor
as the default for the Executor
template parameter,basic_
prefixfrom -15.4- Class template basic_­waitable_timer
[timer.waitable]
15.4 Class template
[timer.waitable]waitable_timerbasic_
namespace std { namespace experimental { namespace net { inline namespace v1 { template<class Clock, class Executor, class WaitTraits = wait_traits<Clock>, class Executor = executor> classbasic_waitable_timer { public: // types: using executor_type = Executor; using clock_type = Clock; using duration = typename clock_type::duration; using time_point = typename clock_type::time_point; using traits_type = WaitTraits; template<class OtherExecutor> using rebind_executor =basic_waitable_timer<Clock, WaitTraits, OtherExecutor>; // [timer.waitable.cons], construct / copy / destroy: explicitbasic_waitable_timer(); template<class ExecutionContext> explicitbasic_waitable_timer(ExecutionContext& ctx);basic_waitable_timer(const executor_type& ex, const time_point& t); template<class ExecutionContext>basic_waitable_timer(ExecutionContext& ctx, const time_point& t);basic_waitable_timer(const executor_type& ex, const duration& d); template<class ExecutionContext>basic_waitable_timer(ExecutionContext& ctx, const duration& d);basic_waitable_timer(constbasic_waitable_timer&) = delete;basic_waitable_timer(basic_waitable_timer&& rhs); ~basic_waitable_timer();basic_waitable_timer& operator=(constbasic_waitable_timer&) = delete;basic_waitable_timer& operator=(basic_waitable_timer&& rhs); // [timer.waitable.ops],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> DEDUCED async_wait(CompletionToken&& token); }; } // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
-1- Instances of class template
meet the requirements of waitable_timerbasic_
Destructible
(C++2014[destructible]), MoveConstructible
(C++2014[moveconstructible]), and MoveAssignable
(C++2014[moveassignable]).
basic_
waitable_timer
constructors [timer.waitable.cons]explicitwaitable_timer(const executor_type& ex);basic_
-1- Effects:Equivalent to
.waitable_timer(ex, time_point())basic_
template<class ExecutionContext> explicitwaitable_timer(ExecutionContext& ctx);basic_
Effects:Equivalent to waitable_timer(ctx.get_executor()).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
waitable_timer(const executor_type& ex, const time_point& t);basic_
-2- Postconditions:
get_executor() == ex
.expiry() == t
.template<class ExecutionContext>waitable_timer(ExecutionContext& ctx, const time_point& t);basic_
Effects:Equivalent to waitable_timer(ctx.get_executor(), t).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
waitable_timer(const executor_type& ex, const duration& d);basic_
-3- Effects:Sets the expiry time as if by calling expires_after(d)
.
-4- Postconditions:get_executor() == ex
.
template<class ExecutionContext>waitable_timer(ExecutionContext& ctx, const duration& d);basic_
Effects:Equivalent to waitable_timer(ctx.get_executor(), d).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
waitable_timer(basic_
waitable_timer&& rhs);basic_
-5- Effects:Move constructs an object of class
that refers to the state originally represented by waitable_timer<Clock, WaitTraits>basic_
rhs
.
-6- Postconditions:
get_executor() == rhs.get_executor()
.expiry()
returns the same value as rhs.expiry()
prior to the constructor invocation.rhs.expiry() == time_point()
.basic_
waitable_timer
destructor [timer.waitable.dtor]~waitable_timer();basic_
-1- Effects:Destroys the timer, canceling any asynchronous wait operations associated with the timer as if by calling cancel()
.
basic_
waitable_timer
assignment [timer.waitable.assign]waitable_timer& operator=(basic_
waitable_timer&& rhs);basic_
-1- Effects:Cancels any outstanding asynchronous operations associated with *this
as if by calling cancel()
, then moves into *this
the state originally represented by rhs
.
-2- Postconditions:
get_executor() == rhs.get_executor()
.expiry()
returns the same value as rhs.expiry()
prior to the assignment.rhs.expiry() == time_point()
.-3- Returns:*this
.
basic_
waitable_timer
operations [timer.waitable.ops][...]
template<class CompletionToken> DEDUCED async_wait(CompletionToken&& token);
-15- Completion signature:void(error_code ec)
.
-16- Effects:Initiates an asynchronous wait operation to repeatedly wait for the relative time produced by WaitTraits::to_wait_duration(e)
, where e
is a value of type time_point
such that e <= expiry()
. The completion handler is submitted for execution only when the condition ec || expiry() <= clock_type::now()
yields true
.
-17- [ Note: To implement async_wait
, an io_context
object ctx
could maintain a priority queue for each specialization of
for which a timer object was initialized with waitable_timer<Clock, WaitTraits>basic_
ctx
. Only the time point e
of the earliest outstanding expiry need be passed to WaitTraits::to_wait_duration(e)
. -- end note ]
Assuming the changes in P1322 have been applied,
executor
as the default for Executor
template parameters,io_context::executor_type
as the default for the iostream class templates' Executor
template parameters,basic_
prefixesin -18.1- Header <experimental/socket>
synopsis [socket.synop]:
namespace std { namespace experimental { namespace net { inline namespace v1 { enum class socket_errc { already_open = an implementation-defined non-zero value, not_found = an implementation-defined non-zero value }; const error_category& socket_category() noexcept; error_code make_error_code(socket_errc e) noexcept; error_condition make_error_condition(socket_errc e) noexcept; // Sockets: class socket_base; template<class Protocol, class Executor= executor> classbasic_socket; template<class Protocol, class Executor= executor> classbasic_datagram_socket; template<class Protocol, class Executor= executor> classbasic_stream_socket; template<class Protocol, class Executor= executor> classbasic_socket_acceptor; // [socket.iostreams], Socket streams: template<class Protocol, class Clock = chrono::steady_clock, class WaitTraits = wait_traits<Clock>, class Executor =executorio_context::executor_type> classbasic_socket_streambuf; template<class Protocol, class Clock = chrono::steady_clock, class WaitTraits = wait_traits<Clock>, class Executor =executorio_context::executor_type> classbasic_socket_iostream; // [socket.algo.connect], synchronous connect operations: template<class Protocol, class Executor, class EndpointSequence> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints); template<class Protocol, class Executor, class EndpointSequence> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, error_code& ec); template<class Protocol, class Executor, class EndpointSequence, class ConnectCondition> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition c); template<class Protocol, class Executor, class EndpointSequence, class ConnectCondition> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition c, error_code& ec); template<class Protocol, class Executor, class InputIterator> InputIterator connect(basic_socket<Protocol, Executor>& s, InputIterator first, InputIterator last); template<class Protocol, class Executor, class InputIterator> InputIterator connect(basic_socket<Protocol, Executor>& s, InputIterator first, InputIterator last, error_code& ec); template<class Protocol, class Executor, class InputIterator, class ConnectCondition> InputIterator connect(basic_socket<Protocol, Executor>& s, InputIterator first, InputIterator last, ConnectCondition c); template<class Protocol, class Executor, class InputIterator, class ConnectCondition> InputIterator connect(basic_socket<Protocol, Executor>& s, InputIterator first, InputIterator last, ConnectCondition c, error_code& ec); // [socket.algo.async.connect], asynchronous connect operations: template<class Protocol, class Executor, class EndpointSequence, class CompletionToken> DEDUCED async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, CompletionToken&& token); template<class Protocol, class Executor, class EndpointSequence, class ConnectCondition, class CompletionToken> DEDUCED async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition c, CompletionToken&& token); template<class Protocol, class Executor, class InputIterator, class CompletionToken> DEDUCED async_connect(basic_socket<Protocol, Executor>& s, InputIterator first, InputIterator last, CompletionToken&& token); template<class Protocol, class Executor, class InputIterator, class ConnectCondition, class CompletionToken> DEDUCED async_connect(basic_socket<Protocol, Executor>& s, InputIterator first, InputIterator last, ConnectCondition c, CompletionToken&& token); } // inline namespace v1 } // namespace net } // namespace experimental template<> struct is_error_code_enum<experimental::net::v1::socket_errc> : public true_type {}; } // namespace std
[...]
Update Figure 1 "Socket and socket stream types [non-normative]" in
-18.1- Header <experimental/socket>
synopsis [socket.synop]
to the following:
Assuming the changes in P1322 have been applied,
socket
type alias from the AcceptableProtocol
requirements,execution::executor
concept, andbasic_
prefixesfrom -18.2.7- Acceptable protocol requirements [socket.reqmts.acceptableprotocol] :
-1- A type X
meets the AcceptableProtocol
requirements if it satisfies the requirements of Protocol
([socket.reqmts.protocol]) as well as the additional requirements listed below.
E
is a type that execution::executor
(P0443R13).expression | return type | assertion/note pre/post-conditions |
X::socket | Destructible (C++2014[destructible]) and MoveConstructible (C++2014[moveconstructible]), and that is publicly and unambiguously derived from basic_socket<X> | |
X::socket_for<E> | A type that satisfies the requirements of Destructible (C++2014[destructible]) and MoveConstructible (C++2014[moveconstructible]), and that is publicly and unambiguously derived from . |
[...]
Assuming the changes in P1322 have been applied,
remove the basic_
prefixes
from -18.4- Class socket_base
[socket.base]:
[...]
-1- socket_base
defines several member types:
broadcast
, debug
, do_not_route
, keep_alive
, linger
, out_of_band_inline
, receive_buffer_size
, receive_low_watermark
, reuse_address
, send_buffer_size
, and send_low_watermark
;shutdown_type
, for use with the basic_
socket<Protocol, Executor>
class's shutdown
member function.wait_type
, for use with the basic_
socket<Protocol, Executor>
and basic_
socket_acceptor<Protocol, Executor>
classes' wait
and async_wait
member functions,message_flags
, for use with the basic_
stream_socket<Protocol, Executor>
class's send
, async_send
, receive
, and async_receive
member functions, and the basic_
datagram_socket<Protocol>
class's send
, async_send
, send_to
, async_send_to
, receive
, async_receive
, receive_from
, and async_receive_from
member functions.max_listen_connections
, for use with the basic_
socket_acceptor<Protocol, Executor>
class's listen
member function.[...]
Assuming the changes in P1322 have been applied,
remove the basic_
prefixes
from -18.6- Class basic_socket
[socket.basic]:
basic_socket
[socket.basic]-1- Class template
is used as the base class for the basic_socket<Protocol, Executor>
and basic_datagram_socket<Protocol, Executor>
class templates. It provides functionality that is common to both types of socket.basic_stream_socket<Protocol, Executor>
namespace std { namespace experimental { namespace net { inline namespace v1 { template<class Protocol, class Executor> classbasic_socket : public socket_base { public: // types: using executor_type = Executor; using native_handle_type = implementation-defined; // see [socket.reqmts.native] using protocol_type = Protocol; using endpoint_type = typename protocol_type::endpoint; template<class OtherExecutor> using rebind_executor =basic_socket<Protocol, OtherExecutor>; // [socket.basic.ops],basic_socket operations:
[...]
protected: // [socket.basic.cons], construct / copy / destroy: explicitbasic_socket(const executor_type& ex); template<class ExecutionContext> explicitbasic_socket(ExecutionContext& ctx);basic_socket(const executor_type& ex, const protocol_type& protocol); template<class ExecutionContext>basic_socket(ExecutionContext& ctx, const protocol_type& protocol);basic_socket(const executor_type& ex, const endpoint_type& endpoint); template<class ExecutionContext>basic_socket(ExecutionContext& ctx, const endpoint_type& endpoint);basic_socket(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_socket); // see [socket.reqmts.native] template<class ExecutionContext>basic_socket(ExecutionContext& ctx, const protocol_type& protocol, const native_handle_type& native_socket); // see [socket.reqmts.native]basic_socket(constbasic_socket&) = delete;basic_socket(basic_socket&& rhs); template<class OtherProtocol, class OtherExecutor>basic_socket(basic_socket<OtherProtocol, OtherExecutor>&& rhs); ~basic_socket();basic_socket& operator=(constbasic_socket&) = delete;basic_socket& operator=(basic_socket&& rhs); template<class OtherProtocol, class OtherExecutor>basic_socket& operator=(basic_socket<OtherProtocol, OtherExecutor>&& rhs); private: protocol_type protocol_; // exposition only }; } // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
-2- Instances of class template
meet the requirements of socketbasic_
Destructible
(C++2014[destructible]), MoveConstructible
(C++2014[moveconstructible]), and MoveAssignable
(C++2014[moveassignable]).
-3- When an operation has its effects specified as if by passing the result of native_handle()
to a POSIX function, then the operation fails with error condition errc::bad_file_descriptor
if is_open() == false
at the point in the effects when the POSIX function is called.
basic_
socket
constructors [socket.basic.cons]explicitsocket(const executor_type& ex);basic_
-1- Postconditions:
get_executor() == ex
.is_open() == false
.template<class ExecutionContext> explicitsocket(ExecutionContext& ctx);basic_
Effects:Equivalent to socket(ctx.get_executor()).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
socket(const executor_type& ex, const protocol_type& protocol);basic_
-2- Effects:Opens this socket as if by calling open(protocol)
.
-3- Postconditions:
get_executor() == ex
.is_open() == true
.non_blocking() == false
.protocol_ == protocol
.template<class ExecutionContext> explicitsocket(ExecutionContext& ctx, const protocol_type& protocol);basic_
Effects:Equivalent to socket(ctx.get_executor(), protocol).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
socket(const executor_type& ex, const endpoint_type& endpoint);basic_
-4- Effects:Opens and binds this socket as if by calling:
open(endpoint.protocol()); bind(endpoint);
-5- Postconditions:
get_executor() == ex
.is_open() == true
.non_blocking() == false
.protocol_ == endpoint.protocol()
.template<class ExecutionContext> explicitsocket(ExecutionContext& ctx, const endpoint_type& endpoint);basic_
Effects:Equivalent to socket(ctx.get_executor(), endpoint).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
socket(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_socket);basic_
-6- Requires:native_socket
is a native handle to an open socket.
-7- Effects:Assigns the existing native socket into this socket as if by calling assign(protocol, native_socket)
.
-8- Postconditions:
get_executor() == ex
.is_open() == true
.non_blocking() == false
.protocol_ == protocol
.template<class ExecutionContext>socket(ExecutionContext& ctx, const protocol_type& protocol, const native_handle_type& native_socket);basic_
Effects:Equivalent to socket(ctx.get_executor(), protocol, native_socket).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
socket(basic_
socket&& rhs);basic_
-9- Effects:Move constructs an object of class
that refers to the state originally represented by socket<Protocol, Executor>basic_
rhs
.
-10- Postconditions:
get_executor() == rhs.get_executor()
.is_open()
returns the same value as rhs.is_open()
prior to the constructor invocation.non_blocking()
returns the same value as rhs.non_blocking()
prior to the constructor invocation.native_handle()
returns the prior value of rhs.native_handle()
.protocol_
is the prior value of rhs.protocol_
.rhs.is_open() == false
.template<class OtherProtocol, class OtherExecutor>socket(basic_
socket<OtherProtocol, OtherExecutor>&& rhs);basic_
-11- Requires:OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
-12- Effects:Move constructs an object of class
that refers to the state originally represented by socket<Protocol, Executor>basic_
rhs
.
-13- Postconditions:
get_executor() == rhs.get_executor()
.is_open()
returns the same value as rhs.is_open()
prior to the constructor invocation.non_blocking()
returns the same value as rhs.non_blocking()
prior to the constructor invocation.native_handle()
returns the prior value of rhs.native_handle()
.protocol_
is the result of converting the prior value of rhs.protocol_
.rhs.is_open() == false
.-14- Remarks:This constructor shall not participate in overload resolution unless OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
basic_
socket
destructor [socket.basic.dtor]~socket();basic_
-1- Effects:If is_open()
is true
, cancels all outstanding asynchronous operations associated with this socket, disables the linger socket option to prevent the destructor from blocking, and releases socket resources as if by POSIX close(native_handle())
. Completion handlers for canceled operations are passed an error code ec
such that ec == errc::operation_canceled
yields true
.
basic_
socket
assignment [socket.basic.assign]socket& operator=(basic_
socket&& rhs);basic_
-1- Effects:If is_open()
is true
, cancels all outstanding asynchronous operations associated with this socket. Completion handlers for canceled operations are passed an error code ec
such that ec == errc::operation_canceled
yields true
. Disables the linger socket option to prevent the assignment from blocking, and releases socket resources as if by POSIX close(native_handle())
. Moves into *this
the state originally represented by rhs
.
-2- Postconditions:
get_executor() == rhs.get_executor()
.is_open()
returns the same value as rhs.is_open()
prior to the assignment.non_blocking()
returns the same value as rhs.non_blocking()
prior to the assignment.protocol_
is the prior value of rhs.protocol_
.rhs.is_open() == false
.-3- Returns:*this
.
template<class OtherProtocol, class OtherExecutor>socket& operator=(basic_
socket<OtherProtocol, OtherExecutor>&& rhs);basic_
-4- Requires:OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
-5- Effects:If is_open()
is true
, cancels all outstanding asynchronous operations associated with this socket. Completion handlers for canceled operations are passed an error code ec
such that ec == errc::operation_canceled
yields true
. Disables the linger socket option to prevent the assignment from blocking, and releases socket resources as if by POSIX close(native_handle())
. Moves into *this
the state originally represented by rhs
.
-6- Postconditions:
get_executor() == rhs.get_executor()
.is_open()
returns the same value as rhs.is_open()
prior to the assignment.non_blocking()
returns the same value as rhs.non_blocking()
prior to the assignment.protocol_
is the result of converting the prior value of rhs.protocol_
.rhs.is_open() == false
.-7- Returns:*this
.
-8- Remarks:This assignment operator shall not participate in overload resolution unless OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
basic_
socket
operations [socket.basic.ops][...]
Assuming the changes in P1322 have been applied,
remove the basic_
prefixes
from -18.7- Class basic_datagram_socket
[socket.dgram]:
basic_datagram_socket
[socket.dgram]-1- The class template
is used to send and receive discrete messages of fixed maximum length.basic_datagram_socket<Protocol, Executor>
namespace std { namespace experimental { namespace net { inline namespace v1 { template<class Protocol, class Executor> classbasic_datagram_socket : publicbasic_socket<Protocol, Executor> { public: // types: using executor_type = Executor; using native_handle_type = implementation-defined; // see [socket.reqmts.native] using protocol_type = Protocol; using endpoint_type = typename protocol_type::endpoint; template<class OtherExecutor> using rebind_executor =basic_datagram_socket<Protocol, OtherExecutor>; // [socket.dgram.cons], construct / copy / destroy: explicitbasic_datagram_socket(const executor_type& ex); template<class ExecutionContext> explicitbasic_datagram_socket(ExecutionContext& ctx);basic_datagram_socket(const executor_type& ex, const protocol_type& protocol); template<class ExecutionContext>basic_datagram_socket(ExecutionContext& ctx, const protocol_type& protocol);basic_datagram_socket(const executor_type& ex, const endpoint_type& endpoint); template<class ExecutionContext>basic_datagram_socket(ExecutionContext& ctx, const endpoint_type& endpoint);basic_datagram_socket(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_socket); template<class ExecutionContext>basic_datagram_socket(ExecutionContext& ctx, const protocol_type& protocol, const native_handle_type& native_socket);basic_datagram_socket(constbasic_datagram_socket&) = delete;basic_datagram_socket(basic_datagram_socket&& rhs); template<class OtherProtocol, class OtherExecutor>basic_datagram_socket(basic_datagram_socket<OtherProtocol, OtherExecutor>&& rhs); ~basic_datagram_socket();basic_datagram_socket& operator=(constbasic_datagram_socket&) = delete;basic_datagram_socket& operator=(basic_datagram_socket&& rhs); template<class OtherProtocol, class OtherExecutor>basic_datagram_socket& operator=(basic_datagram_socket<OtherProtocol, OtherExecutor>&& rhs); // [socket.dgram.op],basic_datagram_socket operations:
[...]
}; } // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
-2- Instances of class template
meet the requirements of datagram_socketbasic_
Destructible
(C++2014[destructible]), MoveConstructible
(C++2014[moveconstructible]), and MoveAssignable
(C++2014[moveassignable]).
-3- If a program performs a synchronous operation on this socket, other than close
, cancel
, shutdown
, send
, or send_to
, while there is an outstanding asynchronous read operation, the behavior is undefined.
-4- If a program performs a synchronous operation on this socket, other than close
, cancel
, shutdown
, receive
, or receive_from
, while there is an outstanding asynchronous write operation, the behavior is undefined.
-5- When an operation has its effects specified as if by passing the result of native_handle()
to a POSIX function, then the operation fails with error condition errc::bad_file_descriptor
if is_open() == false
at the point in the effects when the POSIX function is called.
-6- If native_handle_type
and
are both defined then they name the same type.socket<Protocol, Executor>::native_handle_typebasic_
basic_
datagram_socket
constructors [socket.dgram.cons]explicitdatagram_socket(const executor_type& ex);basic_
-1- Effects:Initializes the base class with
.socket<Protocol, Executor>(ex)basic_
template<class ExecutionContext> explicitdatagram_socket(ExecutionContext& ctx);basic_
Effects:Equivalent to datagram_socket(ctx.get_executor()).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
datagram_socket(const executor_type& ex, const protocol_type& protocol);basic_
-2- Effects:Initializes the base class with
.socket<Protocol, Executor>(ctx, protocol)basic_
template<class ExecutionContext> explicitdatagram_socket(ExecutionContext& ctx, const protocol_type& protocol);basic_
Effects:Equivalent to datagram_socket(ctx.get_executor(), protocol).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
datagram_socket(const executor_type& ex, const endpoint_type& endpoint);basic_
-3- Effects:Initializes the base class with
.socket<Protocol, Executor>(ctx, endpoint)basic_
template<class ExecutionContext> explicitdatagram_socket(ExecutionContext& ctx, const endpoint_type& endpoint);basic_
Effects:Equivalent to datagram_socket(ctx.get_executor(), endpoint).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
datagram_socket(io_context& ctx, const protocol_type& protocol, const native_handle_type& native_socket);basic_
-4- Effects:Initializes the base class with
.socket<Protocol, Executor>(ctx, protocol, native_socket)basic_
template<class ExecutionContext>datagram_socket(ExecutionContext& ctx, const protocol_type& protocol, const native_handle_type& native_socket);basic_
Effects:Equivalent to datagram_socket(ctx.get_executor(), protocol, native_socket).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
datagram_socket(basic_
datagram_socket&& rhs);basic_
-5- Effects:Move constructs an object of class
, initializing the base class with datagram_socket<Protocol, Executor>basic_
.socket<Protocol, Executor>(std::move(rhs))basic_
template<class OtherProtocol, class OtherExecutor>datagram_socket(basic_
datagram_socket<OtherProtocol, OtherExecutor>&& rhs);basic_
-6- Requires:OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
-7- Effects:Move constructs an object of class
, initializing the base class with datagram_socket<Protocol, Executor>basic_
.socket<Protocol, Executor>(std::move(rhs))basic_
-8- Remarks:This constructor shall not participate in overload resolution unless OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
basic_
datagram_socket
assignment [socket.dgram.assign]datagram_socket& operator=(basic_
datagram_socket&& rhs);basic_
-1- Effects:Equivalent to
.socket<Protocol, Executor>::operator=(std::move(rhs))basic_
-2- Returns:*this
.
template<class OtherProtocol, class OtherExecutor>datagram_socket& operator=(basic_
datagram_socket<OtherProtocol, OtherExecutor>&& rhs);basic_
-3- Requires:OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
-4- Effects:Equivalent to
.socket<Protocol, Executor>::operator=(std::move(rhs))basic_
-5- Returns:*this
.
-6- Remarks:This assignment operator not participate in overload resolution unless OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
basic_
datagram_socket
operations [socket.dgram.op][...]
Assuming the changes in P1322 have been applied,
remove the basic_
prefixes
from -18.8- Class basic_stream_socket
[socket.stream]:
basic_stream_socket
[socket.stream]-1- The class template
is used to exchange data with a peer over a sequenced, reliable, bidirectional, connection-mode byte stream.basic_stream_socket<Protocol, Executor>
namespace std { namespace experimental { namespace net { inline namespace v1 { template<class Protocol, class Executor> classbasic_stream_socket : publicbasic_socket<Protocol, Executor> { public: // types: using executor_type = Executor; using native_handle_type = implementation-defined; // see [socket.reqmts.native] using protocol_type = Protocol; using endpoint_type = typename protocol_type::endpoint; template<class OtherExecutor> using rebind_executor =basic_stream_socket<Protocol, OtherExecutor>; // [socket.stream.cons], construct / copy / destroy: explicitbasic_stream_socket(const executor_type& ex); template<class ExecutionContext> explicitbasic_stream_socket(ExecutionContext& ctx);basic_stream_socket(const executor_type& ex, const protocol_type& protocol); template<class ExecutionContext>basic_stream_socket(ExecutionContext& ctx, const protocol_type& protocol);basic_stream_socket(const executor_type& ex, const endpoint_type& endpoint); template<class ExecutionContext>basic_stream_socket(ExecutionContext& ctx, const endpoint_type& endpoint);basic_stream_socket(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_socket); template<class ExecutionContext>basic_stream_socket(ExecutionContext& ctx, const protocol_type& protocol, const native_handle_type& native_socket);basic_stream_socket(constbasic_stream_socket&) = delete;basic_stream_socket(basic_stream_socket&& rhs); template<class OtherProtocol, class OtherExecutor>basic_stream_socket(basic_stream_socket<OtherProtocol, OtherExecutor>&& rhs); ~basic_stream_socket();basic_stream_socket& operator=(constbasic_stream_socket&) = delete;basic_stream_socket& operator=(basic_stream_socket&& rhs); template<class OtherProtocol, class OtherExecutor>basic_stream_socket& operator=(basic_stream_socket<OtherProtocol, OtherExecutor>&& rhs); // [socket.stream.ops],basic_stream_socket operations:
[...]
}; } // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
-2- Instances of class template
meet the requirements of stream_socketbasic_
Destructible
(C++2014[destructible]), MoveConstructible
(C++2014[moveconstructible]), MoveAssignable
(C++2014[moveassignable]), SyncReadStream
([buffer.stream.reqmts.syncreadstream]), SyncWriteStream
([buffer.stream.reqmts.syncwritestream]), AsyncReadStream
([buffer.stream.reqmts.asyncreadstream]), and AsyncWriteStream
([buffer.stream.reqmts.asyncwritestream]).
-3- If a program performs a synchronous operation on this socket, other than close
, cancel
, shutdown
, or send
, while there is an outstanding asynchronous read operation, the behavior is undefined.
-4- If a program performs a synchronous operation on this socket, other than close
, cancel
, shutdown
, or receive
, while there is an outstanding asynchronous write operation, the behavior is undefined.
-5- When an operation has its effects specified as if by passing the result of native_handle()
to a POSIX function, then the operation fails with error condition errc::bad_file_descriptor
if is_open() == false
at the point in the effects when the POSIX function is called.
-6- If native_handle_type
and
are both defined then they name the same type.socket<Protocol, Executor>::native_handle_typebasic_
basic_
stream_socket
constructors [socket.stream.cons]explicitstream_socket(const executor_type& ex);basic_
-1- Effects:Initializes the base class with
.socket<Protocol, Executor>(ctx)basic_
template<class ExecutionContext> explicitstream_socket(ExecutionContext& ctx);basic_
Effects:Equivalent to stream_socket(ctx.get_executor()).basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
stream_socket(const executor_type& ex, const protocol_type& protocol);basic_
-2- Effects:Initializes the base class with
.socket<Protocol, Executor>(ctx, protocol)basic_
template<class ExecutionContext> explicitstream_socket(ExecutionContext& ctx, const protocol_type& protocol);basic_
Effects:Equivalent to
.stream_socket(ctx.get_executor(), protocol)basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
stream_socket(const executor_type& ex, const endpoint_type& endpoint);basic_
-3- Effects:Initializes the base class with
.socket<Protocol, Executor>(ctx, endpoint)basic_
template<class ExecutionContext> explicitstream_socket(ExecutionContext& ctx, const endpoint_type& endpoint);basic_
Effects:Equivalent to
.stream_socket(ctx.get_executor(), endpoint)basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
stream_socket(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_socket);basic_
-4- Effects:Initializes the base class with
.socket<Protocol, Executor>(ctx, protocol, native_socket)basic_
template<class ExecutionContext>stream_socket(ExecutionContext& ctx, const protocol_type& protocol, const native_handle_type& native_socket);basic_
Effects:Equivalent to
.stream_socket(ctx.get_executor(), protocol, native_socket)basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
stream_socket(basic_
stream_socket&& rhs);basic_
-5- Effects:Move constructs an object of class
, initializing the base class with stream_socket<Protocol, Executor>basic_
.socket<Protocol, Executor>(std::move(rhs))basic_
template<class OtherProtocol, class OtherExecutor>stream_socket(basic_
stream_socket<OtherProtocol, OtherExecutor>&& rhs);basic_
-6- Requires:OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
-7- Effects:Move constructs an object of class
, initializing the base class with stream_socket<Protocol, Executor>basic_
.socket<Protocol, Executor>(std::move(rhs))basic_
-8- Remarks:This constructor shall not participate in overload resolution unless OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
basic_
stream_socket
assignment [socket.stream.assign]stream_socket& operator=(basic_
stream_socket&& rhs);basic_
-1- Effects:Equivalent to
.socket<Protocol, Executor>::operator=(std::move(rhs))basic_
-2- Returns:*this
.
template<class OtherProtocol, class OtherExecutor>stream_socket& operator=(basic_
stream_socket<OtherProtocol, OtherExecutor>&& rhs);basic_
-3- Requires:OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
-4- Effects:Equivalent to
.socket<Protocol, Executor>::operator=(std::move(rhs))basic_
-5- Returns:*this
.
-6- Remarks:This assignment operator shall not participate in overload resolution unless OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
basic_
stream_socket
operations [socket.stream.ops][...]
Assuming the changes in P1322 have been applied,
remove the basic_
prefixes
from -18.9- Class basic_socket_acceptor
[socket.acceptor]:
basic_socket_acceptor
[socket.acceptor]-1- An object of class template
is used to listen for, and queue, incoming socket connections. Socket objects that represent the incoming connections are dequeued by calling basic_socket_acceptor<AcceptableProtocol, Executor>accept
or async_accept
.
namespace std { namespace experimental { namespace net { inline namespace v1 { template<class AcceptableProtocol, class Executor> classbasic_socket_acceptor : public socket_base { public: // types: using executor_type = Executor; using native_handle_type = implementation-defined; // see [socket.reqmts.native] using protocol_type = AcceptableProtocol; using endpoint_type = typename protocol_type::endpoint; using socket_type = typename protocol_type::socket_for<executor_type>; template<class OtherExecutor> using socket_type_for = typename protocol_type::socket_for<OtherExecutor>; template<class OtherExecutor> using rebind_executor =basic_socket_acceptor<AcceptableProtocol, OtherExecutor>; // [socket.acceptor.cons], construct / copy / destroy: explicitbasic_socket_acceptor(const executor_type& ex); template<class ExecutionContext> explicitbasic_socket_acceptor(ExecutionContext& ctx);basic_socket_acceptor(const executor_type& ex, const protocol_type& protocol); template<class ExecutionContext>basic_socket_acceptor(ExecutionContext& ctx, const protocol_type& protocol);basic_socket_acceptor(const executor_type& ex, const endpoint_type& endpoint, bool reuse_addr = true); template<class ExecutionContext>basic_socket_acceptor(ExecutionContext& ctx, const endpoint_type& endpoint, bool reuse_addr = true);basic_socket_acceptor(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_socket); template<class ExecutionContext>basic_socket_acceptor(ExecutionContext& ctx, const protocol_type& protocol, const native_handle_type& native_socket);basic_socket_acceptor(constbasic_socket_acceptor&) = delete;basic_socket_acceptor(basic_socket_acceptor&& rhs); template<class OtherProtocol, class OtherExecutor>basic_socket_acceptor(basic_socket_acceptor<OtherProtocol, OtherExecutor>&& rhs); ~basic_socket_acceptor();basic_socket_acceptor& operator=(constbasic_socket_acceptor&) = delete;basic_socket_acceptor& operator=(basic_socket_acceptor&& rhs); template<class OtherProtocol, class OtherExecutor>basic_socket_acceptor& operator=(basic_socket_acceptor<OtherProtocol, OtherExecutor>&& rhs); // [socket.acceptor.ops],basic_socket_acceptor operations:
[...]
}; } // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
-2- Instances of class template
meet the requirements of socket_acceptorbasic_
Destructible
(C++2014[destructible]), MoveConstructible
(C++2014[moveconstructible]), and MoveAssignable
(C++2014[moveassignable]).
-3- When there are multiple outstanding asynchronous accept operations the order in which the incoming connections are dequeued, and the order of invocation of the completion handlers for these operations, is unspecified.
-4- When an operation has its effects specified as if by passing the result of native_handle()
to a POSIX function, then the operation fails with error condition errc::bad_file_descriptor
if is_open() == false
at the point in the effects when the POSIX function is called.
basic_
socket_acceptor
constructors [socket.acceptor.cons]explicitsocket_acceptor(const executor_type& ex);basic_
-1- Postconditions:
get_executor() == ex
.is_open() == false
.template<class ExecutionContext> explicitsocket_acceptor(ExecutionContext& ctx);basic_
Effects:Equivalent to
.socket_acceptor(ctx.get_executor())basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
socket_acceptor(const executor_type& ex, const protocol_type& protocol);basic_
-2- Effects:Opens this acceptor as if by calling open(protocol)
.
-3- Postconditions:
get_executor() == ex
.is_open() == true
.non_blocking() == false
.enable_connection_aborted() == false
.protocol_ == protocol
.template<class ExecutionContext> explicitsocket_acceptor(ExecutionContext& ctx, const protocol_type& protocol);basic_
Effects:Equivalent to
.socket_acceptor(ctx.get_executor(), protocol)basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
socket_acceptor(const executor_type& ex, const endpoint_type& endpoint, bool reuse_addr = true);basic_
-4- Effects:Opens and binds this acceptor as if by calling:
open(endpoint.protocol()); if (reuse_addr) set_option(reuse_address(true)); bind(endpoint); listen();
-5- Postconditions:
get_executor() == ex
.is_open() == true
.non_blocking() == false
.enable_connection_aborted() == false
.protocol_ == endpoint.protocol()
.template<class ExecutionContext> explicitsocket_acceptor(ExecutionContext& ctx, const endpoint_type& endpoint, bool reuse_addr = true);basic_
Effects:Equivalent to
.socket_acceptor(ctx.get_executor(), endpoint, reuse_addr)basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
socket_acceptor(const executor_type& ex, const protocol_type& protocol, const native_handle_type& native_acceptor);basic_
-6- Requires:native_acceptor
is a native handle to an open acceptor.
-7- Effects:Assigns the existing native acceptor into this acceptor as if by calling assign(protocol, native_acceptor)
.
-8- Postconditions:
get_executor() == ex
.is_open() == true
.non_blocking() == false
.enable_connection_aborted() == false
.protocol_ == protocol
.template<class ExecutionContext>socket_acceptor(ExecutionContext& ctx, const protocol_type& protocol, const native_handle_type& native_socket);basic_
Effects:Equivalent to
.socket_acceptor(ctx.get_executor(), protocol, native_socket)basic_
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
socket_acceptor(basic_
socket_acceptor&& rhs);basic_
-9- Effects:Move constructs an object of class
that refers to the state originally represented by socket_acceptor<AcceptableProtocol, Executor>basic_
rhs
.
-10- Postconditions:
get_executor() == rhs.get_executor()
.is_open()
returns the same value as rhs.is_open()
prior to the constructor invocation.non_blocking()
returns the same value as rhs.non_blocking()
prior to the constructor invocation.enable_connection_aborted()
returns the same value as rhs.enable_connection_aborted()
prior to the constructor invocation.native_handle()
returns the same value as rhs.native_handle()
prior to the constructor invocation.protocol_
is equal to the prior value of rhs.protocol_
.rhs.is_open() == false
.template<class OtherProtocol, class OtherExecutor>socket_acceptor(basic_
socket_acceptor<OtherProtocol, OtherExecutor>&& rhs);basic_
-11- Requires:OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
-12- Effects:Move constructs an object of class
that refers to the state originally represented by socket_acceptor<AcceptableProtocol, Executor>basic_
rhs
.
-13- Postconditions:
get_executor() == rhs.get_executor()
.is_open()
returns the same value as rhs.is_open()
prior to the constructor invocation.non_blocking()
returns the same value as rhs.non_blocking()
prior to the constructor invocation.enable_connection_aborted()
returns the same value as rhs.enable_connection_aborted()
prior to the constructor invocation.native_handle()
returns the prior value of rhs.native_handle()
.protocol_
is the result of converting the prior value of rhs.protocol_
.rhs.is_open() == false
.-14- Remarks:This constructor shall not participate in overload resolution unless OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
basic_
socket_acceptor
destructor [socket.acceptor.dtor]~socket_acceptor();basic_
-1- Effects:If is_open()
is true
, cancels all outstanding asynchronous operations associated with this acceptor, and releases acceptor resources as if by POSIX close(native_handle())
. Completion handlers for canceled operations are passed an error code ec
such that ec == errc::operation_canceled
yields true
.
basic_
socket_acceptor
assignment [socket.acceptor.assign]socket_acceptor& operator=(basic_
socket_acceptor&& rhs);basic_
-1- Effects:If is_open()
is true
, cancels all outstanding asynchronous operations associated with this acceptor, and releases acceptor resources as if by POSIX close(native_handle())
. Then moves into *this
the state originally represented by rhs
. Completion handlers for canceled operations are passed an error code ec
such that ec == errc::operation_canceled
yields true
.
-2- Postconditions:
get_executor() == rhs.get_executor()
.is_open()
returns the same value as rhs.is_open()
prior to the assignment.non_blocking()
returns the same value as rhs.non_blocking()
prior to the assignment.enable_connection_aborted()
returns the same value as rhs.enable_connection_aborted()
prior to the assignment.native_handle()
returns the same value as rhs.native_handle()
prior to the assignment.protocol_
is the same value as rhs.protocol_
prior to the assignment.rhs.is_open() == false
.-3- Returns:*this
.
template<class OtherProtocol, class OtherExecutor>socket_acceptor& operator=(basic_
socket_acceptor<OtherProtocol, OtherExecutor>&& rhs);basic_
-4- Requires:OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
-5- Effects:If is_open()
is true
, cancels all outstanding asynchronous operations associated with this acceptor, and releases acceptor resources as if by POSIX close(native_handle())
. Then moves into *this
the state originally represented by rhs
. Completion handlers for canceled operations are passed an error code ec
such that ec == errc::operation_canceled
yields true
.
-6- Postconditions:
get_executor() == rhs.get_executor()
.is_open()
returns the same value as rhs.is_open()
prior to the assignment.non_blocking()
returns the same value as rhs.non_blocking()
prior to the assignment.enable_connection_aborted()
returns the same value as rhs.enable_connection_aborted()
prior to the assignment.native_handle()
returns the same value as rhs.native_handle()
prior to the assignment.protocol_
is the result of converting the value of rhs.protocol_
prior to the assignment.rhs.is_open() == false
.-7- Returns:*this
.
-8- Remarks:This assignment operator shall not participate in overload resolution unless OtherProtocol
is implicitly convertible to Protocol
and OtherExecutor
is implicitly convertible to Executor
.
basic_
socket_acceptor
operations [socket.acceptor.ops][...]
Assuming the changes in P1322 have been applied,
io_context::executor_type
as the default for the iostream class templates' Executor
template parameters,protocol_type
's resolver_for
type alias instead of resolver
, andbasic_
prefixesin -19.1- Class template basic_socket_streambuf
[socket.streambuf]:
basic_
socket_streambuf
[socket.streambuf]-1- The class
associates both the input sequence and the output sequence with a socket. The input and output sequences do not support seeking. [ Note: The input and output sequences are independent as a stream socket provides full duplex I/O. -- end note ] socket_streambuf<Protocol, Clock, WaitTraits, Executor>basic_
-2- [ Note: This class is intended for sending and receiving bytes, not characters. Any conversion from characters to bytes, and vice versa, occurs elsewhere. -- end note ]
namespace std { namespace experimental { namespace net { inline namespace v1 { template<class Protocol, class Clock, class WaitTraits, class Executor =executorio_context::executor_type> classbasic_socket_streambuf : public basic_streambuf<char> { public: // types: using executor_type = Executor; using protocol_type = Protocol; using endpoint_type = typename protocol_type::endpoint; using clock_type = Clock; using time_point = typename clock_type::time_point; using duration = typename clock_type::duration; using wait_traits_type = WaitTraits; // [socket.streambuf.cons], construct / copy / destroy:basic_socket_streambuf(); explicitbasic_socket_streambuf(basic_stream_socket<protocol_type, executor_type> s);basic_socket_streambuf(constbasic_socket_streambuf&) = delete;basic_socket_streambuf(basic_socket_streambuf&& rhs); virtual ~basic_socket_streambuf();basic_socket_streambuf& operator=(constbasic_socket_streambuf&) = delete;basic_socket_streambuf& operator=(basic_socket_streambuf&& rhs); // [socket.streambuf.members], members:basic_socket_streambuf* connect(const endpoint_type& e); template<class... Args>basic_socket_streambuf* connect(Args&&... );basic_socket_streambuf* close();basic_socket<protocol_type, executor_type>& socket(); error_code error() const; time_point expiry() const; void expires_at(const time_point& t); void expires_after(const duration& d); protected: // overridden virtual functions: virtual int_type underflow() override; virtual int_type pbackfail(int_type c = traits_type::eof()) override; virtual int_type overflow(int_type c = traits_type::eof()) override; virtual int sync() override; virtual streambuf* setbuf(char_type* s, streamsize n) override; private:basic_stream_socket<protocol_type, executor_type> socket_; // exposition only error_code ec_; // exposition only time_point expiry_; // exposition only }; } // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
-3- Instances of class template
meet the requirements of socket_streambufbasic_
Destructible
(C++2014[destructible]), MoveConstructible
(C++2014[moveconstructible]), and MoveAssignable
(C++2014[moveassignable]).
basic_
socket_streambuf
constructors [socket.streambuf.cons]socket_streambuf();basic_
-1- Effects:Initializes socket_
with ctx
, where ctx
is an unspecified object of class io_context
.
-2- Postconditions:expiry() == time_point::max()
and !error()
.
Remarks:This function shall not participate in overload resolution unless
is_constructible<executor_type, io_context::executor_type>::value
is true
.
explicitsocket_streambuf(basic_
stream_socket<protocol_type, executor_type> s);basic_
-3- Effects:Initializes socket_
with std::move(s)
.
-4- Postconditions:expiry() == time_point::max()
and !error()
.
socket_streambuf(basic_
socket_streambuf&& rhs);basic_
-5- Effects:Move constructs from the rvalue rhs
. It is implementation-defined whether the sequence pointers in *this
(eback()
, gptr()
, egptr()
, pbase()
, pptr()
, epptr()
) obtain the values which rhs
had. Whether they do or not, *this
and rhs
reference separate buffers (if any at all) after the construction. Additionally *this
references the socket which rhs
did before the construction, and rhs
references no open socket after the construction.
-6- Postconditions:Let rhs_p
refer to the state of rhs
just prior to this construction and let rhs_a
refer to the state of rhs
just after this construction.
is_open() == rhs_p.is_open()
rhs_a.is_open() == false
error() == rhs_p.error()
!rhs_a.error()
expiry() == rhs_p.expiry()
rhs_a.expiry() == time_point::max()
gptr() - eback() == rhs_p.gptr() - rhs_p.eback()
egptr() - eback() == rhs_p.egptr() - rhs_p.eback()
ptr() - pbase() == rhs_p.pptr() - rhs_p.pbase()
pptr() - pbase() == rhs_p.epptr() - rhs_p.pbase()
if (eback()) eback() != rhs_a.eback()
if (gptr()) gptr() != rhs_a.gptr()
if (egptr()) egptr() != rhs_a.egptr()
if (pbase()) pbase() != rhs_a.pbase()
if (pptr()) pptr() != rhs_a.pptr()
if (epptr()) epptr() != rhs_a.epptr()
virtual ~socket_streambuf();basic_
-7- Effects:If a put area exists, calls overflow(traits_type::eof())
to flush characters. [ Note: The socket is closed by the
destructor. -- end note ] stream_socket<protocol_type, executor_type>basic_
socket_streambuf& operator=(basic_
socket_streambuf&& rhs);basic_
-8- Effects:Calls this->close()
then move assigns from rhs
. After the move assignment *this
and rhs
have the observable state
they would have had if *this
had been move constructed from rhs
.
-9- Returns:*this
.
basic_
socket_streambuf
members [socket.streambuf.members]socket_streambuf* connect(const endpoint_type& e);basic_
-1- Effects:Initializes the
as required, closes and re-opens the socket by performing socket_streambufbasic_
socket_.close(ec_)
and socket_.open(e.protocol(), ec_)
, then attempts to establish a connection as if by POSIX connect(socket_.native_handle(), static_cast<sockaddr*>(e.data()), e.size())
. ec_
is set to reflect the error code produced by the operation. If the operation does not complete before the absolute timeout specified by expiry_
, the socket is closed and ec_
is set to errc::timed_out
.
-2- Returns:if !ec_
, this
; otherwise, a null pointer.
template<class... Args>socket_streambuf* connect(Args&&... args);basic_
-3- Effects:Initializes the
as required and closes the socket as if by calling socket_streambufbasic_
socket_.close(ec_)
. Obtains an endpoint sequence endpoints
by performing protocol_type::resolver
, where _for<executor_type>
(ctx).resolve(forward<Args>(args)...)ctx
is an unspecified object of class io_context
. For each endpoint e
in the sequence, closes and re-opens the socket by performing socket_.close(ec_)
and socket_.open(e.protocol(), ec_)
, then attempts to establish a connection as if by POSIX connect(socket_.native_handle(), static_cast<sockaddr*>(e.data()), e.size())
. ec_
is set to reflect the error code produced by the operation. If the operation does not complete before the absolute timeout specified by expiry_
, the socket is closed and ec_
is set to errc::timed_out
.
-4- Returns:if !ec_
, this
; otherwise, a null pointer.
-5- Remarks:This function shall not participate in overload resolution unless Protocol
meets the requirements for an internet protocol ([internet.reqmts.protocol]).
socket_streambuf* close();basic_
-6- Effects:If a put area exists, calls overflow(traits_type::eof())
to flush characters. Regardless of whether the preceding call fails or throws an exception, the function closes the socket as if by
. If any of the calls made by the function fail, socket<protocol_type, executor_type>::close(ec_)basic_
close
fails by returning a null pointer. If one of these calls throws an exception, the exception is caught and rethrown after closing the socket.
-7- Returns:this
on success, a null pointer otherwise.
-8- Postconditions:is_open() == false
.
socket<protocol_type, executor_type>& socket();basic_
-9- Returns:socket_
.
error_code error() const;
-10- Returns:ec_
.
time_point expiry() const;
-11- Returns:expiry_
.
void expires_at(const time_point& t);
-12- Postconditions:expiry_ == t
.
void expires_after(const duration& d);
-13- Effects:Equivalent to expires_at(clock_type::now() + d)
.
basic_
socket_streambuf
overridden virtual functions [socket.streambuf.virt][...]
Assuming the changes in P1322 have been applied,
io_context::executor_type
as the default for the iostream class templates' Executor
template parameters,basic_
prefixesin -19.2- Class template basic_socket_iostream
[socket.iostream]:
basic_
socket_iostream
[socket.iostream]-1- The class template
supports reading and writing on sockets. It uses a basic_socket_iostream<Protocol, Clock, WaitTraits, Executor>
object to control the associated sequences.basic_socket_streambuf<Protocol, Clock, WaitTraits, Executor>
-2- [ Note: This class is intended for sending and receiving bytes, not characters. Any conversion from characters to bytes, and vice versa, occurs elsewhere. -- end note ]
namespace std { namespace experimental { namespace net { inline namespace v1 { template<class Protocol, class Clock, class WaitTraits, class Executor =executorio_context::executor_type> classbasic_socket_iostream : public basic_iostream<char> { public: // types: using executor_type = Executor; using protocol_type = Protocol; using endpoint_type = typename protocol_type::endpoint; using clock_type = Clock; using time_point = typename clock_type::time_point; using duration = typename clock_type::duration; using wait_traits_type = WaitTraits; // [socket.iostream.cons], construct / copy / destroy:basic_socket_iostream(); explicitbasic_socket_iostream(basic_stream_socket<protocol_type, executor_type> s);basic_socket_iostream(constbasic_socket_iostream&) = delete;basic_socket_iostream(basic_socket_iostream&& rhs); template<class... Args> explicitbasic_socket_iostream(Args&&... args);basic_socket_iostream& operator=(constbasic_socket_iostream&) = delete;basic_socket_iostream& operator=(basic_socket_iostream&& rhs); // [socket.iostream.members], members: template<class... Args> void connect(Args&&... args); void close();basic_socket_streambuf<protocol_type, clock_type, wait_traits_type, executor_type>* rdbuf() const;basic_socket<protocol_type, executor_type>& socket(); error_code error() const; time_point expiry() const; void expires_at(const time_point& t); void expires_after(const duration& d); private:basic_socket_streambuf<protocol_type, clock_type, wait_traits_type, executor_type> sb_; // exposition only }; } // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
-3- Instances of class template
meet the requirements of socket_iostreambasic_
Destructible
(C++2014[destructible]), MoveConstructible
(C++2014[moveconstructible]), and MoveAssignable
(C++2014[moveassignable]).
basic_
socket_iostream
constructors [socket.iostream.cons]socket_iostream();basic_
-1- Effects:Initializes the base class as basic_iostream<char>(&sb_)
, value-initializes sb_
, and performs setf(std::ios_base::unitbuf)
.
Remarks:This function shall not participate in overload resolution unless
is_default_constructible<
is socket_streambuf<protocol_type, clock_type, wait_traits_type, executor_type>>::valuebasic_
true
.
explicitsocket_iostream(basic_
stream_socket<protocol_type, executor_type> s);basic_
-2- Effects:Initializes the base class as basic_iostream<char>(&sb_)
, initializes sb_
with std::move(s)
, and performs setf(std::ios_base::unitbuf)
.
socket_iostream(basic_
socket_iostream&& rhs);basic_
-3- Effects:Move constructs from the rvalue rhs
. This is accomplished by move constructing the base class, and the contained
. Next socket_streambufbasic_
basic_iostream<char>::set_rdbuf(&sb_)
is called to install the contained
.socket_streambufbasic_
template<class... Args> explicitsocket_iostream(Args&&... args);basic_
-4- Effects:Initializes the base class as basic_iostream<char>(&sb_)
, value-initializes sb_
, and performs setf(std::ios_base::unitbuf)
. Then calls rdbuf()->connect(forward<Args>(args)...)
. If that function returns a null pointer, calls setstate(failbit)
.
socket_iostream& operator=(basic_
socket_iostream&& rhs);basic_
-5- Effects:Move assigns the base and members of *this
from the base and corresponding members of rhs
.
-6- Returns:*this
.
basic_
socket_iostream
members [socket.iostream.members]template<class... Args> void connect(Args&&... args);
-1- Effects:Calls rdbuf()->connect(forward<Args>(args)...)
. If that function returns a null pointer, calls setstate(failbit)
(which may throw ios_base::failure
).
void close();
-2- Effects:Calls rdbuf()->close()
. If that function returns a null pointer, calls setstate(failbit)
(which may throw ios_base::failure
).
socket_streambuf<protocol_type, clock_type, wait_traits_type, executor_type>* rdbuf() const;basic_
-3- Let SB
be the type
.socket_streambuf<protocol_type, clock_type, wait_traits_type, executor_type>basic_
-4- Returns:const_cast<SB*>(addressof(sb_))
.
socket<protocol_type, executor_type>& socket();basic_
-5- Returns:rdbuf()->socket()
.
[...]
Remove the basic_
prefix from basic_socket
in -20.1- Synchronous connect operations [socket.algo.connect] as follows:
template<class Protocol, class Executor, class EndpointSequence> typename Protocol::endpoint connect(socket<Protocol, Executor>& s, const EndpointSequence& endpoints); template<class Protocol, class Executor, class EndpointSequence> typename Protocol::endpoint connect(basic_
socket<Protocol, Executor>& s, const EndpointSequence& endpoints, error_code& ec);basic_
[...]
template<class Protocol, class Executor, class EndpointSequence, class ConnectCondition> typename Protocol::endpoint connect(socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition c); template<class Protocol, class Executor, class EndpointSequence, class ConnectCondition> typename Protocol::endpoint connect(basic_
socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition c, error_code& ec);basic_
[...]
template<class Protocol, class Executor, class InputIterator> InputIterator connect(socket<Protocol, Executor>& s, InputIterator first, InputIterator last); template<class Protocol, class Executor, class InputIterator> InputIterator connect(basic_
socket<Protocol, Executor>& s, InputIterator first, InputIterator last, error_code& ec);basic_
[...]
template<class Protocol, class Executor, class InputIterator, class ConnectCondition> InputIterator connect(socket<Protocol, Executor>& s, InputIterator first, InputIterator last, ConnectCondition c); template<class Protocol, class Executor, class InputIterator, class ConnectCondition> InputIterator connect(basic_
socket<Protocol, Executor>& s, InputIterator first, InputIterator last, ConnectCondition c, error_code& ec);basic_
[...]
Remove the basic_
prefix from basic_socket
in -20.2- Asynchronous connect operations [socket.algo.async.connect] as follows:
template<class Protocol, class Executor, class EndpointSequence, class CompletionToken> DEDUCED async_connect(socket<Protocol, Executor>& s, const EndpointSequence& endpoints, CompletionToken&& token);basic_
[...]
template<class Protocol, class Executor, class EndpointSequence, class ConnectCondition, class CompletionToken> DEDUCED async_connect(socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition c, CompletionToken&& token);basic_
[...]
template<class Protocol, class Executor, class InputIterator, class CompletionToken> DEDUCED async_connect(socket<Protocol, Executor>& s, InputIterator first, InputIterator last, CompletionToken&& token);basic_
[...]
template<class Protocol, class Executor, class InputIterator, class ConnectCondition, class CompletionToken> DEDUCED async_connect(socket<Protocol, Executor>& s, InputIterator first, InputIterator last, ConnectCondition c, CompletionToken&& token);basic_
[...]
Assuming the changes in P1322 have been applied,
executor
as the default for the Executor
template parameter,basic_
prefixin -21.1- Header <experimental/internet> synopsis [internet.synop]:
template<class InternetProtocol, class Executor= executor> classbasic_resolver;
Assuming the changes in P1322 have been applied,
resolver_for
instead of resolver
, andbasic_
prefixin -21.2.1- Internet protocol requirements [internet.reqmts.protocol]:
-1- A type X
meets the InternetProtocol
requirements if it satisfies the requirements of AcceptableProtocol
([socket.reqmts.acceptableprotocol]), as well as the additional requirements listed below.
-2- In the table below,
a
and b
denote (possibly const) values of type X
, and E
is a type that models execution::executor
(P0443R13).
expression | return type | assertion/note pre/post-conditions |
X::resolver | ip:: | The type of a resolver for the protocol and executor. |
X::v4() | X | Returns an object representing the IP version 4 protocol. |
X::v6() | X | Returns an object representing the IP version 6 protocol. |
a == b | convertible to bool | Returns true if a and b represent the same IP protocol version, otherwise false . |
a != b | convertible to bool | Returns !(a == b) . |
Assuming the changes in P1322 have been applied,
basic_
prefix, andresolve
and async_resolve
in -21.15- Class template ip::basic_resolver_results
[internet.resolver.results]:
[...]
-3- A default-constructed basic_resolver_results
object is empty. A non-empty results object is obtained only by calling a
object's resolverbasic_
wait
resolve
or async_
operations, or otherwise by copy construction, move construction, assignment, or swap from another non-empty results object.wait
resolve
Assuming the changes in P1322 have been applied,
executor
as the default for the Executor
template parameter,basic_
prefixin -21.17- Class template ip::basic_resolver
[internet.resolver]:
ip::basic_resolver
[internet.resolver]-1- Objects of type
are used to perform name resolution. Name resolution is the translation of a host name and service name into a sequence of endpoints, or the translation of an endpoint into its corresponding host name and service name.resolver<InternetProtocol, Executor>basic_
namespace std { namespace experimental { namespace net { inline namespace v1 { namespace ip { template<class InternetProtocol, class Executor= executor> classbasic_resolver : public resolver_base { public: // types: using executor_type = Executor; using protocol_type = InternetProtocol; using endpoint_type = typename InternetProtocol::endpoint; using results_type = basic_resolver_results<InternetProtocol>; template<class OtherExecutor> using rebind_executor =basic_resolver<InternetProtocol, OtherExecutor>; // [internet.resolver.cons], construct / copy / destroy: explicitbasic_resolver(const executor_type& ex); template<class ExecutionContext> explicitbasic_resolver(ExecutionContext& ctx);basic_resolver(constbasic_resolver&) = delete;basic_resolver(basic_resolver&& rhs) noexcept; ~basic_resolver();basic_resolver& operator=(constbasic_resolver&) = delete;basic_resolver& operator=(basic_resolver&& rhs); // [internet.resolver.ops],basic_resolver operations: executor_type get_executor() noexcept; void cancel(); results_type resolve(string_view host_name, string_view service_name); results_type resolve(string_view host_name, string_view service_name, error_code& ec); results_type resolve(string_view host_name, string_view service_name, flags f); results_type resolve(string_view host_name, string_view service_name, flags f, error_code& ec); template<class CompletionToken> DEDUCED async_resolve(string_view host_name, string_view service_name, CompletionToken&& token); template<class CompletionToken> DEDUCED async_resolve(string_view host_name, string_view service_name, flags f, CompletionToken&& token); results_type resolve(const protocol_type& protocol, string_view host_name, string_view service_name); results_type resolve(const protocol_type& protocol, string_view host_name, string_view service_name, error_code& ec); results_type resolve(const protocol_type& protocol, string_view host_name, string_view service_name, flags f); results_type resolve(const protocol_type& protocol, string_view host_name, string_view service_name, flags f, error_code& ec); template<class CompletionToken> DEDUCED async_resolve(const protocol_type& protocol, string_view host_name, string_view service_name, CompletionToken&& token); template<class CompletionToken> DEDUCED async_resolve(const protocol_type& protocol, string_view host_name, string_view service_name, flags f, CompletionToken&& token); results_type resolve(const endpoint_type& e); results_type resolve(const endpoint_type& e, error_code& ec); template<class CompletionToken> DEDUCED async_resolve(const endpoint_type& e, CompletionToken&& token); }; } // namespace ip } // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
ip::basic_
resolver
constructors [internet.resolver.cons]explicitresolver(const executor_type& ex);basic_
-1- Postconditions:get_executor() == ex
.
template<class ExecutionContext> explicitresolver(ExecutionContext& ctx);basic_
Postconditions:get_executor() == ctx.get_executor().
Remarks:This function shall not participate in overload resolution unless
is_convertible<ExecutionContext&, execution_context&>::value
is true
and is_constructible<executor_type, typename ExecutionContext::executor_type>::value
is true
.
resolver(basic_
resolver&& rhs) noexcept;basic_
-2- Effects:Move constructs an object of class
that refers to the state originally represented by resolver<InternetProtocolbasic_
, Executor
>rhs
.
-3- Postconditions:get_executor() == rhs.get_executor()
.
ip::basic_
resolver
destructor [internet.resolver.dtor]~resolver();basic_
-1- Effects:Destroys the resolver, canceling all asynchronous operations associated with this resolver as if by calling cancel()
.
ip::basic_
resolver
assignment [internet.resolver.assign]resolver& operator=(basic_
resolver&& rhs);basic_
-1- Effects:Cancels all outstanding asynchronous operations associated with *this
as if by calling cancel()
, then moves into *this
the state originally represented by rhs
.
-2- Postconditions:get_executor() == rhs.get_executor()
.
-3- Returns:*this
.
ip::basic_
resolver
operations [internet.resolver.ops][...]
Assuming the changes in P1322 have been applied, update -21.19- Class ip::tcp
as follows:
namespace std { namespace experimental { namespace net { inline namespace v1 { namespace ip { class tcp { public: // types: using endpoint = basic_endpoint<tcp>;using resolver = basic_resolver<tcp>;template<class Executor> using resolver_for = resolver<tcp, Executor>;using socket = basic_stream_socket<tcp>;template<class Executor> using socket_for =basic_stream_socket<tcp, Executor>;using acceptor = basic_socket_acceptor<tcp>;template<class Executor> using acceptor_for = socket_acceptor<tcp, Executor>; using iostream =basic_socket_iostream<tcp>;
Assuming the changes in P1322 have been applied, update -21.20- Class ip::udp
as follows:
namespace std { namespace experimental { namespace net { inline namespace v1 { namespace ip { class udp { public: // types: using endpoint = basic_endpoint<udp>;using resolver = basic_resolver<udp>;template<class Executor> using resolver_for = resolver<udp, Executor>;using socket = basic_stream_socket<udp>;template<class Executor> using socket_for =basic_datagram_socket<udp, Executor>;
dispatch
, post
, and defer
in terms of the new executors modelModify section -13.22- Function dispatch [async.dispatch] as follows:
-1- [Note: The function dispatch
satisfies the requirements for an asynchronous operation (13.2.7), except for the requirement that the operation uses the post
execution::blocking.never
property if it completes immediately. --end note]
[...]
-3- Effects:
completion
of type async_completion<CompletionToken, void()>
, initialized with token
.ex.dispatch(std::move(completion.completion_handler), alloc)
, where ex
is the result of get_associated_executor(completion.completion_handler)
, and alloc
is the result of get_associated_allocator(completion.completion_handler)
.execution::execute( std::prefer(ex, execution::blocking.possibly, execution::allocator(alloc)), std::move(completion.completion_handler));where
ex
is the result of get_associated_executor(completion.completion_handler)
, and alloc
is the result of get_associated_allocator(completion.completion_handler)
.[...]
-6- Effects:
completion
of type async_completion<CompletionToken, void()>
, initialized with token
.f
containing as members:
w
for the completion handler's associated executor, initialized with std::prefer(get_associated_executor(h), execution::outstanding_work)
,h
, initialized with std::move(completion.completion_handler)
,executor_work_guard
object w
for the completion handler's associated executor, initialized with make_work_guard(h)
,f()
is:
w.get_executor().dispatch(std::move(h), alloc)
, where alloc
is the result of get_associated_allocator(h)
, followed byw.reset()
.execution::execute( std::prefer(w, execution::blocking.possibly, execution::allocator(alloc)), std::move(h));where
alloc
is the result of get_associated_allocator(h)
.ex.dispatch(std::move(f), alloc)
, where alloc
is the result of get_associated_allocator(completion.completion_handler)
prior to the construction of f
.execution::execute( std::prefer(ex, execution::blocking.possibly, execution::allocator(alloc)), std::move(f));
Modify section -13.23- Function post [async.post] as follows:
-3- Effects:
completion
of type async_completion<CompletionToken, void()>
, initialized with token
.ex.post(std::move(completion.completion_handler), alloc)
, where ex
is the result of get_associated_executor(completion.completion_handler)
, and alloc
is the result of get_associated_allocator(completion.completion_handler)
.execution::execute( std::prefer( std::require(ex, execution::blocking.never), execution::relationship.fork, execution::allocator(alloc)), std::move(completion.completion_handler));where
ex
is the result of get_associated_executor(completion.completion_handler)
, and alloc
is the result of get_associated_allocator(completion.completion_handler)
.[...]
-6- Effects:
completion
of type async_completion<CompletionToken, void()>
, initialized with token
.f
containing as members:
w
for the completion handler's associated executor, initialized with std::prefer(get_associated_executor(h), execution::outstanding_work)
,h
, initialized with std::move(completion.completion_handler)
,executor_work_guard
object w
for the completion handler's associated executor, initialized with make_work_guard(h)
,f()
is:
w.get_executor().dispatch(std::move(h), alloc)
, where alloc
is the result of get_associated_allocator(h)
, followed byw.reset()
.execution::execute( std::prefer(w, execution::blocking.possibly, execution::allocator(alloc)), std::move(h));where
alloc
is the result of get_associated_allocator(h)
.ex.dispatch(std::move(f), alloc)
, where alloc
is the result of get_associated_allocator(completion.completion_handler)
prior to the construction of f
.execution::execute( std::prefer( std::require(ex, execution::blocking.never), execution::relationship.fork, execution::allocator(alloc)), std::move(f));
Modify section -13.24- Function defer [async.defer] as follows:
-1- [Note: The function defer
satisfies the requirements for an asynchronous operation (13.2.7), except for the requirement that the operation uses . --end note]post
if it completes immediately
[...]
-3- Effects:
completion
of type async_completion<CompletionToken, void()>
, initialized with token
.ex.defer(std::move(completion.completion_handler), alloc)
, where ex
is the result of get_associated_executor(completion.completion_handler)
, and alloc
is the result of get_associated_allocator(completion.completion_handler)
.execution::execute( std::prefer( std::require(ex, execution::blocking.never), execution::relationship.continuation, execution::allocator(alloc)), std::move(completion.completion_handler));where
ex
is the result of get_associated_executor(completion.completion_handler)
, and alloc
is the result of get_associated_allocator(completion.completion_handler)
.[...]
-6- Effects:
completion
of type async_completion<CompletionToken, void()>
, initialized with token
.f
containing as members:
w
for the completion handler's associated executor, initialized with std::prefer(get_associated_executor(h), execution::outstanding_work)
,h
, initialized with std::move(completion.completion_handler)
,executor_work_guard
object w
for the completion handler's associated executor, initialized with make_work_guard(h)
,f()
is:
w.get_executor().dispatch(std::move(h), alloc)
, where alloc
is the result of get_associated_allocator(h)
, followed byw.reset()
.execution::execute( std::prefer(w, execution::blocking.possibly, execution::allocator(alloc)), std::move(h));where
alloc
is the result of get_associated_allocator(h)
.ex.dispatch(std::move(f), alloc)
, where alloc
is the result of get_associated_allocator(completion.completion_handler)
prior to the construction of f
.execution::execute( std::prefer( std::require(ex, execution::blocking.never), execution::relationship.continuation, execution::allocator(alloc)), std::move(f));
strand
adapter to conform to the new executors modelModify section -13.25- Class template strand [async.strand] as follows:
namespace std { namespace experimental { namespace net { inline namespace v1 { template<class Executor> class strand { public:
[...]
execution_context& context() const noexcept; void on_work_started() const noexcept; void on_work_finished() const noexcept; template<class Func, class ProtoAllocator> void dispatch(Func&& f, const ProtoAllocator& a) const; template<class Func, class ProtoAllocator> void post(Func&& f, const ProtoAllocator& a) const; template<class Func, class ProtoAllocator> void defer(Func&& f, const ProtoAllocator& a) const;template<class Property> see below query(const Property& p) const; template<class Property> see below require(const Property& p) const; template<class Property> see below prefer(const Property& p) const; template<class Function> void execute(Function&& f) const;
[...]
-3- A strand provides guarantees of ordering and non-concurrency. Given:
s1
and s2
such that s1 == s2
f1
s1
post
or defer
, or using dispatch
execution::blocking.never
property is established in s1
, or when s1.running_in_this_thread()
is false
f2
s2
post
or defer
, or using dispatch
execution::blocking.never
property is established in s2
, or when s2.running_in_this_thread()
is false
Modify section -13.25.4- strand operations [async.strand.ops] as follows:
bool running_in_this_thread() const noexcept;
-2- Returns: true
if the current thread of execution is running a function that was submitted to the strand, or to any other strand object that shares the same ordered, non-concurrent state, using s
such that s == *this
, using dispatch
, post
or defer
execute
; otherwise false
. [Note: That is, the current thread of execution's call chain includes a function that was submitted to the strand. --end note]
void on_work_started() const noexcept;
-4- Effects: Calls inner_ex_.on_work_started()
.
void on_work_finished() const noexcept;
-5- Effects: Calls inner_ex_.on_work_finished()
.
template<class Func, class ProtoAllocator> void dispatch(Func&& f, const ProtoAllocator& a) const;
-6- Effects: If running_in_this_thread()
is true, calls DECAY_COPY(forward<Func>(f))()
(C++ 2014 [thread.decaycopy]). [Note: If f
exits via an exception, the exception propagates to the caller of dispatch()
. --end note] 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.
template<class Func, class ProtoAllocator> void post(Func&& f, const ProtoAllocator& a) const;
-7- 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.
-8- 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 Property> see below query(const Property& p) const;
-?- Returns: std::query(inner_ex_, p)
.
-?- Remarks: Shall not participate in overload resolution unless can_query_v<const Executor&, const Property&>
is true
.
template<class Property> see below require(const Property& p) const;
-?- Returns: A strand s
of type strand<decay_t<decltype(std::require(inner_ex_, p))>>
, where s.inner_ex_
is initialized with std::require(inner_ex_, p)
, and sharing the same ordered, non-concurrent state as *this
.
-?- Remarks: Shall not participate in overload resolution unless can_require_v<const Executor&, const Property&>
is true
.
template<class Property> see below prefer(const Property& p) const;
-?- Returns: A strand s
of type strand<decay_t<decltype(std::prefer(inner_ex_, p))>>
, where s.inner_ex_
is initialized with std::prefer(inner_ex_, p)
, and sharing the same ordered, non-concurrent state as *this
.
-?- Remarks: Shall not participate in overload resolution unless can_prefer_v<const Executor&, const Property&>
is true
.
template<class Function> void execute(Function&& f) const;
-?- Effects: Submits f
to the executor inner_ex_
, such that the guarantees of ordering and non-concurrency are met.
use_future
completion token to conform to the new executors modelModify section -13.26.2- use_future_t members [async.use.future.members] as follows:
-8- For any executor type E
, the associated object for the associator associated_executor<H, E>
is an executor where, for function objects executed using the executor's dispatch()
, post()
or defer()
functionsexecute()
function, any exception thrown is caught by a function object and stored in the associated shared state.
Modify section -13.26.3- Partial class template specialization async_result for use_future_t [async.use.future.result] as follows:
-3- The implementation specializes associated_executor
for F
. For function objects executed using the associated executor's dispatch()
, post()
or defer()
functionsexecute()
function, any exception thrown is caught by the executor and stored in the associated shared state.
-4- For any executor type E
, the associated object for the associator associated_executor<F, E>
is an executor where, for function objects executed using the executor's dispatch()
, post()
or defer()
functionsexecute()
function, any exception thrown by a function object is caught by the executor and stored in the associated shared state.
io_context
to conform to the new executors modelModify section -14.2- Class io_context [io_context.io_context] as follows:
namespace std { namespace experimental { namespace net { inline namespace v1 { class io_context : public execution_context { public: // types:class executor_type;using executor_type = see below;
[...]
-1- The class io_context
satisfies the ExecutionContext type requirements (13.2.3).
-?- executor_type
is an executor type conforming to the specification for io_context
executor types described below.
[...]
-4- For an object of type io_context
, outstanding work is defined as the sum of:
on_work_started
function, less the total number of calls to the on_work_finished
function, to any executor of the io_context
.io_context
for which the execution::outstanding_work.tracked
property is established;io_context
via any executor of the io_context
, but not yet executed; andio_context
.[...]
executor_type get_executor() noexcept;
-3- Returns: An executor that may be used for submitting function objects to the io_context
. The returned executor has the following properties already established:
execution::blocking.possibly
execution::relationship.fork
execution::outstanding_work.untracked
execution::mapping.thread
execution::allocator(std::allocator<void>())
-?- io_context
executors having a different set of established properties may be represented by distinct, unspecified types.
[...]
-13- Remarks: This function may invoke additional function objects through nested calls to the io_context
executor's dispatch
execute
member function. These do not count towards the return value.
[...]
-19- Remarks: This function may invoke additional function objects through nested calls to the io_context
executor's dispatch
execute
member function. These do not count towards the return value.
[...]
-25- Remarks: This function may invoke additional function objects through nested calls to the io_context
executor's dispatch
execute
member function. These do not count towards the return value.
Remove section -14.3- Class io_context::executor_type [io_context.exec] in its entirety.
After section -14.2- Class io_context [io_context.io_context] insert a new section as follows:
io_context
executor types-1- Class io-context-executor is for exposition only. It is used to specify a bounded set of types that model execution::executor
(P0443R13). All executor types accessible through io_context::get_executor()
, and subsequent calls to the member function require
, are members of this set and conform to the specification of io-context-executor.
namespace std { namespace experimental { namespace net { inline namespace v1 { class io-context-executor { public: // construct / copy / destroy: io-context-executor(const io-context-executor& other) noexcept; io-context-executor(io-context-executor&& other) noexcept; io-context-executor& operator=(const io-context-executor& other) noexcept; io-context-executor& operator=(io-context-executor&& other) noexcept; // executor operations: see below require(execution::blocking_t::possibly_t) const; see below require(execution::blocking_t::never_t) const; see below require(execution::relationship_t::fork_t) const; see below require(execution::relationship_t::continuation_t) const; see below require(execution::outstanding_work_t::untracked_t) const; see below require(execution::outstanding_work_t::tracked_t) const; see below require(execution::allocator_t<void>) const; template<class ProtoAllocator> see below require(const execution::allocator_t<ProtoAllocator>& a) const; static constexpr execution::mapping_t query(execution::mapping_t) noexcept; io_context& query(execution::context_t) const noexcept; execution::blocking_t query(execution::blocking_t) const noexcept; execution::relationship_t query(execution::relationship_t) const noexcept; execution::outstanding_work_t query(execution::outstanding_work_t) const noexcept; see below query(execution::allocator_t<void>) const noexcept; template<class ProtoAllocator> see below query(const execution::allocator_t<ProtoAllocator>&) const noexcept; bool running_in_this_thread() const noexcept; template<class Function> void execute(Function&& f) const; }; bool operator==(const io-context-executor& a, const io-context-executor& b) noexcept; bool operator!=(const io-context-executor& a, const io-context-executor& b) noexcept; } // inline namespace v1 } // namespace net } // namespace experimental } // namespace std
-2- Objects of type io-context-executor
are associated with an io_context
, and function objects submitted using the execute
member function will be executed by the io_context
from within a run function.
io_context
executor constructorsio-context-executor(const io-context-executor& other) noexcept;
-1- Postconditions: *this == other
.
io-context-executor(io-context-executor&& other) noexcept;
-2- Postconditions: *this
is equal to the prior value of other
.
io_context
executor assignmentio-context-executor& operator=(const io-context-executor& other) noexcept;
-1- Postconditions: *this == other
.
-2- Returns: *this
.
io-context-executor& operator=(io-context-executor&& other) noexcept;
-3- Postconditions: *this
is equal to the prior value of other
.
-4- Returns: *this
.
io_context
executor operationssee below require(execution::blocking_t::possibly_t) const; see below require(execution::blocking_t::never_t) const; see below require(execution::relationship_t::fork_t) const; see below require(execution::relationship_t::continuation_t) const; see below require(execution::outstanding_work_t::untracked_t) const; see below require(execution::outstanding_work_t::tracked_t) const;
-1- Returns: An object of an io-context-executor
class, associated with the same io_context
as *this
, and having the requested property established. When the requested property is part of a group that is defined as a mutually exclusive set, any other properties in the group are removed from the returned executor object. All other properties of the returned executor object are identical to those of *this
.
see below require(execution::allocator_t<void>) const;
-2- Returns: require(execution::allocator(std::allocator<void>()))
.
template<class ProtoAllocator> see below require(const execution::allocator_t<ProtoAllocator>& a) const;
-3- Returns: An object of an io-context-executor
class, associated with the same io_context
as *this
, with the execution::allocator_t<ProtoAllocator>
property established such that allocation and deallocation associated with function submission will be performed using a copy of a.value()
. All other properties of the returned executor object are identical to those of *this
.
static constexpr execution::mapping_t query(execution::execution::mapping_t) noexcept;
-4- Returns: true
.
io_context& query(execution::context_t) const noexcept;
-5- Returns: A reference to the associated io_context
object.
execution::blocking_t query(execution::blocking_t) const noexcept; execution::relationship_t query(execution::relationship_t) const noexcept; execution::outstanding_work_t query(execution::outstanding_work_t) const noexcept;
-6- Returns: The established value of the property for the executor object *this.
see below query(execution::allocator_t<void>) const noexcept; template<class ProtoAllocator> see below query(const execution::allocator_t<ProtoAllocator>&) const noexcept;
-7- Returns: The allocator object associated with the executor, with type and value as previously established by the execution::allocator_t<ProtoAllocator>
property.
bool running_in_this_thread() const noexcept;
-8- Returns: true
if the current thread of execution is calling a run function of the associated io_context
object. [Note: That is, the current thread of execution's call chain includes a run function. --end note]
template<class Function> void execute(Function&& f) const
-9- Effects: Submits the function f
for execution on the io_context
according to the execution::executor
concept and the properties established for *this
. If f
exits via an exception, the exception does not propagate to the caller of execute()
, but is instead subsequently propagated to a caller of a run function for the io_context
object.
io_context
executor comparisonsbool operator==(const io-context-executor& a, const io-context-executor& b) noexcept;
-1- Returns: true
if addressof(a.query(execution::context_t)) == addressof(b.query(execution::context_t))
, and a
and b
have identical properties, otherwise false
.
bool operator!=(const io-context-executor& a, const io-context-executor& b) noexcept;
-2- Returns: !(a == b)
.
The following changes were made in revision 3 of this paper:
Note: changed sections in R3 are indicated by a pale blue background with a dark blue line on the right margin.execution::executor
concept.
system-context-executor
and io-context-executor
.
any_io_executor
type alias and all uses of polymorphic executors.Executor
template parameters.basic_
prefixes from timer, socket, and resolver class templates.The following changes were made in revision 2 of this paper:
std
rather than std::execution
.context()
member function to I/O objects.any_io_executor
.any_io_executor
to the forward declaration header <netfwd>
.any_io_executor
as the default, assuming P1322 changes have been applied.context_as
to context_as_t
, and added template variable context_as
.system_context
executor specification based on implementation experience.io_context
executor specification based on implementation experience.The following changes were made in revision 1 of this paper:
system_context
executors use distinct types when different properties are established.system_context
executors.strand
to conditionally forward static query()
calls to the adapted executor.io_context
executors use distinct types when different properties are established.io_context
executors.execution::context_as<>
property adapter.