Make executors shallow-const.
diff --git a/asio/include/asio/executor.hpp b/asio/include/asio/executor.hpp
index 3efbda6..d1d6fd3 100644
--- a/asio/include/asio/executor.hpp
+++ b/asio/include/asio/executor.hpp
@@ -126,19 +126,19 @@
}
/// Obtain the underlying execution context.
- execution_context& context() ASIO_NOEXCEPT
+ execution_context& context() const ASIO_NOEXCEPT
{
return get_impl()->context();
}
/// Inform the executor that it has some outstanding work to do.
- void on_work_started() ASIO_NOEXCEPT
+ void on_work_started() const ASIO_NOEXCEPT
{
get_impl()->on_work_started();
}
/// Inform the executor that some work is no longer outstanding.
- void on_work_finished() ASIO_NOEXCEPT
+ void on_work_finished() const ASIO_NOEXCEPT
{
get_impl()->on_work_finished();
}
@@ -157,7 +157,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Request the executor to invoke the given function object.
/**
@@ -173,7 +173,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void post(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Request the executor to invoke the given function object.
/**
@@ -189,7 +189,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
struct unspecified_bool_type_t {};
typedef void (*unspecified_bool_type)(unspecified_bool_type_t);
@@ -301,7 +301,7 @@
};
// Helper function to check and return the implementation pointer.
- impl_base* get_impl()
+ impl_base* get_impl() const
{
if (!impl_)
{
diff --git a/asio/include/asio/impl/executor.hpp b/asio/include/asio/impl/executor.hpp
index 8aa9079..7c0766e 100644
--- a/asio/include/asio/impl/executor.hpp
+++ b/asio/include/asio/impl/executor.hpp
@@ -344,7 +344,8 @@
}
template <typename Function, typename Allocator>
-void executor::dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a)
+void executor::dispatch(ASIO_MOVE_ARG(Function) f,
+ const Allocator& a) const
{
impl_base* i = get_impl();
if (i->fast_dispatch_)
@@ -354,13 +355,15 @@
}
template <typename Function, typename Allocator>
-void executor::post(ASIO_MOVE_ARG(Function) f, const Allocator& a)
+void executor::post(ASIO_MOVE_ARG(Function) f,
+ const Allocator& a) const
{
get_impl()->post(function(ASIO_MOVE_CAST(Function)(f), a));
}
template <typename Function, typename Allocator>
-void executor::defer(ASIO_MOVE_ARG(Function) f, const Allocator& a)
+void executor::defer(ASIO_MOVE_ARG(Function) f,
+ const Allocator& a) const
{
get_impl()->defer(function(ASIO_MOVE_CAST(Function)(f), a));
}
diff --git a/asio/include/asio/impl/io_context.hpp b/asio/include/asio/impl/io_context.hpp
index 9045440..b10491f 100644
--- a/asio/include/asio/impl/io_context.hpp
+++ b/asio/include/asio/impl/io_context.hpp
@@ -148,24 +148,26 @@
#endif // !defined(ASIO_NO_DEPRECATED)
inline io_context&
-io_context::executor_type::context() ASIO_NOEXCEPT
+io_context::executor_type::context() const ASIO_NOEXCEPT
{
return io_context_;
}
-inline void io_context::executor_type::on_work_started() ASIO_NOEXCEPT
+inline void
+io_context::executor_type::on_work_started() const ASIO_NOEXCEPT
{
io_context_.impl_.work_started();
}
-inline void io_context::executor_type::on_work_finished() ASIO_NOEXCEPT
+inline void
+io_context::executor_type::on_work_finished() const ASIO_NOEXCEPT
{
io_context_.impl_.work_finished();
}
template <typename Function, typename Allocator>
void io_context::executor_type::dispatch(
- ASIO_MOVE_ARG(Function) f, const Allocator& a)
+ ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
@@ -198,7 +200,7 @@
template <typename Function, typename Allocator>
void io_context::executor_type::post(
- ASIO_MOVE_ARG(Function) f, const Allocator& a)
+ ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
@@ -223,7 +225,7 @@
template <typename Function, typename Allocator>
void io_context::executor_type::defer(
- ASIO_MOVE_ARG(Function) f, const Allocator& a)
+ ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
diff --git a/asio/include/asio/impl/system_executor.hpp b/asio/include/asio/impl/system_executor.hpp
index bcf429b..29f6a0a 100644
--- a/asio/include/asio/impl/system_executor.hpp
+++ b/asio/include/asio/impl/system_executor.hpp
@@ -25,14 +25,14 @@
namespace asio {
-inline execution_context& system_executor::context() ASIO_NOEXCEPT
+inline execution_context& system_executor::context() const ASIO_NOEXCEPT
{
return detail::global<context_impl>();
}
template <typename Function, typename Allocator>
void system_executor::dispatch(
- ASIO_MOVE_ARG(Function) f, const Allocator&)
+ ASIO_MOVE_ARG(Function) f, const Allocator&) const
{
typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f));
asio_handler_invoke_helpers::invoke(tmp, tmp);
@@ -40,7 +40,7 @@
template <typename Function, typename Allocator>
void system_executor::post(
- ASIO_MOVE_ARG(Function) f, const Allocator& a)
+ ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
context_impl& ctx = detail::global<context_impl>();
@@ -66,7 +66,7 @@
template <typename Function, typename Allocator>
void system_executor::defer(
- ASIO_MOVE_ARG(Function) f, const Allocator& a)
+ ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
context_impl& ctx = detail::global<context_impl>();
diff --git a/asio/include/asio/impl/thread_pool.hpp b/asio/include/asio/impl/thread_pool.hpp
index 7e9b6c4..7aeee4e 100644
--- a/asio/include/asio/impl/thread_pool.hpp
+++ b/asio/include/asio/impl/thread_pool.hpp
@@ -32,24 +32,26 @@
}
inline thread_pool&
-thread_pool::executor_type::context() ASIO_NOEXCEPT
+thread_pool::executor_type::context() const ASIO_NOEXCEPT
{
return pool_;
}
-inline void thread_pool::executor_type::on_work_started() ASIO_NOEXCEPT
+inline void
+thread_pool::executor_type::on_work_started() const ASIO_NOEXCEPT
{
pool_.scheduler_.work_started();
}
-inline void thread_pool::executor_type::on_work_finished() ASIO_NOEXCEPT
+inline void thread_pool::executor_type::on_work_finished()
+const ASIO_NOEXCEPT
{
pool_.scheduler_.work_finished();
}
template <typename Function, typename Allocator>
void thread_pool::executor_type::dispatch(
- ASIO_MOVE_ARG(Function) f, const Allocator& a)
+ ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
@@ -82,7 +84,7 @@
template <typename Function, typename Allocator>
void thread_pool::executor_type::post(
- ASIO_MOVE_ARG(Function) f, const Allocator& a)
+ ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
@@ -107,7 +109,7 @@
template <typename Function, typename Allocator>
void thread_pool::executor_type::defer(
- ASIO_MOVE_ARG(Function) f, const Allocator& a)
+ ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
diff --git a/asio/include/asio/io_context.hpp b/asio/include/asio/io_context.hpp
index 7fb49a9..96a0a33 100644
--- a/asio/include/asio/io_context.hpp
+++ b/asio/include/asio/io_context.hpp
@@ -503,7 +503,7 @@
{
public:
/// Obtain the underlying execution context.
- io_context& context() ASIO_NOEXCEPT;
+ io_context& context() const ASIO_NOEXCEPT;
/// Inform the io_context that it has some outstanding work to do.
/**
@@ -511,7 +511,7 @@
* This ensures that the io_context's run() and run_one() functions do not
* exit while the work is underway.
*/
- void on_work_started() ASIO_NOEXCEPT;
+ void on_work_started() const ASIO_NOEXCEPT;
/// Inform the io_context that some work is no longer outstanding.
/**
@@ -519,7 +519,7 @@
* finished. Once the count of unfinished work reaches zero, the io_context
* is stopped and the run() and run_one() functions may exit.
*/
- void on_work_finished() ASIO_NOEXCEPT;
+ void on_work_finished() const ASIO_NOEXCEPT;
/// Request the io_context to invoke the given function object.
/**
@@ -536,7 +536,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Request the io_context to invoke the given function object.
/**
@@ -552,7 +552,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void post(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Request the io_context to invoke the given function object.
/**
@@ -572,7 +572,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Determine whether the io_context is running in the current thread.
/**
diff --git a/asio/include/asio/system_executor.hpp b/asio/include/asio/system_executor.hpp
index 07c7874..e227687 100644
--- a/asio/include/asio/system_executor.hpp
+++ b/asio/include/asio/system_executor.hpp
@@ -36,13 +36,13 @@
{
public:
/// Obtain the underlying execution context.
- execution_context& context() ASIO_NOEXCEPT;
+ execution_context& context() const ASIO_NOEXCEPT;
/// Inform the executor that it has some outstanding work to do.
/**
* For the system executor, this is a no-op.
*/
- void on_work_started() ASIO_NOEXCEPT
+ void on_work_started() const ASIO_NOEXCEPT
{
}
@@ -50,7 +50,7 @@
/**
* For the system executor, this is a no-op.
*/
- void on_work_finished() ASIO_NOEXCEPT
+ void on_work_finished() const ASIO_NOEXCEPT
{
}
@@ -67,7 +67,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Request the system executor to invoke the given function object.
/**
@@ -83,7 +83,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void post(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Request the system executor to invoke the given function object.
/**
@@ -99,7 +99,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Compare two executors for equality.
/**
diff --git a/asio/include/asio/thread_pool.hpp b/asio/include/asio/thread_pool.hpp
index 2a6b460..f3182bf 100644
--- a/asio/include/asio/thread_pool.hpp
+++ b/asio/include/asio/thread_pool.hpp
@@ -83,7 +83,7 @@
{
public:
/// Obtain the underlying execution context.
- thread_pool& context() ASIO_NOEXCEPT;
+ thread_pool& context() const ASIO_NOEXCEPT;
/// Inform the thread pool that it has some outstanding work to do.
/**
@@ -91,7 +91,7 @@
* This ensures that the thread pool's join() function will not return while
* the work is underway.
*/
- void on_work_started() ASIO_NOEXCEPT;
+ void on_work_started() const ASIO_NOEXCEPT;
/// Inform the thread pool that some work is no longer outstanding.
/**
@@ -99,7 +99,7 @@
* finished. Once the count of unfinished work reaches zero, the thread
* pool's join() function is permitted to exit.
*/
- void on_work_finished() ASIO_NOEXCEPT;
+ void on_work_finished() const ASIO_NOEXCEPT;
/// Request the thread pool to invoke the given function object.
/**
@@ -116,7 +116,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Request the thread pool to invoke the given function object.
/**
@@ -132,7 +132,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void post(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Request the thread pool to invoke the given function object.
/**
@@ -152,7 +152,7 @@
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
- void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+ void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Determine whether the thread pool is running in the current thread.
/**
diff --git a/asio/src/doc/requirements/Executor.qbk b/asio/src/doc/requirements/Executor.qbk
index 9be992b..569410c 100644
--- a/asio/src/doc/requirements/Executor.qbk
+++ b/asio/src/doc/requirements/Executor.qbk
@@ -8,25 +8,33 @@
[section:Executor1 Executor requirements]
The library describes a standard set of requirements for ['executors]. A type
-meeting Executor requirements shall embody a set of rules for determining how
+meeting the `Executor` requirements embodies a set of rules for determining how
submitted function objects are to be executed.
-An executor type `X` shall satisfy the requirements of `CopyConstructible` (C++
-Std, [copyconstructible]) types. No constructor, comparison operator, copy
-operation, move operation, swap operation, or member functions `context`,
-`on_work_started` and `on_work_finished` on these types shall exit via an
-exception.
+A type `X` meets the `Executor` requirements if it satisfies the requirements of
+`CopyConstructible` (C++Std [copyconstructible]) and `Destructible` (C++Std
+[destructible]), as well as the additional requirements listed below.
-The executor copy constructor, comparison operators, and member functions
+No constructor, comparison operator, copy operation, move operation, swap
+operation, or member functions `context`, `on_work_started`, and
+`on_work_finished` on these types shall exit via an exception.
+
+The executor copy constructor, comparison operators, and other member functions
defined in these requirements shall not introduce data races as a result of
concurrent calls to those functions from different threads.
-In the table below, `X` denotes an executor class, `x` denotes a value of type
-`X&`, `x1` and `x2` denote values of type `const X&`, `x3` denotes a value of
-type `X&&`, `f` denotes a `MoveConstructible` (C++ Std, [moveconstructible])
-function object callable with zero arguments, `a` denotes a value of type `A`
-meeting `Allocator` requirements (C++ Std, [allocator.requirements]), `t`
-denotes an object of type `T`, and `u` denotes an identifier.
+Let `ctx` be the execution context returned by the executor's `context()`
+member function. An executor becomes ['invalid] when the first call to
+`ctx.shutdown()` returns. The effect of calling `on_work_started`,
+`on_work_finished`, `dispatch`, `post`, or `defer` on an invalid executor is
+undefined. [inline_note The copy constructor, comparison operators, and
+`context()` member function continue to remain valid until `ctx` is destroyed.]
+
+In the table below, `x1` and `x2` denote (possibly const) values of type `X`,
+`mx1` denotes an xvalue of type `X`, `f` denotes a `MoveConstructible` (C++Std
+[moveconstructible]) function object callable with zero arguments, `a` denotes
+a (possibly const) value of type `A` meeting the `Allocator` requirements
+(C++Std [allocator.requirements]), and `u` denotes an identifier.
[table Executor requirements
[[expression] [type] [assertion/note\npre/post-conditions]]
@@ -35,24 +43,25 @@
[]
[Shall not exit via an exception.\n
\n
- post: `u == x1`]
+ post: `u == x1` and
+ `std::addressof(u.context()) == std::addressof(x1.context()).`]
]
[
- [`X u(x3);`]
+ [`X u(mx1);`]
[]
[Shall not exit via an exception.\n
\n
- post: `u` equals the prior value of `x3`.]
+ post: `u` equals the prior value of `mx1` and
+ `std::addressof(u.context())` equals the prior value of
+ `std::addressof(mx1.context())`.]
]
[
[`x1 == x2`]
[`bool`]
- [Shall not exit via an exception.\n
- \n
- Returns `true` only if `x1` and `x2` can be interchanged with identical
+ [ Returns `true` only if `x1` and `x2` can be interchanged with identical
effects in any of the expressions defined in these type requirements.
- Note: `false` does not necessarily imply that the effects are not
- identical.\n
+ [inline_note Returning `false` does not necessarily imply that the effects
+ are not identical.]\n
\n
`operator==` shall be reflexive, symmetric, and transitive, and shall not
exit via an exception.]
@@ -60,71 +69,72 @@
[
[`x1 != x2`]
[`bool`]
+ [Same as `!(x1 == x2)`.]
+ ]
+ [
+ [`x1.context()`]
+ [`execution_context&`, or `E&` where `E` is a type that satifisfies the
+ [link requirements.execution_context `ExecutionContext`] requirements.]
[Shall not exit via an exception.\n
\n
- Same as `!(x1 == x2)`.]
+ The comparison operators and member functions defined in these
+ requirements shall not alter the reference returned by this function.]
]
[
- [`x.context()`]
- [`execution_context&`, or a type that is convertible to `execution_context&`.]
- [Shall not exit via an exception.]
- ]
- [
- [`x.on_work_started()`]
+ [`x1.on_work_started()`]
[]
[Shall not exit via an exception.]
]
[
- [`x.on_work_finished()`]
+ [`x1.on_work_finished()`]
[]
[Shall not exit via an exception.\n
\n
- Requires: A preceding call `x1.on_work_started()` where `x == x1`.]
+ Precondition: A preceding call `x2.on_work_started()` where `x1 == x2`.]
]
[
- [`x.dispatch(std::move(f),a)`]
+ [`x1.dispatch(std::move(f),a)`]
[]
- [Effects: Calls [^['DECAY_COPY]]`(forward<Func>(f))()` at most once. The
- executor may invoke `f` in the current thread, prior to returning from
- `dispatch`. The call to `DECAY_COPY()` is evaluated in the thread that
- called `dispatch`.\n
+ [Effects: Creates an object `f1` initialized with
+ [^['DECAY_COPY]]`(forward<Func>(f))` (C++Std \[thread.decaycopy\]) in the
+ current thread of execution . Calls `f1()` at most once. The executor may
+ block forward progress of the caller until `f1()` finishes execution.\n
\n
- Executor implementations are encouraged to use the supplied allocator to
- allocate any memory required to store the function object. The executor
- shall deallocate all memory prior to invoking the function object.\n
+ Executor implementations should use the supplied allocator to allocate any
+ memory required to store the function object. Prior to invoking the
+ function object, the executor shall deallocate any memory allocated.
+ [inline_note Executors defined in this Technical Specification always use
+ the supplied allocator unless otherwise specified.]\n
\n
- Synchronization: The invocation of `dispatch` synchronizes with (C++ Std,
- \[intro.multithread\]) the invocation of `f`.]
+ Synchronization: The invocation of `dispatch` synchronizes with (C++Std
+ \[intro.multithread\]) the invocation of `f1`.]
]
[
- [`x.post(std::move(f),a)`]
+ [`x1.post(std::move(f),a)`\n
+ `x1.defer(std::move(f),a)`]
[]
- [Effects: Calls [^['DECAY_COPY]]`(forward<Func>(f))()` at most once. The
- executor may not invoke `f` in the current thread, prior to returning from
- `post`. The call to `DECAY_COPY()` is evaluated in the thread that called
- `post`.\n
+ [Effects: Creates an object `f1` initialized with
+ [^['DECAY_COPY]]`(forward<Func>(f))` in the current thread of execution.
+ Calls `f1()` at most once. The executor shall not block forward progress
+ of the caller pending completion of `f1()`.\n
\n
- Executor implementations are encouraged to use the supplied allocator to
- allocate any memory required to store the function object. The executor
- shall deallocate all memory prior to invoking the function object.\n
+ Executor implementations should use the supplied allocator to allocate any
+ memory required to store the function object. Prior to invoking the
+ function object, the executor shall deallocate any memory allocated.
+ [inline_note Executors defined in this Technical Specification always use
+ the supplied allocator unless otherwise specified.]\n
\n
- Synchronization: The invocation of `post` synchronizes with (C++ Std,
- \[intro.multithread\]) the invocation of `f`.]
- ]
- [
- [`x.defer(std::move(f),a)`]
- []
- [Effects: Calls [^['DECAY_COPY]]`(forward<Func>(f))()` at most once. The
- executor may not invoke `f` in the current thread, prior to returning from
- `defer`. The call to `DECAY_COPY()` is evaluated in the thread that called
- `defer`.\n
+ Synchronization: The invocation of `post` or `defer` synchronizes with
+ (C++Std \[intro.multithread\]) the invocation of `f1`.\n
\n
- Executor implementations are encouraged to use the supplied allocator to
- allocate any memory required to store the function object. The executor
- shall deallocate all memory prior to invoking the function object.\n
- \n
- Synchronization: The invocation of `defer` synchronizes with (C++ Std,
- \[intro.multithread\]) the invocation of `f`.]
+ [inline_note Although the requirements placed on `defer` are identical to
+ `post`, the use of `post` conveys a preference that the caller ['does not]
+ block the first step of [^f1]'s progress, whereas `defer` conveys a
+ preference that the caller ['does] block the first step of [^f1]. One use
+ of `defer` is to convey the intention of the caller that [^f1] is a
+ continuation of the current call context. The executor may use this
+ information to optimize or otherwise adjust the way in which `f1` is
+ invoked.]]
]
]