From 2f327be5fed7b19d8c027fbcbba3a8b883edfa16 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:37:47 +1000 Subject: [PATCH 01/90] Linearise gather-write buffer sequences in ssl::stream. --- .../asio/detail/buffer_sequence_adapter.hpp | 92 +++++++++++++++++++ include/boost/asio/ssl/detail/write_op.hpp | 6 +- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/include/boost/asio/detail/buffer_sequence_adapter.hpp b/include/boost/asio/detail/buffer_sequence_adapter.hpp index f0aa0013..fba5fb57 100644 --- a/include/boost/asio/detail/buffer_sequence_adapter.hpp +++ b/include/boost/asio/detail/buffer_sequence_adapter.hpp @@ -154,6 +154,16 @@ public: boost::asio::buffer_sequence_end(buffer_sequence)); } + enum { linearisation_storage_size = 8192 }; + + static Buffer linearise(const Buffers& buffer_sequence, + const boost::asio::mutable_buffer& storage) + { + return buffer_sequence_adapter::linearise( + boost::asio::buffer_sequence_begin(buffer_sequence), + boost::asio::buffer_sequence_end(buffer_sequence), storage); + } + private: template void init(Iterator begin, Iterator end) @@ -202,6 +212,30 @@ private: return Buffer(); } + template + static Buffer linearise(Iterator begin, Iterator end, + const boost::asio::mutable_buffer& storage) + { + boost::asio::mutable_buffer unused_storage = storage; + Iterator iter = begin; + while (iter != end && unused_storage.size() != 0) + { + Buffer buffer(*iter); + ++iter; + if (buffer.size() == 0) + continue; + if (unused_storage.size() == storage.size()) + { + if (iter == end) + return buffer; + if (buffer.size() >= unused_storage.size()) + return buffer; + } + unused_storage += boost::asio::buffer_copy(unused_storage, buffer); + } + return Buffer(storage.data(), storage.size() - unused_storage.size()); + } + native_buffer_type buffers_[max_buffers]; std::size_t count_; std::size_t total_buffer_size_; @@ -254,6 +288,14 @@ public: return Buffer(buffer_sequence); } + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const boost::asio::mutable_buffer& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + private: native_buffer_type buffer_; std::size_t total_buffer_size_; @@ -306,6 +348,14 @@ public: return Buffer(buffer_sequence); } + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const boost::asio::const_buffer& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + private: native_buffer_type buffer_; std::size_t total_buffer_size_; @@ -360,6 +410,14 @@ public: return Buffer(buffer_sequence); } + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const boost::asio::mutable_buffers_1& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + private: native_buffer_type buffer_; std::size_t total_buffer_size_; @@ -412,6 +470,14 @@ public: return Buffer(buffer_sequence); } + enum { linearisation_storage_size = 1 }; + + static Buffer linearise(const boost::asio::const_buffers_1& buffer_sequence, + const Buffer&) + { + return Buffer(buffer_sequence); + } + private: native_buffer_type buffer_; std::size_t total_buffer_size_; @@ -469,6 +535,19 @@ public: ? buffer_sequence[0] : buffer_sequence[1]); } + enum { linearisation_storage_size = 8192 }; + + static Buffer linearise(const boost::array& buffer_sequence, + const boost::asio::mutable_buffer& storage) + { + if (buffer_sequence[0].size() == 0) + return Buffer(buffer_sequence[1]); + if (buffer_sequence[1].size() == 0) + return Buffer(buffer_sequence[0]); + return Buffer(storage.data(), + boost::asio::buffer_copy(storage, buffer_sequence)); + } + private: native_buffer_type buffers_[2]; std::size_t total_buffer_size_; @@ -526,6 +605,19 @@ public: ? buffer_sequence[0] : buffer_sequence[1]); } + enum { linearisation_storage_size = 8192 }; + + static Buffer linearise(const std::array& buffer_sequence, + const boost::asio::mutable_buffer& storage) + { + if (buffer_sequence[0].size() == 0) + return Buffer(buffer_sequence[1]); + if (buffer_sequence[1].size() == 0) + return Buffer(buffer_sequence[0]); + return Buffer(storage.data(), + boost::asio::buffer_copy(storage, buffer_sequence)); + } + private: native_buffer_type buffers_[2]; std::size_t total_buffer_size_; diff --git a/include/boost/asio/ssl/detail/write_op.hpp b/include/boost/asio/ssl/detail/write_op.hpp index f76b662a..204fe205 100644 --- a/include/boost/asio/ssl/detail/write_op.hpp +++ b/include/boost/asio/ssl/detail/write_op.hpp @@ -40,9 +40,13 @@ public: boost::system::error_code& ec, std::size_t& bytes_transferred) const { + unsigned char storage[ + boost::asio::detail::buffer_sequence_adapter::linearisation_storage_size]; + boost::asio::const_buffer buffer = boost::asio::detail::buffer_sequence_adapter::first(buffers_); + ConstBufferSequence>::linearise(buffers_, boost::asio::buffer(storage)); return eng.write(buffer, ec, bytes_transferred); } From 1cebe7c5b3c6a8fefbe9c9634315b682676595f3 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:40:13 +1000 Subject: [PATCH 02/90] Add missing nested type '::type' when computing signature. --- include/boost/asio/impl/co_spawn.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/asio/impl/co_spawn.hpp b/include/boost/asio/impl/co_spawn.hpp index 2d71969e..4eb4e00b 100644 --- a/include/boost/asio/impl/co_spawn.hpp +++ b/include/boost/asio/impl/co_spawn.hpp @@ -134,7 +134,7 @@ co_spawn(const Executor& ex, F&& f, CompletionToken&& token, >::type*) { return async_initiate::type>>( + typename detail::awaitable_signature::type>::type>( detail::initiate_co_spawn< typename result_of::type::executor_type>(ex), token, std::forward(f)); From 56aaf6156b9c935ad051077ad0406027b31cbbaf Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:42:56 +1000 Subject: [PATCH 03/90] Add move constructor to ssl::stream<>. --- example/cpp11/ssl/server.cpp | 8 ++-- include/boost/asio/ssl/detail/engine.hpp | 5 +++ include/boost/asio/ssl/detail/impl/engine.ipp | 19 ++++++++-- include/boost/asio/ssl/detail/stream_core.hpp | 38 ++++++++++++++++++- include/boost/asio/ssl/stream.hpp | 15 ++++++++ test/ssl/stream.cpp | 10 ++++- 6 files changed, 85 insertions(+), 10 deletions(-) diff --git a/example/cpp11/ssl/server.cpp b/example/cpp11/ssl/server.cpp index 32936a67..ce7ee9f0 100644 --- a/example/cpp11/ssl/server.cpp +++ b/example/cpp11/ssl/server.cpp @@ -19,8 +19,8 @@ using boost::asio::ip::tcp; class session : public std::enable_shared_from_this { public: - session(tcp::socket socket, boost::asio::ssl::context& context) - : socket_(std::move(socket), context) + session(boost::asio::ssl::stream socket) + : socket_(std::move(socket)) { } @@ -106,7 +106,9 @@ private: { if (!error) { - std::make_shared(std::move(socket), context_)->start(); + std::make_shared( + boost::asio::ssl::stream( + std::move(socket), context_))->start(); } do_accept(); diff --git a/include/boost/asio/ssl/detail/engine.hpp b/include/boost/asio/ssl/detail/engine.hpp index f3c4407a..d84fad97 100644 --- a/include/boost/asio/ssl/detail/engine.hpp +++ b/include/boost/asio/ssl/detail/engine.hpp @@ -59,6 +59,11 @@ public: // Construct a new engine for the specified context. BOOST_ASIO_DECL explicit engine(SSL_CTX* context); +#if defined(BOOST_ASIO_HAS_MOVE) + // Move construct from another engine. + BOOST_ASIO_DECL engine(engine&& other) BOOST_ASIO_NOEXCEPT; +#endif // defined(BOOST_ASIO_HAS_MOVE) + // Destructor. BOOST_ASIO_DECL ~engine(); diff --git a/include/boost/asio/ssl/detail/impl/engine.ipp b/include/boost/asio/ssl/detail/impl/engine.ipp index cba7e516..c377ab76 100644 --- a/include/boost/asio/ssl/detail/impl/engine.ipp +++ b/include/boost/asio/ssl/detail/impl/engine.ipp @@ -56,16 +56,29 @@ engine::engine(SSL_CTX* context) ::SSL_set_bio(ssl_, int_bio, int_bio); } +#if defined(BOOST_ASIO_HAS_MOVE) +engine::engine(engine&& other) BOOST_ASIO_NOEXCEPT + : ssl_(other.ssl_), + ext_bio_(other.ext_bio_) +{ + other.ssl_ = 0; + other.ext_bio_ = 0; +} +#endif // defined(BOOST_ASIO_HAS_MOVE) + engine::~engine() { - if (SSL_get_app_data(ssl_)) + if (ssl_ && SSL_get_app_data(ssl_)) { delete static_cast(SSL_get_app_data(ssl_)); SSL_set_app_data(ssl_, 0); } - ::BIO_free(ext_bio_); - ::SSL_free(ssl_); + if (ext_bio_) + ::BIO_free(ext_bio_); + + if (ssl_) + ::SSL_free(ssl_); } SSL* engine::native_handle() diff --git a/include/boost/asio/ssl/detail/stream_core.hpp b/include/boost/asio/ssl/detail/stream_core.hpp index b32c682f..88bad784 100644 --- a/include/boost/asio/ssl/detail/stream_core.hpp +++ b/include/boost/asio/ssl/detail/stream_core.hpp @@ -52,6 +52,40 @@ struct stream_core pending_write_.expires_at(neg_infin()); } +#if defined(BOOST_ASIO_HAS_MOVE) + stream_core(stream_core&& other) + : engine_(BOOST_ASIO_MOVE_CAST(engine)(other.engine_)), +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + pending_read_( + BOOST_ASIO_MOVE_CAST(boost::asio::deadline_timer)( + other.pending_read_)), + pending_write_( + BOOST_ASIO_MOVE_CAST(boost::asio::deadline_timer)( + other.pending_write_)), +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + pending_read_( + BOOST_ASIO_MOVE_CAST(boost::asio::steady_timer)( + other.pending_read_)), + pending_write_( + BOOST_ASIO_MOVE_CAST(boost::asio::steady_timer)( + other.pending_write_)), +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + output_buffer_space_( + BOOST_ASIO_MOVE_CAST(std::vector)( + other.output_buffer_space_)), + output_buffer_(other.output_buffer_), + input_buffer_space_( + BOOST_ASIO_MOVE_CAST(std::vector)( + other.input_buffer_space_)), + input_buffer_(other.input_buffer_), + input_(other.input_) + { + other.output_buffer_ = boost::asio::mutable_buffer(0, 0); + other.input_buffer_ = boost::asio::mutable_buffer(0, 0); + other.input_ = boost::asio::const_buffer(0, 0); + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + ~stream_core() { } @@ -115,13 +149,13 @@ struct stream_core std::vector output_buffer_space_; // A buffer that may be used to prepare output intended for the transport. - const boost::asio::mutable_buffer output_buffer_; + boost::asio::mutable_buffer output_buffer_; // Buffer space used to read input intended for the engine. std::vector input_buffer_space_; // A buffer that may be used to read input intended for the engine. - const boost::asio::mutable_buffer input_buffer_; + boost::asio::mutable_buffer input_buffer_; // The buffer pointing to the engine's unconsumed input. boost::asio::const_buffer input_; diff --git a/include/boost/asio/ssl/stream.hpp b/include/boost/asio/ssl/stream.hpp index 3d64ffb8..cc157b89 100644 --- a/include/boost/asio/ssl/stream.hpp +++ b/include/boost/asio/ssl/stream.hpp @@ -110,6 +110,21 @@ public: } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a stream from another. + /** + * @param other The other stream object from which the move will occur. Must + * have no outstanding asynchronous operations associated with it. Following + * the move, @c other has a valid but unspecified state where the only safe + * operation is destruction. + */ + stream(stream&& other) + : next_layer_(BOOST_ASIO_MOVE_CAST(Stream)(other.next_layer_)), + core_(BOOST_ASIO_MOVE_CAST(detail::stream_core)(other.core_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Destructor. /** * @note A @c stream object must not be destroyed while there are pending diff --git a/test/ssl/stream.cpp b/test/ssl/stream.cpp index 007dd5f4..24f86acf 100644 --- a/test/ssl/stream.cpp +++ b/test/ssl/stream.cpp @@ -75,6 +75,12 @@ void test() ip::tcp::socket socket1(ioc, ip::tcp::v4()); ssl::stream stream2(socket1, context); +#if defined(BOOST_ASIO_HAS_MOVE) + ssl::stream stream3 + = ssl::stream(ioc, context); + ssl::stream stream4(std::move(stream3)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + // basic_io_object functions. ssl::stream::executor_type ex = stream1.get_executor(); @@ -89,9 +95,9 @@ void test() = stream1.lowest_layer(); (void)lowest_layer; - const ssl::stream& stream3 = stream1; + const ssl::stream& stream5 = stream1; const ssl::stream::lowest_layer_type& lowest_layer2 - = stream3.lowest_layer(); + = stream5.lowest_layer(); (void)lowest_layer2; stream1.set_verify_mode(ssl::verify_none); From 4d3e0453e8681dfe4bd67b6f0a11ee8e070a8f7d Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:45:09 +1000 Subject: [PATCH 04/90] Fix async_compose so that it works with copyable handlers passed as an lvalue. --- include/boost/asio/impl/compose.hpp | 13 +++--- test/compose.cpp | 61 ++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/include/boost/asio/impl/compose.hpp b/include/boost/asio/impl/compose.hpp index 3c329f03..53b8b37a 100644 --- a/include/boost/asio/impl/compose.hpp +++ b/include/boost/asio/impl/compose.hpp @@ -249,12 +249,13 @@ namespace detail #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) { public: - composed_op(BOOST_ASIO_MOVE_ARG(Impl) impl, - BOOST_ASIO_MOVE_ARG(Work) work, - BOOST_ASIO_MOVE_ARG(Handler) handler) - : impl_(BOOST_ASIO_MOVE_CAST(Impl)(impl)), - work_(BOOST_ASIO_MOVE_CAST(Work)(work)), - handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + template + composed_op(BOOST_ASIO_MOVE_ARG(I) impl, + BOOST_ASIO_MOVE_ARG(W) work, + BOOST_ASIO_MOVE_ARG(H) handler) + : impl_(BOOST_ASIO_MOVE_CAST(I)(impl)), + work_(BOOST_ASIO_MOVE_CAST(W)(work)), + handler_(BOOST_ASIO_MOVE_CAST(H)(handler)), invocations_(0) { } diff --git a/test/compose.cpp b/test/compose.cpp index 3255ef82..8282b10c 100644 --- a/test/compose.cpp +++ b/test/compose.cpp @@ -74,6 +74,16 @@ void compose_0_args_handler(int* count) ++(*count); } +struct compose_0_args_lvalue_handler +{ + int* count_; + + void operator()() + { + ++(*count_); + } +}; + void compose_0_completion_args_test() { #if defined(BOOST_ASIO_HAS_BOOST_BIND) @@ -96,6 +106,22 @@ void compose_0_completion_args_test() // The run() call will not return until all work has finished. BOOST_ASIO_CHECK(ioc.stopped()); BOOST_ASIO_CHECK(count == 1); + + ioc.restart(); + count = 0; + + compose_0_args_lvalue_handler lvalue_handler = { &count }; + async_0_completion_args(ioc, lvalue_handler); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); } //------------------------------------------------------------------------------ @@ -140,12 +166,24 @@ async_1_completion_arg(boost::asio::io_context& ioc, impl_1_completion_arg(ioc), token); } -void compose_1_args_handler(int* count, int* result_out, int result) +void compose_1_arg_handler(int* count, int* result_out, int result) { ++(*count); *result_out = result; } +struct compose_1_arg_lvalue_handler +{ + int* count_; + int* result_out_; + + void operator()(int result) + { + ++(*count_); + *result_out_ = result; + } +}; + void compose_1_completion_arg_test() { #if defined(BOOST_ASIO_HAS_BOOST_BIND) @@ -160,7 +198,26 @@ void compose_1_completion_arg_test() int result = 0; async_1_completion_arg(ioc, - bindns::bind(&compose_1_args_handler, &count, &result, _1)); + bindns::bind(&compose_1_arg_handler, &count, &result, _1)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + BOOST_ASIO_CHECK(result == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + BOOST_ASIO_CHECK(result == 42); + + ioc.restart(); + count = 0; + result = 0; + + compose_1_arg_lvalue_handler lvalue_handler = { &count, &result }; + async_1_completion_arg(ioc, lvalue_handler); // No handlers can be called until run() is called. BOOST_ASIO_CHECK(!ioc.stopped()); From 84ee50a2d8c0b4bc10c8364ea97f3dc0f77f2bf2 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:45:30 +1000 Subject: [PATCH 05/90] Enable C++20 coroutine support for gcc 10. --- include/boost/asio/awaitable.hpp | 12 ++++++++- include/boost/asio/detail/config.hpp | 35 +++++++++++++++++++++------ include/boost/asio/impl/awaitable.hpp | 16 ++++++++++++ 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/include/boost/asio/awaitable.hpp b/include/boost/asio/awaitable.hpp index 6bf14569..9578bc42 100644 --- a/include/boost/asio/awaitable.hpp +++ b/include/boost/asio/awaitable.hpp @@ -19,7 +19,12 @@ #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) -#include +#if defined(BOOST_ASIO_HAS_STD_COROUTINE) +# include +#else // defined(BOOST_ASIO_HAS_STD_COROUTINE) +# include +#endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) + #include #include @@ -28,8 +33,13 @@ namespace boost { namespace asio { namespace detail { +#if defined(BOOST_ASIO_HAS_STD_COROUTINE) +using std::coroutine_handle; +using std::suspend_always; +#else // defined(BOOST_ASIO_HAS_STD_COROUTINE) using std::experimental::coroutine_handle; using std::experimental::suspend_always; +#endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) template class awaitable_thread; template class awaitable_frame; diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp index d48528a4..c8e69ea0 100644 --- a/include/boost/asio/detail/config.hpp +++ b/include/boost/asio/detail/config.hpp @@ -1460,7 +1460,7 @@ # define BOOST_ASIO_UNUSED_VARIABLE #endif // !defined(BOOST_ASIO_UNUSED_VARIABLE) -// Support co_await on compilers known to allow it. +// Support the co_await keyword on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_CO_AWAIT) # if !defined(BOOST_ASIO_DISABLE_CO_AWAIT) # if defined(BOOST_ASIO_MSVC) @@ -1470,14 +1470,33 @@ # endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED) # endif // (_MSC_FULL_VER >= 190023506) # endif // defined(BOOST_ASIO_MSVC) +# if defined(__clang__) +# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) # endif // !defined(BOOST_ASIO_DISABLE_CO_AWAIT) -# if defined(__clang__) -# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) -# if __has_include() -# define BOOST_ASIO_HAS_CO_AWAIT 1 -# endif // __has_include() -# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) -# endif // defined(__clang__) #endif // !defined(BOOST_ASIO_HAS_CO_AWAIT) +// Standard library support for coroutines. +#if !defined(BOOST_ASIO_HAS_STD_COROUTINE) +# if !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) +# if defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) +#endif // !defined(BOOST_ASIO_HAS_STD_COROUTINE) + #endif // BOOST_ASIO_DETAIL_CONFIG_HPP diff --git a/include/boost/asio/impl/awaitable.hpp b/include/boost/asio/impl/awaitable.hpp index 088d03d1..6f67e608 100644 --- a/include/boost/asio/impl/awaitable.hpp +++ b/include/boost/asio/impl/awaitable.hpp @@ -406,6 +406,21 @@ protected: } // namespace boost #if !defined(GENERATING_DOCUMENTATION) +# if defined(BOOST_ASIO_HAS_STD_COROUTINE) + +namespace boost { +namespace system { + +template +struct coroutine_traits, Args...> +{ + typedef boost::asio::detail::awaitable_frame promise_type; +}; + +} // namespace system +} // namespace boost + +# else // defined(BOOST_ASIO_HAS_STD_COROUTINE) namespace std { namespace experimental { @@ -417,6 +432,7 @@ struct coroutine_traits, Args...> }} // namespace std::experimental +# endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) #endif // !defined(GENERATING_DOCUMENTATION) #include From cb60b08ff52287f0ac665443326385bb722c3549 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:46:29 +1000 Subject: [PATCH 06/90] Add source location support to handler tracking. The BOOST_ASIO_HANDLER_LOCATION((file_name, line, function_name)) macro may be used to inform the handler tracking mechanism of a source location. This macro declares an object that is placed on the stack. When an asynchronous operation is launched with location information, it outputs lines using the 'n^m', prior to the 'n*m' line that signifies the beginning of the asynchronous operation. For example: @asio|1589423304.861944|>7|ec=system:0,bytes_transferred=5 @asio|1589423304.861952|7^8|in 'async_write' (./../../../include/asio/impl/write.hpp:330) @asio|1589423304.861952|7^8|called from 'do_write' (handler_tracking/async_tcp_echo_server.cpp:62) @asio|1589423304.861952|7^8|called from 'operator()' (handler_tracking/async_tcp_echo_server.cpp:51) @asio|1589423304.861952|7*8|socket@0x7ff61c008230.async_send @asio|1589423304.861975|.8|non_blocking_send,ec=system:0,bytes_transferred=5 @asio|1589423304.861980|<7| If std::source_location or std::experimental::source_location are available, the use_awaitable_t token (when default-constructed or used as a default completion token) will also cause handler tracking to output a source location for each newly created asynchronous operation. A use_awaitable_t object may also be explicitly constructed with location information. --- doc/examples.qbk | 7 +- doc/overview/handler_tracking.qbk | 113 ++++++++++++++---- .../async_tcp_echo_server.cpp | 21 ++++ .../handler_tracking/custom_tracking.hpp | 10 ++ example/cpp17/coroutines_ts/echo_server.cpp | 5 + include/boost/asio/detail/config.hpp | 31 +++++ .../boost/asio/detail/handler_tracking.hpp | 26 ++++ .../asio/detail/impl/handler_tracking.ipp | 40 ++++++- include/boost/asio/detail/source_location.hpp | 47 ++++++++ include/boost/asio/impl/co_spawn.hpp | 2 +- include/boost/asio/impl/connect.hpp | 4 + include/boost/asio/impl/read.hpp | 21 +++- include/boost/asio/impl/read_at.hpp | 18 ++- include/boost/asio/impl/read_until.hpp | 64 +++++++--- include/boost/asio/impl/use_awaitable.hpp | 5 +- include/boost/asio/impl/write.hpp | 8 +- include/boost/asio/impl/write_at.hpp | 9 +- .../asio/ssl/detail/buffered_handshake_op.hpp | 5 + .../boost/asio/ssl/detail/handshake_op.hpp | 5 + include/boost/asio/ssl/detail/io.hpp | 16 +++ include/boost/asio/ssl/detail/read_op.hpp | 5 + include/boost/asio/ssl/detail/shutdown_op.hpp | 5 + include/boost/asio/ssl/detail/write_op.hpp | 5 + include/boost/asio/use_awaitable.hpp | 54 ++++++++- 24 files changed, 460 insertions(+), 66 deletions(-) create mode 100644 include/boost/asio/detail/source_location.hpp diff --git a/doc/examples.qbk b/doc/examples.qbk index aafc1721..c238f80c 100644 --- a/doc/examples.qbk +++ b/doc/examples.qbk @@ -398,10 +398,15 @@ Boost.Asio's asynchronous operations. [heading Handler Tracking] -This example shows how to implement custom handler tracking. +This example header file shows how to implement custom handler tracking. * [@boost_asio/example/cpp11/handler_tracking/custom_tracking.hpp] +This example program shows how to include source location information in +the handler tracking output. + +* [@boost_asio/example/cpp11/handler_tracking/async_tcp_echo_server.cpp] + [heading HTTP Server] diff --git a/doc/overview/handler_tracking.qbk b/doc/overview/handler_tracking.qbk index fad1ef59..5cb34ce9 100644 --- a/doc/overview/handler_tracking.qbk +++ b/doc/overview/handler_tracking.qbk @@ -18,30 +18,31 @@ asynchronous operations are chained together, or what the pending asynchronous operations are. As an illustration, here is the output when you run the HTTP Server example, handle a single request, then shut down via Ctrl+C: - @asio|1512254357.979980|0*1|signal_set@0x7ffeaaaa20d8.async_wait - @asio|1512254357.980127|0*2|socket@0x7ffeaaaa20f8.async_accept - @asio|1512254357.980150|.2|non_blocking_accept,ec=asio.system:11 - @asio|1512254357.980162|0|resolver@0x7ffeaaaa1fd8.cancel - @asio|1512254368.457147|.2|non_blocking_accept,ec=system:0 - @asio|1512254368.457193|>2|ec=system:0 - @asio|1512254368.457219|2*3|socket@0x55cf39f0a238.async_receive - @asio|1512254368.457244|.3|non_blocking_recv,ec=system:0,bytes_transferred=141 - @asio|1512254368.457275|2*4|socket@0x7ffeaaaa20f8.async_accept - @asio|1512254368.457293|.4|non_blocking_accept,ec=asio.system:11 - @asio|1512254368.457301|<2| - @asio|1512254368.457310|>3|ec=system:0,bytes_transferred=141 - @asio|1512254368.457441|3*5|socket@0x55cf39f0a238.async_send - @asio|1512254368.457502|.5|non_blocking_send,ec=system:0,bytes_transferred=156 - @asio|1512254368.457511|<3| - @asio|1512254368.457519|>5|ec=system:0,bytes_transferred=156 - @asio|1512254368.457544|5|socket@0x55cf39f0a238.close - @asio|1512254368.457559|<5| - @asio|1512254371.385106|>1|ec=system:0,signal_number=2 - @asio|1512254371.385130|1|socket@0x7ffeaaaa20f8.close - @asio|1512254371.385163|<1| - @asio|1512254371.385175|>4|ec=asio.system:125 - @asio|1512254371.385182|<4| - @asio|1512254371.385202|0|signal_set@0x7ffeaaaa20d8.cancel + @asio|1589424178.741850|0*1|signal_set@0x7ffee977d878.async_wait + @asio|1589424178.742593|0*2|socket@0x7ffee977d8a8.async_accept + @asio|1589424178.742619|.2|non_blocking_accept,ec=asio.system:11 + @asio|1589424178.742625|0|resolver@0x7ffee977d760.cancel + @asio|1589424195.830382|.2|non_blocking_accept,ec=system:0 + @asio|1589424195.830413|>2|ec=system:0 + @asio|1589424195.830473|2*3|socket@0x7fa71d808230.async_receive + @asio|1589424195.830496|.3|non_blocking_recv,ec=system:0,bytes_transferred=151 + @asio|1589424195.830503|2*4|socket@0x7ffee977d8a8.async_accept + @asio|1589424195.830507|.4|non_blocking_accept,ec=asio.system:11 + @asio|1589424195.830510|<2| + @asio|1589424195.830529|>3|ec=system:0,bytes_transferred=151 + @asio|1589424195.831143|3^5|in 'async_write' (./../../../boost/asio/impl/write.hpp:330) + @asio|1589424195.831143|3*5|socket@0x7fa71d808230.async_send + @asio|1589424195.831186|.5|non_blocking_send,ec=system:0,bytes_transferred=1090 + @asio|1589424195.831194|<3| + @asio|1589424195.831218|>5|ec=system:0,bytes_transferred=1090 + @asio|1589424195.831263|5|socket@0x7fa71d808230.close + @asio|1589424195.831298|<5| + @asio|1589424199.793770|>1|ec=system:0,signal_number=2 + @asio|1589424199.793781|1|socket@0x7ffee977d8a8.close + @asio|1589424199.793809|<1| + @asio|1589424199.793840|>4|ec=asio.system:125 + @asio|1589424199.793854|<4| + @asio|1589424199.793883|0|signal_set@0x7ffee977d878.cancel Each line is of the form: @@ -74,6 +75,13 @@ The `` takes one of the following forms: usually the case for any unfinished asynchronous operations when the `io_context` is destroyed.] ] + [ + [n^m] + [The handler number `n` is about to create a new asynchronous operation with + completion handler number `m`. The `` contains source location + information to help identify where in the program the asynchronous operation + is being started.] + ] [ [n*m] [The handler number `n` created a new asynchronous operation with completion @@ -105,6 +113,53 @@ As shown above, Each handler is assigned a numeric identifier. Where the handler tracking output shows a handler number of 0, it means that the action was performed outside of any handler. +[heading Adding Location Information] + +[c++] +Programs may augment the handler tracking output's location information by +using the macro `BOOST_ASIO_HANDLER_LOCATION` in the source code. For example: + + #define HANDLER_LOCATION \ + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, __func__)) + + // ... + + void do_read() + { + HANDLER_LOCATION; + + auto self(shared_from_this()); + socket_.async_read_some(boost::asio::buffer(data_, max_length), + [this, self](boost::system::error_code ec, std::size_t length) + { + HANDLER_LOCATION; + + if (!ec) + { + do_write(length); + } + }); + } + +[teletype] +With the additional location information available, the handler tracking output +may include a call stack of source locations: + + @asio|1589423304.861944|>7|ec=system:0,bytes_transferred=5 + @asio|1589423304.861952|7^8|in 'async_write' (./../../../boost/asio/impl/write.hpp:330) + @asio|1589423304.861952|7^8|called from 'do_write' (handler_tracking/async_tcp_echo_server.cpp:62) + @asio|1589423304.861952|7^8|called from 'operator()' (handler_tracking/async_tcp_echo_server.cpp:51) + @asio|1589423304.861952|7*8|socket@0x7ff61c008230.async_send + @asio|1589423304.861975|.8|non_blocking_send,ec=system:0,bytes_transferred=5 + @asio|1589423304.861980|<7| + +Furthermore, if `std::source_location` or `std::experimental::source_location` +are available, the [link boost_asio.reference.use_awaitable_t `use_awaitable_t`] +token (when default-constructed or used as a default completion token) will +also cause handler tracking to output a source location for each newly created +asynchronous operation. A `use_awaitable_t` object may also be explicitly +constructed with location information. + [heading Visual Representations] The handler tracking output may be post-processed using the included @@ -137,6 +192,12 @@ preprocessor macros: [`BOOST_ASIO_HANDLER_TRACKING_INIT(args)`] [An expression that is used to initialise the tracking mechanism.] ] + [ + [`BOOST_ASIO_HANDLER_LOCATION(args)`] + [A variable declaration that is used to define a source code location. + `args` is a parenthesised function argument list containing the file + name, line number, and function name.] + ] [ [`BOOST_ASIO_HANDLER_CREATION(args)`] [An expression that is called on creation of an asynchronous operation. @@ -214,7 +275,7 @@ preprocessor macros: [heading See Also] -[link boost_asio.examples.cpp11_examples.handler_tracking Custom handler tracking -example]. +[link boost_asio.examples.cpp11_examples.handler_tracking Handler tracking +examples]. [endsect] diff --git a/example/cpp11/handler_tracking/async_tcp_echo_server.cpp b/example/cpp11/handler_tracking/async_tcp_echo_server.cpp index f0c674e1..57f1ca6f 100644 --- a/example/cpp11/handler_tracking/async_tcp_echo_server.cpp +++ b/example/cpp11/handler_tracking/async_tcp_echo_server.cpp @@ -16,6 +16,13 @@ using boost::asio::ip::tcp; +// Define a helper macro to invoke BOOST_ASIO_HANDLER_LOCATION with the current +// file name, line number, and function name. For the function name, you might +// also consider using __PRETTY_FUNCTION__, BOOST_CURRENT_FUNCTION, or a hand- +// crafted name. For C++20 or later, you may also use std::source_location. +#define HANDLER_LOCATION \ + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, __func__)) + class session : public std::enable_shared_from_this { @@ -27,16 +34,22 @@ public: void start() { + HANDLER_LOCATION; + do_read(); } private: void do_read() { + HANDLER_LOCATION; + auto self(shared_from_this()); socket_.async_read_some(boost::asio::buffer(data_, max_length), [this, self](boost::system::error_code ec, std::size_t length) { + HANDLER_LOCATION; + if (!ec) { do_write(length); @@ -46,10 +59,14 @@ private: void do_write(std::size_t length) { + HANDLER_LOCATION; + auto self(shared_from_this()); boost::asio::async_write(socket_, boost::asio::buffer(data_, length), [this, self](boost::system::error_code ec, std::size_t /*length*/) { + HANDLER_LOCATION; + if (!ec) { do_read(); @@ -74,9 +91,13 @@ public: private: void do_accept() { + HANDLER_LOCATION; + acceptor_.async_accept( [this](boost::system::error_code ec, tcp::socket socket) { + HANDLER_LOCATION; + if (!ec) { std::make_shared(std::move(socket))->start(); diff --git a/example/cpp11/handler_tracking/custom_tracking.hpp b/example/cpp11/handler_tracking/custom_tracking.hpp index 1bb5b6ad..7a5d4712 100644 --- a/example/cpp11/handler_tracking/custom_tracking.hpp +++ b/example/cpp11/handler_tracking/custom_tracking.hpp @@ -24,6 +24,9 @@ # define BOOST_ASIO_HANDLER_TRACKING_INIT \ ::custom_tracking::init() +# define BOOST_ASIO_HANDLER_LOCATION(args) \ + ::custom_tracking::location args + # define BOOST_ASIO_HANDLER_CREATION(args) \ ::custom_tracking::creation args @@ -71,6 +74,13 @@ struct custom_tracking { } + // Record a source location. + static void location(const char* file_name, + int line, const char* function_name) + { + std::printf("At location %s:%d in %s\n", file_name, line, function_name); + } + // Record the creation of a tracked handler. static void creation(boost::asio::execution_context& /*ctx*/, tracked_handler& h, const char* object_type, void* /*object*/, diff --git a/example/cpp17/coroutines_ts/echo_server.cpp b/example/cpp17/coroutines_ts/echo_server.cpp index 7ca12c69..01cf3807 100644 --- a/example/cpp17/coroutines_ts/echo_server.cpp +++ b/example/cpp17/coroutines_ts/echo_server.cpp @@ -23,6 +23,11 @@ using boost::asio::detached; using boost::asio::use_awaitable; namespace this_coro = boost::asio::this_coro; +#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) +# define use_awaitable \ + boost::asio::use_awaitable_t(__FILE__, __LINE__, __PRETTY_FUNCTION__) +#endif + awaitable echo(tcp::socket socket) { try diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp index c8e69ea0..bff69672 100644 --- a/include/boost/asio/detail/config.hpp +++ b/include/boost/asio/detail/config.hpp @@ -927,6 +927,37 @@ # endif // !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) #endif // !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) +// Standard library support for std::source_location. +#if !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) +// ... +# endif // !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) + +// Standard library support for std::experimental::source_location. +#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if defined(__GNUC__) +# if (__cplusplus >= 201709) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1 +# endif // __has_include() +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +// Standard library has a source_location that we can use. +#if !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) +# if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# endif // !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) + // Windows App target. Windows but with a limited API. #if !defined(BOOST_ASIO_WINDOWS_APP) # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) diff --git a/include/boost/asio/detail/handler_tracking.hpp b/include/boost/asio/detail/handler_tracking.hpp index 3eeb2046..78730412 100644 --- a/include/boost/asio/detail/handler_tracking.hpp +++ b/include/boost/asio/detail/handler_tracking.hpp @@ -90,6 +90,28 @@ public: // Initialise the tracking system. BOOST_ASIO_DECL static void init(); + class location + { + public: + // Constructor adds a location to the stack. + BOOST_ASIO_DECL explicit location(const char* file, + int line, const char* func); + + // Destructor removes a location from the stack. + BOOST_ASIO_DECL ~location(); + + private: + // Disallow copying and assignment. + location(const location&) BOOST_ASIO_DELETED; + location& operator=(const location&) BOOST_ASIO_DELETED; + + friend class handler_tracking; + const char* file_; + int line_; + const char* func_; + location* next_; + }; + // Record the creation of a tracked handler. BOOST_ASIO_DECL static void creation( execution_context& context, tracked_handler& h, @@ -178,6 +200,9 @@ private: # define BOOST_ASIO_HANDLER_TRACKING_INIT \ boost::asio::detail::handler_tracking::init() +# define BOOST_ASIO_HANDLER_LOCATION(args) \ + boost::asio::detail::handler_tracking::location tracked_location args + # define BOOST_ASIO_HANDLER_CREATION(args) \ boost::asio::detail::handler_tracking::creation args @@ -214,6 +239,7 @@ private: # define BOOST_ASIO_INHERIT_TRACKED_HANDLER # define BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER # define BOOST_ASIO_HANDLER_TRACKING_INIT (void)0 +# define BOOST_ASIO_HANDLER_LOCATION(loc) (void)0 # define BOOST_ASIO_HANDLER_CREATION(args) (void)0 # define BOOST_ASIO_HANDLER_COMPLETION(args) (void)0 # define BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0 diff --git a/include/boost/asio/detail/impl/handler_tracking.ipp b/include/boost/asio/detail/impl/handler_tracking.ipp index 6c7fcfc1..f87924c6 100644 --- a/include/boost/asio/detail/impl/handler_tracking.ipp +++ b/include/boost/asio/detail/impl/handler_tracking.ipp @@ -74,11 +74,12 @@ struct handler_tracking::tracking_state static_mutex mutex_; uint64_t next_id_; tss_ptr* current_completion_; + tss_ptr* current_location_; }; handler_tracking::tracking_state* handler_tracking::get_state() { - static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0 }; + static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0, 0 }; return &state; } @@ -91,6 +92,25 @@ void handler_tracking::init() static_mutex::scoped_lock lock(state->mutex_); if (state->current_completion_ == 0) state->current_completion_ = new tss_ptr; + if (state->current_location_ == 0) + state->current_location_ = new tss_ptr; +} + +handler_tracking::location::location( + const char* file, int line, const char* func) + : file_(file), + line_(line), + func_(func), + next_(*get_state()->current_location_) +{ + if (file_) + *get_state()->current_location_ = this; +} + +handler_tracking::location::~location() +{ + if (file_) + *get_state()->current_location_ = next_; } void handler_tracking::creation(execution_context&, @@ -110,6 +130,24 @@ void handler_tracking::creation(execution_context&, if (completion* current_completion = *state->current_completion_) current_id = current_completion->id_; + for (location* current_location = *state->current_location_; + current_location; current_location = current_location->next_) + { + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%I64u^%I64u|%s%s%.80s%s(%.80s:%d)\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|%llu^%llu|%s%s%.80s%s(%.80s:%d)\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + current_id, h.id_, + current_location == *state->current_location_ ? "in " : "called from ", + current_location->func_ ? "'" : "", + current_location->func_ ? current_location->func_ : "", + current_location->func_ ? "' " : "", + current_location->file_, current_location->line_); + } + write_line( #if defined(BOOST_ASIO_WINDOWS) "@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n", diff --git a/include/boost/asio/detail/source_location.hpp b/include/boost/asio/detail/source_location.hpp new file mode 100644 index 00000000..e36ef8c6 --- /dev/null +++ b/include/boost/asio/detail/source_location.hpp @@ -0,0 +1,47 @@ +// +// detail/source_location.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SOURCE_LOCATION_HPP +#define BOOST_ASIO_DETAIL_SOURCE_LOCATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) + +#if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# include +#elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# include +#else // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# error BOOST_ASIO_HAS_SOURCE_LOCATION is set \ + but no source_location is available +#endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +using std::source_location; +#elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +using std::experimental::source_location; +#endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) + +#endif // BOOST_ASIO_DETAIL_SOURCE_LOCATION_HPP diff --git a/include/boost/asio/impl/co_spawn.hpp b/include/boost/asio/impl/co_spawn.hpp index 4eb4e00b..df20aa56 100644 --- a/include/boost/asio/impl/co_spawn.hpp +++ b/include/boost/asio/impl/co_spawn.hpp @@ -71,7 +71,7 @@ awaitable co_spawn_entry_point( auto handler_work = make_work_guard(handler, ex); (void) co_await (post)(spawn_work.get_executor(), - use_awaitable_t{}); + use_awaitable_t{__FILE__, __LINE__, "co_spawn_entry_point"}); std::exception_ptr e = nullptr; try diff --git a/include/boost/asio/impl/connect.hpp b/include/boost/asio/impl/connect.hpp index 82b17908..a761089c 100644 --- a/include/boost/asio/impl/connect.hpp +++ b/include/boost/asio/impl/connect.hpp @@ -358,6 +358,7 @@ namespace detail if (iter != end) { socket_.close(ec); + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); socket_.async_connect(*iter, BOOST_ASIO_MOVE_CAST(range_connect_op)(*this)); return; @@ -366,6 +367,7 @@ namespace detail if (start) { ec = boost::asio::error::not_found; + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); boost::asio::post(socket_.get_executor(), detail::bind_handler( BOOST_ASIO_MOVE_CAST(range_connect_op)(*this), ec)); @@ -545,6 +547,7 @@ namespace detail if (iter_ != end_) { socket_.close(ec); + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); socket_.async_connect(*iter_, BOOST_ASIO_MOVE_CAST(iterator_connect_op)(*this)); return; @@ -553,6 +556,7 @@ namespace detail if (start) { ec = boost::asio::error::not_found; + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); boost::asio::post(socket_.get_executor(), detail::bind_handler( BOOST_ASIO_MOVE_CAST(iterator_connect_op)(*this), ec)); diff --git a/include/boost/asio/impl/read.hpp b/include/boost/asio/impl/read.hpp index 9889aceb..23293ebe 100644 --- a/include/boost/asio/impl/read.hpp +++ b/include/boost/asio/impl/read.hpp @@ -361,8 +361,11 @@ namespace detail max_size = this->check_for_completion(ec, buffers_.total_consumed()); do { - stream_.async_read_some(buffers_.prepare(max_size), - BOOST_ASIO_MOVE_CAST(read_op)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read")); + stream_.async_read_some(buffers_.prepare(max_size), + BOOST_ASIO_MOVE_CAST(read_op)(*this)); + } return; default: buffers_.consume(bytes_transferred); if ((!ec && bytes_transferred == 0) || buffers_.empty()) @@ -632,8 +635,11 @@ namespace detail buffers_.max_size() - buffers_.size())); for (;;) { - stream_.async_read_some(buffers_.prepare(bytes_available), - BOOST_ASIO_MOVE_CAST(read_dynbuf_v1_op)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read")); + stream_.async_read_some(buffers_.prepare(bytes_available), + BOOST_ASIO_MOVE_CAST(read_dynbuf_v1_op)(*this)); + } return; default: total_transferred_ += bytes_transferred; buffers_.commit(bytes_transferred); @@ -932,8 +938,11 @@ namespace detail { pos = buffers_.size(); buffers_.grow(bytes_available_); - stream_.async_read_some(buffers_.data(pos, bytes_available_), - BOOST_ASIO_MOVE_CAST(read_dynbuf_v2_op)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read")); + stream_.async_read_some(buffers_.data(pos, bytes_available_), + BOOST_ASIO_MOVE_CAST(read_dynbuf_v2_op)(*this)); + } return; default: total_transferred_ += bytes_transferred; buffers_.shrink(bytes_available_ - bytes_transferred); diff --git a/include/boost/asio/impl/read_at.hpp b/include/boost/asio/impl/read_at.hpp index 8edc5e08..74715d1f 100644 --- a/include/boost/asio/impl/read_at.hpp +++ b/include/boost/asio/impl/read_at.hpp @@ -226,9 +226,12 @@ namespace detail max_size = this->check_for_completion(ec, buffers_.total_consumed()); do { - device_.async_read_some_at( - offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), - BOOST_ASIO_MOVE_CAST(read_at_op)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at")); + device_.async_read_some_at( + offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), + BOOST_ASIO_MOVE_CAST(read_at_op)(*this)); + } return; default: buffers_.consume(bytes_transferred); if ((!ec && bytes_transferred == 0) || buffers_.empty()) @@ -501,9 +504,12 @@ namespace detail bytes_available = read_size_helper(streambuf_, max_size); for (;;) { - device_.async_read_some_at(offset_ + total_transferred_, - streambuf_.prepare(bytes_available), - BOOST_ASIO_MOVE_CAST(read_at_streambuf_op)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at")); + device_.async_read_some_at(offset_ + total_transferred_, + streambuf_.prepare(bytes_available), + BOOST_ASIO_MOVE_CAST(read_at_streambuf_op)(*this)); + } return; default: total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); diff --git a/include/boost/asio/impl/read_until.hpp b/include/boost/asio/impl/read_until.hpp index 132adfe8..6af4f075 100644 --- a/include/boost/asio/impl/read_until.hpp +++ b/include/boost/asio/impl/read_until.hpp @@ -872,8 +872,12 @@ namespace detail break; // Start a new asynchronous read op_v1eration to obtain more data. - stream_.async_read_some(buffers_.prepare(bytes_to_read), - BOOST_ASIO_MOVE_CAST(read_until_delim_op_v1)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.prepare(bytes_to_read), + BOOST_ASIO_MOVE_CAST(read_until_delim_op_v1)(*this)); + } return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) @@ -1156,8 +1160,12 @@ namespace detail break; // Start a new asynchronous read op_v1eration to obtain more data. - stream_.async_read_some(buffers_.prepare(bytes_to_read), - BOOST_ASIO_MOVE_CAST(read_until_delim_string_op_v1)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.prepare(bytes_to_read), + BOOST_ASIO_MOVE_CAST(read_until_delim_string_op_v1)(*this)); + } return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) @@ -1448,8 +1456,12 @@ namespace detail break; // Start a new asynchronous read op_v1eration to obtain more data. - stream_.async_read_some(buffers_.prepare(bytes_to_read), - BOOST_ASIO_MOVE_CAST(read_until_expr_op_v1)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.prepare(bytes_to_read), + BOOST_ASIO_MOVE_CAST(read_until_expr_op_v1)(*this)); + } return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) @@ -1733,8 +1745,12 @@ namespace detail break; // Start a new asynchronous read op_v1eration to obtain more data. - stream_.async_read_some(buffers_.prepare(bytes_to_read), - BOOST_ASIO_MOVE_CAST(read_until_match_op_v1)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.prepare(bytes_to_read), + BOOST_ASIO_MOVE_CAST(read_until_match_op_v1)(*this)); + } return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) @@ -2082,8 +2098,12 @@ namespace detail // Start a new asynchronous read op_v2eration to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); - stream_.async_read_some(buffers_.data(pos, bytes_to_read_), - BOOST_ASIO_MOVE_CAST(read_until_delim_op_v2)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + BOOST_ASIO_MOVE_CAST(read_until_delim_op_v2)(*this)); + } return; default: buffers_.shrink(bytes_to_read_ - bytes_transferred); if (ec || bytes_transferred == 0) @@ -2371,8 +2391,12 @@ namespace detail // Start a new asynchronous read op_v2eration to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); - stream_.async_read_some(buffers_.data(pos, bytes_to_read_), - BOOST_ASIO_MOVE_CAST(read_until_delim_string_op_v2)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + BOOST_ASIO_MOVE_CAST(read_until_delim_string_op_v2)(*this)); + } return; default: buffers_.shrink(bytes_to_read_ - bytes_transferred); if (ec || bytes_transferred == 0) @@ -2670,8 +2694,12 @@ namespace detail // Start a new asynchronous read op_v2eration to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); - stream_.async_read_some(buffers_.data(pos, bytes_to_read_), - BOOST_ASIO_MOVE_CAST(read_until_expr_op_v2)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + BOOST_ASIO_MOVE_CAST(read_until_expr_op_v2)(*this)); + } return; default: buffers_.shrink(bytes_to_read_ - bytes_transferred); if (ec || bytes_transferred == 0) @@ -2961,8 +2989,12 @@ namespace detail // Start a new asynchronous read op_v2eration to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); - stream_.async_read_some(buffers_.data(pos, bytes_to_read_), - BOOST_ASIO_MOVE_CAST(read_until_match_op_v2)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, "async_read_until")); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + BOOST_ASIO_MOVE_CAST(read_until_match_op_v2)(*this)); + } return; default: buffers_.shrink(bytes_to_read_ - bytes_transferred); if (ec || bytes_transferred == 0) diff --git a/include/boost/asio/impl/use_awaitable.hpp b/include/boost/asio/impl/use_awaitable.hpp index 02a1545a..eb90444c 100644 --- a/include/boost/asio/impl/use_awaitable.hpp +++ b/include/boost/asio/impl/use_awaitable.hpp @@ -252,10 +252,13 @@ public: template static return_type initiate(Initiation initiation, - use_awaitable_t, InitArgs... args) + use_awaitable_t u, InitArgs... args) { + (void)u; + co_await [&](auto* frame) { + BOOST_ASIO_HANDLER_LOCATION((u.file_name_, u.line_, u.function_name_)); handler_type handler(frame->detach_thread()); std::move(initiation)(std::move(handler), std::move(args)...); return static_cast(nullptr); diff --git a/include/boost/asio/impl/write.hpp b/include/boost/asio/impl/write.hpp index cb35613d..1b3f23c1 100644 --- a/include/boost/asio/impl/write.hpp +++ b/include/boost/asio/impl/write.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -326,8 +327,11 @@ namespace detail max_size = this->check_for_completion(ec, buffers_.total_consumed()); do { - stream_.async_write_some(buffers_.prepare(max_size), - BOOST_ASIO_MOVE_CAST(write_op)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write")); + stream_.async_write_some(buffers_.prepare(max_size), + BOOST_ASIO_MOVE_CAST(write_op)(*this)); + } return; default: buffers_.consume(bytes_transferred); if ((!ec && bytes_transferred == 0) || buffers_.empty()) diff --git a/include/boost/asio/impl/write_at.hpp b/include/boost/asio/impl/write_at.hpp index bbc6a9da..a06ffc3c 100644 --- a/include/boost/asio/impl/write_at.hpp +++ b/include/boost/asio/impl/write_at.hpp @@ -211,9 +211,12 @@ namespace detail max_size = this->check_for_completion(ec, buffers_.total_consumed()); do { - device_.async_write_some_at( - offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), - BOOST_ASIO_MOVE_CAST(write_at_op)(*this)); + { + BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write_at")); + device_.async_write_some_at( + offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), + BOOST_ASIO_MOVE_CAST(write_at_op)(*this)); + } return; default: buffers_.consume(bytes_transferred); if ((!ec && bytes_transferred == 0) || buffers_.empty()) diff --git a/include/boost/asio/ssl/detail/buffered_handshake_op.hpp b/include/boost/asio/ssl/detail/buffered_handshake_op.hpp index 4031df63..2cf8d151 100644 --- a/include/boost/asio/ssl/detail/buffered_handshake_op.hpp +++ b/include/boost/asio/ssl/detail/buffered_handshake_op.hpp @@ -30,6 +30,11 @@ template class buffered_handshake_op { public: + static BOOST_ASIO_CONSTEXPR const char* tracking_name() + { + return "ssl::stream<>::async_buffered_handshake"; + } + buffered_handshake_op(stream_base::handshake_type type, const ConstBufferSequence& buffers) : type_(type), diff --git a/include/boost/asio/ssl/detail/handshake_op.hpp b/include/boost/asio/ssl/detail/handshake_op.hpp index 58f83124..7904af7b 100644 --- a/include/boost/asio/ssl/detail/handshake_op.hpp +++ b/include/boost/asio/ssl/detail/handshake_op.hpp @@ -29,6 +29,11 @@ namespace detail { class handshake_op { public: + static BOOST_ASIO_CONSTEXPR const char* tracking_name() + { + return "ssl::stream<>::async_handshake"; + } + handshake_op(stream_base::handshake_type type) : type_(type) { diff --git a/include/boost/asio/ssl/detail/io.hpp b/include/boost/asio/ssl/detail/io.hpp index 94d4db1b..f024bdab 100644 --- a/include/boost/asio/ssl/detail/io.hpp +++ b/include/boost/asio/ssl/detail/io.hpp @@ -17,6 +17,7 @@ #include +#include #include #include #include @@ -163,6 +164,9 @@ public: // Prevent other read operations from being started. core_.pending_read_.expires_at(core_.pos_infin()); + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, Operation::tracking_name())); + // Start reading some data from the underlying transport. next_layer_.async_read_some( boost::asio::buffer(core_.input_buffer_), @@ -170,6 +174,9 @@ public: } else { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, Operation::tracking_name())); + // Wait until the current read operation completes. core_.pending_read_.async_wait(BOOST_ASIO_MOVE_CAST(io_op)(*this)); } @@ -190,6 +197,9 @@ public: // Prevent other write operations from being started. core_.pending_write_.expires_at(core_.pos_infin()); + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, Operation::tracking_name())); + // Start writing all the data to the underlying transport. boost::asio::async_write(next_layer_, core_.engine_.get_output(core_.output_buffer_), @@ -197,6 +207,9 @@ public: } else { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, Operation::tracking_name())); + // Wait until the current write operation completes. core_.pending_write_.async_wait(BOOST_ASIO_MOVE_CAST(io_op)(*this)); } @@ -214,6 +227,9 @@ public: // read so the handler runs "as-if" posted using io_context::post(). if (start) { + BOOST_ASIO_HANDLER_LOCATION(( + __FILE__, __LINE__, Operation::tracking_name())); + next_layer_.async_read_some( boost::asio::buffer(core_.input_buffer_, 0), BOOST_ASIO_MOVE_CAST(io_op)(*this)); diff --git a/include/boost/asio/ssl/detail/read_op.hpp b/include/boost/asio/ssl/detail/read_op.hpp index d57366e4..ede49f1b 100644 --- a/include/boost/asio/ssl/detail/read_op.hpp +++ b/include/boost/asio/ssl/detail/read_op.hpp @@ -31,6 +31,11 @@ template class read_op { public: + static BOOST_ASIO_CONSTEXPR const char* tracking_name() + { + return "ssl::stream<>::async_read_some"; + } + read_op(const MutableBufferSequence& buffers) : buffers_(buffers) { diff --git a/include/boost/asio/ssl/detail/shutdown_op.hpp b/include/boost/asio/ssl/detail/shutdown_op.hpp index 3d96fd2e..51e2c787 100644 --- a/include/boost/asio/ssl/detail/shutdown_op.hpp +++ b/include/boost/asio/ssl/detail/shutdown_op.hpp @@ -29,6 +29,11 @@ namespace detail { class shutdown_op { public: + static BOOST_ASIO_CONSTEXPR const char* tracking_name() + { + return "ssl::stream<>::async_shutdown"; + } + engine::want operator()(engine& eng, boost::system::error_code& ec, std::size_t& bytes_transferred) const diff --git a/include/boost/asio/ssl/detail/write_op.hpp b/include/boost/asio/ssl/detail/write_op.hpp index 204fe205..292e5fd5 100644 --- a/include/boost/asio/ssl/detail/write_op.hpp +++ b/include/boost/asio/ssl/detail/write_op.hpp @@ -31,6 +31,11 @@ template class write_op { public: + static BOOST_ASIO_CONSTEXPR const char* tracking_name() + { + return "ssl::stream<>::async_write_some"; + } + write_op(const ConstBufferSequence& buffers) : buffers_(buffers) { diff --git a/include/boost/asio/use_awaitable.hpp b/include/boost/asio/use_awaitable.hpp index 152e3286..5a08098a 100644 --- a/include/boost/asio/use_awaitable.hpp +++ b/include/boost/asio/use_awaitable.hpp @@ -20,6 +20,13 @@ #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #include +#include + +#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) +# if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) +# include +# endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) #include @@ -47,10 +54,43 @@ template struct use_awaitable_t { /// Default constructor. - BOOST_ASIO_CONSTEXPR use_awaitable_t() + BOOST_ASIO_CONSTEXPR use_awaitable_t( +#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) +# if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) + detail::source_location location = detail::source_location::current() +# endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + ) +#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) +# if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) + : file_name_(location.file_name()), + line_(location.line()), + function_name_(location.function_name()) +# else // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) + : file_name_(0), + line_(0), + function_name_(0) +# endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) { } + /// Constructor used to specify file name, line, and function name. + BOOST_ASIO_CONSTEXPR use_awaitable_t(const char* file_name, + int line, const char* function_name) +#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + : file_name_(file_name), + line_(line), + function_name_(function_name) +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + { +#if !defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + (void)file_name; + (void)line; + (void)function_name; +#endif // !defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + } + /// Adapts an executor to add the @c use_awaitable_t completion token as the /// default. template @@ -88,16 +128,24 @@ struct use_awaitable_t executor_with_default::type::executor_type> >::other(BOOST_ASIO_MOVE_CAST(T)(object)); } + +#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + const char* file_name_; + int line_; + const char* function_name_; +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) }; /// A completion token object that represents the currently executing coroutine. /** * See the documentation for boost::asio::use_awaitable_t for a usage example. */ -#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +#if defined(GENERATING_DOCUMENTATION) constexpr use_awaitable_t<> use_awaitable; +#elif defined(BOOST_ASIO_HAS_CONSTEXPR) +constexpr use_awaitable_t<> use_awaitable(0, 0, 0); #elif defined(BOOST_ASIO_MSVC) -__declspec(selectany) use_awaitable_t<> use_awaitable; +__declspec(selectany) use_awaitable_t<> use_awaitable(0, 0, 0); #endif } // namespace asio From 62afb04c4b9906e9547f27a1a2fec34bd9f96085 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:47:14 +1000 Subject: [PATCH 07/90] Fix search/replace damage in comments. --- include/boost/asio/impl/read_until.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/boost/asio/impl/read_until.hpp b/include/boost/asio/impl/read_until.hpp index 6af4f075..a82a4ade 100644 --- a/include/boost/asio/impl/read_until.hpp +++ b/include/boost/asio/impl/read_until.hpp @@ -871,7 +871,7 @@ namespace detail if (!start && bytes_to_read == 0) break; - // Start a new asynchronous read op_v1eration to obtain more data. + // Start a new asynchronous read operation to obtain more data. { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); @@ -1159,7 +1159,7 @@ namespace detail if (!start && bytes_to_read == 0) break; - // Start a new asynchronous read op_v1eration to obtain more data. + // Start a new asynchronous read operation to obtain more data. { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); @@ -1455,7 +1455,7 @@ namespace detail if (!start && bytes_to_read == 0) break; - // Start a new asynchronous read op_v1eration to obtain more data. + // Start a new asynchronous read operation to obtain more data. { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); @@ -1744,7 +1744,7 @@ namespace detail if (!start && bytes_to_read == 0) break; - // Start a new asynchronous read op_v1eration to obtain more data. + // Start a new asynchronous read operation to obtain more data. { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); @@ -2095,7 +2095,7 @@ namespace detail if (!start && bytes_to_read_ == 0) break; - // Start a new asynchronous read op_v2eration to obtain more data. + // Start a new asynchronous read operation to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); { @@ -2388,7 +2388,7 @@ namespace detail if (!start && bytes_to_read_ == 0) break; - // Start a new asynchronous read op_v2eration to obtain more data. + // Start a new asynchronous read operation to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); { @@ -2691,7 +2691,7 @@ namespace detail if (!start && bytes_to_read_ == 0) break; - // Start a new asynchronous read op_v2eration to obtain more data. + // Start a new asynchronous read operation to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); { @@ -2986,7 +2986,7 @@ namespace detail if (!start && bytes_to_read_ == 0) break; - // Start a new asynchronous read op_v2eration to obtain more data. + // Start a new asynchronous read operation to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); { From 496fdf25a5e70cc517064f5a1a83740b2ebbff22 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:47:32 +1000 Subject: [PATCH 08/90] Fix awaitable_handler specialisation for empty completion signatures. --- include/boost/asio/impl/use_awaitable.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/asio/impl/use_awaitable.hpp b/include/boost/asio/impl/use_awaitable.hpp index eb90444c..09025182 100644 --- a/include/boost/asio/impl/use_awaitable.hpp +++ b/include/boost/asio/impl/use_awaitable.hpp @@ -55,7 +55,7 @@ template class awaitable_handler; template -class awaitable_handler +class awaitable_handler : public awaitable_handler_base { public: From b258d68f3a62143df5cdef74251598e043df6c10 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:47:48 +1000 Subject: [PATCH 09/90] Add missing handler tracking include. --- include/boost/asio/impl/connect.hpp | 1 + include/boost/asio/impl/read.hpp | 1 + include/boost/asio/impl/read_at.hpp | 1 + include/boost/asio/impl/read_until.hpp | 1 + include/boost/asio/impl/write_at.hpp | 1 + 5 files changed, 5 insertions(+) diff --git a/include/boost/asio/impl/connect.hpp b/include/boost/asio/impl/connect.hpp index a761089c..27fc66c0 100644 --- a/include/boost/asio/impl/connect.hpp +++ b/include/boost/asio/impl/connect.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/impl/read.hpp b/include/boost/asio/impl/read.hpp index 23293ebe..8c2eb4e2 100644 --- a/include/boost/asio/impl/read.hpp +++ b/include/boost/asio/impl/read.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/impl/read_at.hpp b/include/boost/asio/impl/read_at.hpp index 74715d1f..e4ca93e5 100644 --- a/include/boost/asio/impl/read_at.hpp +++ b/include/boost/asio/impl/read_at.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/impl/read_until.hpp b/include/boost/asio/impl/read_until.hpp index a82a4ade..399eb5d0 100644 --- a/include/boost/asio/impl/read_until.hpp +++ b/include/boost/asio/impl/read_until.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/impl/write_at.hpp b/include/boost/asio/impl/write_at.hpp index a06ffc3c..19d00d9b 100644 --- a/include/boost/asio/impl/write_at.hpp +++ b/include/boost/asio/impl/write_at.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include From d4105da06fb4e58e7da573e495a3d99687d6480f Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:48:07 +1000 Subject: [PATCH 10/90] Various improvements to the handlerviz.pl tool. * Add nodes for pending handlers at bottom of graph, outlined in red. * Display source location in a tooltip on the edge label (for SVG). * Use invisible nodes to enforce order to keep related control flow vertical. --- tools/handlerviz.pl | 100 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 12 deletions(-) diff --git a/tools/handlerviz.pl b/tools/handlerviz.pl index 7e8de3df..7c1ff13c 100755 --- a/tools/handlerviz.pl +++ b/tools/handlerviz.pl @@ -16,7 +16,7 @@ # # perl handlerviz.pl < output.txt | dot -Tpdf > output.pdf # -# Copyright (c) 2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) # # Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -26,9 +26,11 @@ use strict; my %nodes = (); my @edges = (); +my %locations = (); my %anon_nodes = (); my $anon_id = 0; my %all_nodes = (); +my %pending_nodes = (); #------------------------------------------------------------------------------- # Parse the debugging output and populate the nodes and edges. @@ -62,6 +64,21 @@ sub parse_debug_output() my %edge = ( begin=>$begin, end=>$end, label=>$label ); push(@edges, \%edge); + + $pending_nodes{$end} = 1; + } + + # Handler location. + elsif ($action =~ /^([0-9]+)\^([0-9]+)$/) + { + if ($1 ne "0") + { + if (not exists($locations{($1,$2)})) + { + $locations{($1,$2)} = (); + } + push(@{$locations{($1,$2)}}, $description); + } } # Begin handler invocation. @@ -71,6 +88,7 @@ sub parse_debug_output() $new_node{content} = (); $nodes{$1} = \%new_node; $all_nodes{"$timestamp-$1"} = $1; + delete($pending_nodes{$1}); } # End handler invocation. @@ -92,6 +110,7 @@ sub parse_debug_output() $new_node{content} = (); $nodes{$1} = \%new_node; $all_nodes{"$timestamp-$1"} = $1; + delete($pending_nodes{$1}); } # Handler performed some operation. @@ -129,8 +148,8 @@ sub escape($) # Templates for dot output. my $graph_header = <<"EOF"; -/* Generated by asioviz.pl */ -digraph G +/* Generated by handlerviz.pl */ +digraph "handlerviz output" { graph [ nodesep="1" ]; node [ shape="box", fontsize="9" ]; @@ -172,9 +191,23 @@ my $anon_node = <<"EOF"; "%name%" [ label="%label%", color="gray" ]; EOF +my $pending_nodes_header = <<"EOF"; +{ +node [ shape="record", color="red" ]; +rank = "max"; +EOF + +my $pending_nodes_footer = <<"EOF"; +} +EOF + +my $pending_node = <<"EOF"; +"%name%"; +EOF + my $edges_header = <<"EOF"; { -edge [ style="dashed", arrowhead="open", weight="100" ]; +edge [ style="dashed", arrowhead="open" ]; EOF my $edges_footer = <<"EOF"; @@ -182,12 +215,13 @@ my $edges_footer = <<"EOF"; EOF my $edge = <<"EOF"; -"%begin%" -> "%end%" [ label="%label%" ] +"%begin%" -> "%end%" [ label="%label%", labeltooltip="%tooltip%" ] EOF my $node_order_header = <<"EOF"; { -edge [ style="invis", weight="1" ]; +node [ style="invisible" ]; +edge [ style="invis", weight="100" ]; EOF my $node_order_footer = <<"EOF"; @@ -195,7 +229,12 @@ my $node_order_footer = <<"EOF"; EOF my $node_order = <<"EOF"; -"%begin%" -> "%end%" +{ +rank="same" +"%begin%"; +"o%begin%"; +} +"o%begin%" -> "o%end%"; EOF #------------------------------------------------------------------------------- @@ -214,10 +253,13 @@ sub print_nodes() $header =~ s/%label%/$label/g; print($header); - my $line = $node_content; - my $content = $entry . " + " . sprintf("%.6f", $exit - $entry) . "s"; - $line =~ s/%content%/$content/g; - print($line); + if (defined($exit) and defined($entry)) + { + my $line = $node_content; + my $content = $entry . " + " . sprintf("%.6f", $exit - $entry) . "s"; + $line =~ s/%content%/$content/g; + print($line); + } foreach my $content (@{$node->{content}}) { @@ -243,7 +285,19 @@ sub print_anon_nodes() $line =~ s/%label%/$label/g; print($line); } - print($edges_footer); + print($anon_nodes_footer); +} + +sub print_pending_nodes() +{ + print($pending_nodes_header); + foreach my $name (sort keys %pending_nodes) + { + my $line = $pending_node; + $line =~ s/%name%/$name/g; + print($line); + } + print($pending_nodes_footer); } sub print_edges() @@ -254,10 +308,19 @@ sub print_edges() my $begin = $e->{begin}; my $end = $e->{end}; my $label = $e->{label}; + my $tooltip = ""; + if (exists($locations{($begin,$end)})) + { + for my $line (@{$locations{($begin,$end)}}) + { + $tooltip = $tooltip . escape($line) . "\n"; + } + } my $line = $edge; $line =~ s/%begin%/$begin/g; $line =~ s/%end%/$end/g; $line =~ s/%label%/$label/g; + $line =~ s/%tooltip%/$tooltip/g; print($line); } print($edges_footer); @@ -280,6 +343,18 @@ sub print_node_order() } $prev = $all_nodes{$name}; } + foreach my $name (sort keys %pending_nodes) + { + if ($prev ne "") + { + my $begin = $prev; + my $line = $node_order; + $line =~ s/%begin%/$begin/g; + $line =~ s/%end%/$name/g; + print($line); + } + last; + } print($node_order_footer); } @@ -288,6 +363,7 @@ sub generate_dot() print($graph_header); print_nodes(); print_anon_nodes(); + print_pending_nodes(); print_edges(); print_node_order(); print($graph_footer); From bc621661c81e60bc6e486cba0d3193e82a56c693 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:48:30 +1000 Subject: [PATCH 11/90] Add handlerlive.pl tool. The handlerlive.pl script processes handler tracking output to produce a list of "live" handlers, namely those that are associated with pending asynchronous operations, as well as handlers that are currently executing. To use: cat output.txt | perl handlerlive.pl or: perl handerlive.pl < output.txt or: perl handlerlive.pl output.txt --- tools/handlerlive.pl | 89 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 tools/handlerlive.pl diff --git a/tools/handlerlive.pl b/tools/handlerlive.pl new file mode 100644 index 00000000..b7a5b8cf --- /dev/null +++ b/tools/handlerlive.pl @@ -0,0 +1,89 @@ +#!/usr/bin/perl -w +# +# handlerlive.pl +# ~~~~~~~~~~~~~~ +# +# A tool for post-processing the debug output generated by Asio-based programs +# to print a list of "live" handlers. These are handlers that are associated +# with operations that have not yet completed, or running handlers that have +# not yet finished their execution. Programs write this output to the standard +# error stream when compiled with the define `BOOST_ASIO_ENABLE_HANDLER_TRACKING'. +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +use strict; + +my %pending_handlers = (); +my %running_handlers = (); + +#------------------------------------------------------------------------------- +# Parse the debugging output and update the set of pending handlers. + +sub parse_debug_output() +{ + while (my $line = <>) + { + chomp($line); + + if ($line =~ /\@asio\|([^|]*)\|([^|]*)\|(.*)$/) + { + my $action = $2; + + # Handler creation. + if ($action =~ /^([0-9]+)\*([0-9]+)$/) + { + $pending_handlers{$2} = 1; + } + + # Begin handler invocation. + elsif ($action =~ /^>([0-9]+)$/) + { + delete($pending_handlers{$1}); + $running_handlers{$1} = 1; + } + + # End handler invocation. + elsif ($action =~ /^<([0-9]+)$/) + { + delete($running_handlers{$1}); + } + + # Handler threw exception. + elsif ($action =~ /^!([0-9]+)$/) + { + delete($running_handlers{$1}); + } + + # Handler was destroyed without being invoked. + elsif ($action =~ /^~([0-9]+)$/) + { + delete($pending_handlers{$1}); + } + } + } +} + +#------------------------------------------------------------------------------- +# Print a list of incompleted handers, on a single line delimited by spaces. + +sub print_handlers($) +{ + my $handlers = shift; + my $prefix = ""; + foreach my $handler (sort { $a <=> $b } keys %{$handlers}) + { + print("$prefix$handler"); + $prefix = " "; + } + print("\n") if ($prefix ne ""); +} + +#------------------------------------------------------------------------------- + +parse_debug_output(); +print_handlers(\%running_handlers); +print_handlers(\%pending_handlers); From 1c39d47784216a63be5ebba3808477d97f1b1e41 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:48:55 +1000 Subject: [PATCH 12/90] Add handlertree.pl tool. The handlertree.pl script filters handler tracking output to include only those events in the tree that produced the nominated handlers. For example, to filter the output to include only the events associated with handlers 123, 456, and their predecessors: cat output.txt | perl handlertree.pl 123 456 or: perl handlertree.pl 123 456 < output.txt This script may be combined with handerlive.pl and handlerviz.pl to produce a graph of the "live" asynchronous operation chains. For example: cat output.txt | perl handlertree.pl `perl handlerlive.pl output.txt` | perl handlerviz.pl | dot -Tsvg > output.svg --- tools/handlertree.pl | 140 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 tools/handlertree.pl diff --git a/tools/handlertree.pl b/tools/handlertree.pl new file mode 100644 index 00000000..ff5c06b1 --- /dev/null +++ b/tools/handlertree.pl @@ -0,0 +1,140 @@ +#!/usr/bin/perl -w +# +# handlertree.pl +# ~~~~~~~~~~~~~~ +# A tool for post-processing the debug output generated by Asio-based programs +# to print the tree of handlers that resulted in some specified handler ids. +# Programs write this output to the standard error stream when compiled with +# the define `BOOST_ASIO_ENABLE_HANDLER_TRACKING'. +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +use strict; + +my %target_handlers = (); +my @cached_output = (); +my %outstanding_handlers = (); +my %running_handlers = (); + +#------------------------------------------------------------------------------- +# Build the initial list of target handlers from the command line arguments. + +sub build_initial_target_handlers() +{ + for my $handler (@ARGV) + { + $target_handlers{$handler} = 1; + } +} + +#------------------------------------------------------------------------------- +# Parse the debugging output and cache the handler tracking lines. + +sub parse_debug_output() +{ + while (my $line = ) + { + chomp($line); + + if ($line =~ /\@asio\|([^|]*)\|([^|]*)\|(.*)$/) + { + push(@cached_output, $line); + } + } +} + +#------------------------------------------------------------------------------- +# Iterate over the cached output in revese and build a hash of all target +# handlers' ancestors. + +sub build_target_handler_tree() +{ + my $i = scalar(@cached_output) - 1; + while ($i >= 0) + { + my $line = $cached_output[$i]; + + if ($line =~ /\@asio\|([^|]*)\|([^|]*)\|(.*)$/) + { + my $action = $2; + + # Handler creation. + if ($action =~ /^([0-9]+)\*([0-9]+)$/) + { + if ($1 ne "0" and exists($target_handlers{$2})) + { + $target_handlers{$1} = 1; + } + } + } + + --$i; + } +} + +#------------------------------------------------------------------------------- +# Print out all handler tracking records associated with the target handlers. + +sub print_target_handler_records() +{ + for my $line (@cached_output) + { + if ($line =~ /\@asio\|([^|]*)\|([^|]*)\|(.*)$/) + { + my $action = $2; + + # Handler location. + if ($action =~ /^([0-9]+)\^([0-9]+)$/) + { + print("$line\n") if ($1 eq "0" or exists($target_handlers{$1})) and exists($target_handlers{$2}); + } + + # Handler creation. + if ($action =~ /^([0-9]+)\*([0-9]+)$/) + { + print("$1, $2, $line\n") if ($1 eq "0" or exists($target_handlers{$1})) and exists($target_handlers{$2}); + } + + # Begin handler invocation. + elsif ($action =~ /^>([0-9]+)$/) + { + print("$line\n") if (exists($target_handlers{$1})); + } + + # End handler invocation. + elsif ($action =~ /^<([0-9]+)$/) + { + print("$line\n") if (exists($target_handlers{$1})); + } + + # Handler threw exception. + elsif ($action =~ /^!([0-9]+)$/) + { + print("$line\n") if (exists($target_handlers{$1})); + } + + # Handler was destroyed without being invoked. + elsif ($action =~ /^~([0-9]+)$/) + { + print("$line\n") if (exists($target_handlers{$1})); + } + + # Operation associated with a handler. + elsif ($action =~ /^\.([0-9]+)$/) + { + print("$line\n") if (exists($target_handlers{$1})); + } + } + } +} + +#------------------------------------------------------------------------------- + +build_initial_target_handlers(); +parse_debug_output(); +build_target_handler_tree(); +print_target_handler_records(); From 3f12308c034113dab9c233c4d3b1f4e75c94e156 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:49:30 +1000 Subject: [PATCH 13/90] Add overloads of co_spawn that launch an awaitable. This change allows us to write: co_spawn(executor, echo(std::move(socket)), detached); instead of: co_spawn(executor, [socket = std::move(socket)]() mutable { return echo(std::move(socket)); }, detached); --- doc/overview/coroutines_ts.qbk | 17 +- doc/reference.xsl | 3 + example/cpp17/coroutines_ts/chat_server.cpp | 5 +- example/cpp17/coroutines_ts/echo_server.cpp | 9 +- .../echo_server_with_default.cpp | 9 +- .../cpp17/coroutines_ts/range_based_for.cpp | 7 +- .../coroutines_ts/refactored_echo_server.cpp | 9 +- include/boost/asio/co_spawn.hpp | 386 +++++++++++++++++- include/boost/asio/impl/co_spawn.hpp | 87 ++++ 9 files changed, 483 insertions(+), 49 deletions(-) diff --git a/doc/overview/coroutines_ts.qbk b/doc/overview/coroutines_ts.qbk index 7638e72d..04a07774 100644 --- a/doc/overview/coroutines_ts.qbk +++ b/doc/overview/coroutines_ts.qbk @@ -14,12 +14,7 @@ boost_asio.reference.co_spawn `co_spawn()`] function. These facilities allow pro to implement asynchronous logic in a synchronous manner, in conjunction with the `co_await` keyword, as shown in the following example: - boost::asio::co_spawn(executor, - [socket = std::move(socket)]() mutable - { - return echo(std::move(socket)); - }, - boost::asio::detached); + boost::asio::co_spawn(executor, echo(std::move(socket)), boost::asio::detached); // ... @@ -46,10 +41,12 @@ execute. For example, a server's per-client object may consist of multiple coroutines; they should all run on the same `strand` so that no explicit synchronisation is required. -The second argument is a nullary function object that returns a [link -boost_asio.reference.awaitable `boost::asio::awaitable`], -where `R` is the type of return value produced by the coroutine. In the above -example, the coroutine returns `void`. +The second argument is an [link boost_asio.reference.awaitable `awaitable`], +that is the result of the coroutine's entry point function, and in the above +example is the result of the call to `echo`. (Alternatively, this argument can +be a function object that returns the [link boost_asio.reference.awaitable +`awaitable`].) The template parameter `R` is the type of return value +produced by the coroutine. In the above example, the coroutine returns `void`. The third argument is a completion token, and this is used by `co_spawn()` to produce a completion handler with signature `void(std::exception_ptr, R)`. This diff --git a/doc/reference.xsl b/doc/reference.xsl index 055f7183..d74a4da3 100644 --- a/doc/reference.xsl +++ b/doc/reference.xsl @@ -1492,6 +1492,9 @@ + + + diff --git a/example/cpp17/coroutines_ts/chat_server.cpp b/example/cpp17/coroutines_ts/chat_server.cpp index e233e9d6..8803be57 100644 --- a/example/cpp17/coroutines_ts/chat_server.cpp +++ b/example/cpp17/coroutines_ts/chat_server.cpp @@ -204,10 +204,7 @@ int main(int argc, char* argv[]) { unsigned short port = std::atoi(argv[i]); co_spawn(io_context, - [&io_context, port] - { - return listener(tcp::acceptor(io_context, {tcp::v4(), port})); - }, + listener(tcp::acceptor(io_context, {tcp::v4(), port})), detached); } diff --git a/example/cpp17/coroutines_ts/echo_server.cpp b/example/cpp17/coroutines_ts/echo_server.cpp index 01cf3807..ed42fa57 100644 --- a/example/cpp17/coroutines_ts/echo_server.cpp +++ b/example/cpp17/coroutines_ts/echo_server.cpp @@ -52,12 +52,7 @@ awaitable listener() for (;;) { tcp::socket socket = co_await acceptor.async_accept(use_awaitable); - co_spawn(executor, - [socket = std::move(socket)]() mutable - { - return echo(std::move(socket)); - }, - detached); + co_spawn(executor, echo(std::move(socket)), detached); } } @@ -70,7 +65,7 @@ int main() boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); signals.async_wait([&](auto, auto){ io_context.stop(); }); - co_spawn(io_context, listener, detached); + co_spawn(io_context, listener(), detached); io_context.run(); } diff --git a/example/cpp17/coroutines_ts/echo_server_with_default.cpp b/example/cpp17/coroutines_ts/echo_server_with_default.cpp index a34f8bf5..9ded4846 100644 --- a/example/cpp17/coroutines_ts/echo_server_with_default.cpp +++ b/example/cpp17/coroutines_ts/echo_server_with_default.cpp @@ -49,12 +49,7 @@ awaitable listener() for (;;) { auto socket = co_await acceptor.async_accept(); - co_spawn(executor, - [socket = std::move(socket)]() mutable - { - return echo(std::move(socket)); - }, - detached); + co_spawn(executor, echo(std::move(socket)), detached); } } @@ -67,7 +62,7 @@ int main() boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); signals.async_wait([&](auto, auto){ io_context.stop(); }); - co_spawn(io_context, listener, detached); + co_spawn(io_context, listener(), detached); io_context.run(); } diff --git a/example/cpp17/coroutines_ts/range_based_for.cpp b/example/cpp17/coroutines_ts/range_based_for.cpp index 477349ae..210e0525 100644 --- a/example/cpp17/coroutines_ts/range_based_for.cpp +++ b/example/cpp17/coroutines_ts/range_based_for.cpp @@ -91,12 +91,7 @@ int main() signals.async_wait([&](auto, auto){ io_context.stop(); }); tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); - co_spawn(io_context, - [acceptor = std::move(acceptor)]() mutable - { - return listener(std::move(acceptor)); - }, - detached); + co_spawn(io_context, listener(std::move(acceptor)), detached); io_context.run(); } diff --git a/example/cpp17/coroutines_ts/refactored_echo_server.cpp b/example/cpp17/coroutines_ts/refactored_echo_server.cpp index 062efc16..8ef0a274 100644 --- a/example/cpp17/coroutines_ts/refactored_echo_server.cpp +++ b/example/cpp17/coroutines_ts/refactored_echo_server.cpp @@ -56,12 +56,7 @@ awaitable listener() for (;;) { tcp::socket socket = co_await acceptor.async_accept(use_awaitable); - co_spawn(executor, - [socket = std::move(socket)]() mutable - { - return echo(std::move(socket)); - }, - detached); + co_spawn(executor, echo(std::move(socket)), detached); } } @@ -74,7 +69,7 @@ int main() boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); signals.async_wait([&](auto, auto){ io_context.stop(); }); - co_spawn(io_context, listener, detached); + co_spawn(io_context, listener(), detached); io_context.run(); } diff --git a/include/boost/asio/co_spawn.hpp b/include/boost/asio/co_spawn.hpp index 991fe252..b19ead5c 100644 --- a/include/boost/asio/co_spawn.hpp +++ b/include/boost/asio/co_spawn.hpp @@ -46,13 +46,321 @@ struct awaitable_signature> } // namespace detail -/// Spawn a new thread of execution. +/// Spawn a new coroutined-based thread of execution. /** - * The entry point function object @c f must have the signature: + * @param ex The executor that will be used to schedule the new thread of + * execution. * - * @code awaitable f(); @endcode + * @param a The boost::asio::awaitable object that is the result of calling the + * coroutine's entry point function. * - * where @c E is convertible from @c Executor. + * @param token The completion token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr, T); @endcode + * + * @par Example + * @code + * boost::asio::awaitable echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * boost::asio::buffer(data), boost::asio::use_awaitable); + * + * co_await boost::asio::async_write(socket, + * boost::asio::buffer(data, n), boost::asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * boost::asio::co_spawn(my_executor, + * echo(std::move(my_tcp_socket)), + * [](std::exception_ptr e, std::size_t n) + * { + * std::cout << "transferred " << n << "\n"; + * }); + * @endcode + */ +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(const Executor& ex, awaitable a, + CompletionToken&& token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename enable_if< + is_executor::value + && is_convertible::value + >::type* = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ex The executor that will be used to schedule the new thread of + * execution. + * + * @param a The boost::asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The completion token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr); @endcode + * + * @par Example + * @code + * boost::asio::awaitable echo(tcp::socket socket) + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * boost::asio::buffer(data), boost::asio::use_awaitable); + * + * co_await boost::asio::async_write(socket, + * boost::asio::buffer(data, n), boost::asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * } + * + * // ... + * + * boost::asio::co_spawn(my_executor, + * echo(std::move(my_tcp_socket)), + * boost::asio::detached); + * @endcode + */ +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(const Executor& ex, awaitable a, + CompletionToken&& token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), + typename enable_if< + is_executor::value + && is_convertible::value + >::type* = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ex An execution context that will provide the executor to be used to + * schedule the new thread of execution. + * + * @param a The boost::asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The completion token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr); @endcode + * + * @par Example + * @code + * boost::asio::awaitable echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * boost::asio::buffer(data), boost::asio::use_awaitable); + * + * co_await boost::asio::async_write(socket, + * boost::asio::buffer(data, n), boost::asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * boost::asio::co_spawn(my_io_context, + * echo(std::move(my_tcp_socket)), + * [](std::exception_ptr e, std::size_t n) + * { + * std::cout << "transferred " << n << "\n"; + * }); + * @endcode + */ +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(ExecutionContext& ctx, awaitable a, + CompletionToken&& token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), + typename enable_if< + is_convertible::value + && is_convertible::value + >::type* = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ex An execution context that will provide the executor to be used to + * schedule the new thread of execution. + * + * @param a The boost::asio::awaitable object that is the result of calling the + * coroutine's entry point function. + * + * @param token The completion token that will handle the notification that + * the thread of execution has completed. The function signature of the + * completion handler must be: + * @code void handler(std::exception_ptr); @endcode + * + * @par Example + * @code + * boost::asio::awaitable echo(tcp::socket socket) + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * boost::asio::buffer(data), boost::asio::use_awaitable); + * + * co_await boost::asio::async_write(socket, + * boost::asio::buffer(data, n), boost::asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * } + * + * // ... + * + * boost::asio::co_spawn(my_io_context, + * echo(std::move(my_tcp_socket)), + * boost::asio::detached); + * @endcode + */ +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(ExecutionContext& ctx, awaitable a, + CompletionToken&& token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), + typename enable_if< + is_convertible::value + && is_convertible::value + >::type* = 0); + +/// Spawn a new coroutined-based thread of execution. +/** + * @param ex The executor that will be used to schedule the new thread of + * execution. + * + * @param f A nullary function object with a return type of the form + * @c boost::asio::awaitable that will be used as the coroutine's entry + * point. + * + * @param token The completion token that will handle the notification that the + * thread of execution has completed. If @c R is @c void, the function + * signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * + * @par Example + * @code + * boost::asio::awaitable echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * boost::asio::buffer(data), boost::asio::use_awaitable); + * + * co_await boost::asio::async_write(socket, + * boost::asio::buffer(data, n), boost::asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * boost::asio::co_spawn(my_executor, + * [socket = std::move(my_tcp_socket)]() mutable + * -> boost::asio::awaitable + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * boost::asio::buffer(data), boost::asio::use_awaitable); + * + * co_await boost::asio::async_write(socket, + * boost::asio::buffer(data, n), boost::asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * }, boost::asio::detached); + * @endcode */ template ::value >::type* = 0); -/// Spawn a new thread of execution. +/// Spawn a new coroutined-based thread of execution. /** - * The entry point function object @c f must have the signature: + * @param ex An execution context that will provide the executor to be used to + * schedule the new thread of execution. * - * @code awaitable f(); @endcode + * @param f A nullary function object with a return type of the form + * @c boost::asio::awaitable that will be used as the coroutine's entry + * point. * - * where @c E is convertible from @c ExecutionContext::executor_type. + * @param token The completion token that will handle the notification that the + * thread of execution has completed. If @c R is @c void, the function + * signature of the completion handler must be: + * + * @code void handler(std::exception_ptr); @endcode + * Otherwise, the function signature of the completion handler must be: + * @code void handler(std::exception_ptr, R); @endcode + * + * + * @par Example + * @code + * boost::asio::awaitable echo(tcp::socket socket) + * { + * std::size_t bytes_transferred = 0; + * + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * boost::asio::buffer(data), boost::asio::use_awaitable); + * + * co_await boost::asio::async_write(socket, + * boost::asio::buffer(data, n), boost::asio::use_awaitable); + * + * bytes_transferred += n; + * } + * } + * catch (const std::exception&) + * { + * } + * + * co_return bytes_transferred; + * } + * + * // ... + * + * boost::asio::co_spawn(my_io_context, + * [socket = std::move(my_tcp_socket)]() mutable + * -> boost::asio::awaitable + * { + * try + * { + * char data[1024]; + * for (;;) + * { + * std::size_t n = co_await socket.async_read_some( + * boost::asio::buffer(data), boost::asio::use_awaitable); + * + * co_await boost::asio::async_write(socket, + * boost::asio::buffer(data, n), boost::asio::use_awaitable); + * } + * } + * catch (const std::exception& e) + * { + * std::cerr << "Exception: " << e.what() << "\n"; + * } + * }, boost::asio::detached); + * @endcode */ template co_spawn_entry_point( }); } +template +class awaitable_as_function +{ +public: + explicit awaitable_as_function(awaitable&& a) + : awaitable_(std::move(a)) + { + } + + awaitable operator()() + { + return std::move(awaitable_); + } + +private: + awaitable awaitable_; +}; + template class initiate_co_spawn { @@ -123,6 +141,75 @@ private: } // namespace detail +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(const Executor& ex, + awaitable a, CompletionToken&& token, + typename enable_if< + is_executor::value + && is_convertible::value + >::type*) +{ + return async_initiate( + detail::initiate_co_spawn(AwaitableExecutor(ex)), + token, detail::awaitable_as_function(std::move(a))); +} + +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(const Executor& ex, + awaitable a, CompletionToken&& token, + typename enable_if< + is_executor::value + && is_convertible::value + >::type*) +{ + return async_initiate( + detail::initiate_co_spawn(AwaitableExecutor(ex)), + token, detail::awaitable_as_function< + void, AwaitableExecutor>(std::move(a))); +} + +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr, T)) +co_spawn(ExecutionContext& ctx, + awaitable a, CompletionToken&& token, + typename enable_if< + is_convertible::value + && is_convertible::value + >::type*) +{ + return (co_spawn)(ctx.get_executor(), std::move(a), + std::forward(token)); +} + +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( + CompletionToken, void(std::exception_ptr)) +co_spawn(ExecutionContext& ctx, + awaitable a, CompletionToken&& token, + typename enable_if< + is_convertible::value + && is_convertible::value + >::type*) +{ + return (co_spawn)(ctx.get_executor(), std::move(a), + std::forward(token)); +} + template ::type>::type) CompletionToken> From e9f85a08e192c2e061d60ffea997c420df857cc8 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:49:47 +1000 Subject: [PATCH 14/90] Add converting constructor to use_awaitable_t::executor_with_default. --- include/boost/asio/use_awaitable.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/boost/asio/use_awaitable.hpp b/include/boost/asio/use_awaitable.hpp index 5a08098a..a522f74f 100644 --- a/include/boost/asio/use_awaitable.hpp +++ b/include/boost/asio/use_awaitable.hpp @@ -104,6 +104,17 @@ struct use_awaitable_t : InnerExecutor(ex) { } + + /// Convert the specified executor to the inner executor type, then use + /// that to construct the adapted executor. + template + executor_with_default(const OtherExecutor& ex, + typename enable_if< + is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT + : InnerExecutor(ex) + { + } }; /// Type alias to adapt an I/O object to use @c use_awaitable_t as its From 619cd04dbf1817bebe4c17654fcfb7ae08a88329 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:50:05 +1000 Subject: [PATCH 15/90] Add converting move construction and assignment to basic_waitable_timer. This change enables move construction and assignment between different timer types, provided the executor types are convertible. For example: basic_waitable_timer< clock_type, traits_type, io_context::executor_type > timer1(my_io_context); basic_waitable_timer< clock_type, traits_type, executor // polymorphic wrapper > timer2(std::move(timer1)); --- include/boost/asio/basic_waitable_timer.hpp | 48 +++++++++++++++++++ .../asio/detail/deadline_timer_service.hpp | 19 +++++++- test/system_timer.cpp | 29 +++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/include/boost/asio/basic_waitable_timer.hpp b/include/boost/asio/basic_waitable_timer.hpp index cd84f88c..d2e7cd97 100644 --- a/include/boost/asio/basic_waitable_timer.hpp +++ b/include/boost/asio/basic_waitable_timer.hpp @@ -319,6 +319,54 @@ public: impl_ = std::move(other.impl_); return *this; } + + // All timers have access to each other's implementations. + template + friend class basic_waitable_timer; + + /// Move-construct a basic_waitable_timer from another. + /** + * This constructor moves a timer from one object to another. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. + */ + template + basic_waitable_timer( + basic_waitable_timer&& other, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_waitable_timer from another. + /** + * This assignment operator moves a timer from one object to another. Cancels + * any outstanding asynchronous operations associated with the target object. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. + */ + template + typename enable_if< + is_convertible::value, + basic_waitable_timer& + >::type operator=(basic_waitable_timer&& other) + { + basic_waitable_timer tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; + } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destroys the timer. diff --git a/include/boost/asio/detail/deadline_timer_service.hpp b/include/boost/asio/detail/deadline_timer_service.hpp index 0fe58c8b..02bf13ac 100644 --- a/include/boost/asio/detail/deadline_timer_service.hpp +++ b/include/boost/asio/detail/deadline_timer_service.hpp @@ -98,7 +98,7 @@ public: cancel(impl, ec); } - // Move-construct a new serial port implementation. + // Move-construct a new timer implementation. void move_construct(implementation_type& impl, implementation_type& other_impl) { @@ -111,7 +111,7 @@ public: other_impl.might_have_pending_waits = false; } - // Move-assign from another serial port implementation. + // Move-assign from another timer implementation. void move_assign(implementation_type& impl, deadline_timer_service& other_service, implementation_type& other_impl) @@ -130,6 +130,21 @@ public: other_impl.might_have_pending_waits = false; } + // Move-construct a new timer implementation. + void converting_move_construct(implementation_type& impl, + deadline_timer_service&, implementation_type& other_impl) + { + move_construct(impl, other_impl); + } + + // Move-assign from another timer implementation. + void converting_move_assign(implementation_type& impl, + deadline_timer_service& other_service, + implementation_type& other_impl) + { + move_assign(impl, other_service, other_impl); + } + // Cancel any asynchronous wait operations associated with the timer. std::size_t cancel(implementation_type& impl, boost::system::error_code& ec) { diff --git a/test/system_timer.cpp b/test/system_timer.cpp index 88755bff..f81fdaf0 100644 --- a/test/system_timer.cpp +++ b/test/system_timer.cpp @@ -356,6 +356,19 @@ boost::asio::system_timer make_timer(boost::asio::io_context& ioc, int* count) t.async_wait(bindns::bind(increment, count)); return t; } + +typedef boost::asio::basic_waitable_timer< + boost::asio::system_timer::clock_type, + boost::asio::system_timer::traits_type, + boost::asio::io_context::executor_type> io_context_system_timer; + +io_context_system_timer make_convertible_timer(boost::asio::io_context& ioc, int* count) +{ + io_context_system_timer t(ioc); + t.expires_after(boost::asio::chrono::seconds(1)); + t.async_wait(bindns::bind(increment, count)); + return t; +} #endif void system_timer_move_test() @@ -378,6 +391,22 @@ void system_timer_move_test() io_context1.run(); BOOST_ASIO_CHECK(count == 2); + + boost::asio::system_timer t4 = make_convertible_timer(io_context1, &count); + boost::asio::system_timer t5 = make_convertible_timer(io_context2, &count); + boost::asio::system_timer t6 = std::move(t4); + + t2 = std::move(t4); + + io_context2.restart(); + io_context2.run(); + + BOOST_ASIO_CHECK(count == 3); + + io_context1.restart(); + io_context1.run(); + + BOOST_ASIO_CHECK(count == 4); #endif // defined(BOOST_ASIO_HAS_MOVE) } From bab4f248b4b823a598d4e220d68410c313bb161b Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:50:27 +1000 Subject: [PATCH 16/90] Add as_default_on() and as_default_on_t<> to asio::detached_t. --- include/boost/asio/detached.hpp | 50 +++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/boost/asio/detached.hpp b/include/boost/asio/detached.hpp index c84d954f..7f384a4e 100644 --- a/include/boost/asio/detached.hpp +++ b/include/boost/asio/detached.hpp @@ -17,6 +17,7 @@ #include #include +#include #include @@ -42,6 +43,55 @@ public: BOOST_ASIO_CONSTEXPR detached_t() { } + + /// Adapts an executor to add the @c detached_t completion token as the + /// default. + template + struct executor_with_default : InnerExecutor + { + /// Specify @c detached_t as the default completion token type. + typedef detached_t default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + executor_with_default(const InnerExecutor& ex) BOOST_ASIO_NOEXCEPT + : InnerExecutor(ex) + { + } + + /// Convert the specified executor to the inner executor type, then use + /// that to construct the adapted executor. + template + executor_with_default(const OtherExecutor& ex, + typename enable_if< + is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT + : InnerExecutor(ex) + { + } + }; + + /// Type alias to adapt an I/O object to use @c detached_t as its + /// default completion token type. +#if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + template + using as_default_on_t = typename T::template rebind_executor< + executor_with_default >::other; +#endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + + /// Function helper to adapt an I/O object to use @c detached_t as its + /// default completion token type. + template + static typename decay::type::template rebind_executor< + executor_with_default::type::executor_type> + >::other + as_default_on(BOOST_ASIO_MOVE_ARG(T) object) + { + return typename decay::type::template rebind_executor< + executor_with_default::type::executor_type> + >::other(BOOST_ASIO_MOVE_CAST(T)(object)); + } }; /// A special value, similar to std::nothrow. From 7709723129c2bdba2c2652d0efa82f29544e7266 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:50:53 +1000 Subject: [PATCH 17/90] Correctly stop "own thread" in service destructor. This change fixes the scheduler and win_iocp_io_context destructors so that they correctly stop the internal thread that was created in the constructor. This fixes a deadlock that can occur when two threads concurrently attempt to create the first I/O object associated with a non-native I/O execution context. --- include/boost/asio/detail/impl/scheduler.ipp | 4 ++++ include/boost/asio/detail/impl/win_iocp_io_context.ipp | 1 + 2 files changed, 5 insertions(+) diff --git a/include/boost/asio/detail/impl/scheduler.ipp b/include/boost/asio/detail/impl/scheduler.ipp index 8ef69856..4d1d09f5 100644 --- a/include/boost/asio/detail/impl/scheduler.ipp +++ b/include/boost/asio/detail/impl/scheduler.ipp @@ -136,6 +136,10 @@ scheduler::~scheduler() { if (thread_) { + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_all_threads(lock); + lock.unlock(); thread_->join(); delete thread_; } diff --git a/include/boost/asio/detail/impl/win_iocp_io_context.ipp b/include/boost/asio/detail/impl/win_iocp_io_context.ipp index 55f18586..ff7e23cf 100644 --- a/include/boost/asio/detail/impl/win_iocp_io_context.ipp +++ b/include/boost/asio/detail/impl/win_iocp_io_context.ipp @@ -114,6 +114,7 @@ win_iocp_io_context::~win_iocp_io_context() { if (thread_.get()) { + stop(); thread_->join(); thread_.reset(); } From 68b195d028d9f4dc9b69d93be0d26f2f9c932ce2 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:51:06 +1000 Subject: [PATCH 18/90] Remove spurious 'Executor' base class from executor_binder implementation. --- include/boost/asio/bind_executor.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/boost/asio/bind_executor.hpp b/include/boost/asio/bind_executor.hpp index 69683a93..3a78ee17 100644 --- a/include/boost/asio/bind_executor.hpp +++ b/include/boost/asio/bind_executor.hpp @@ -155,16 +155,14 @@ struct executor_binder_argument_type typedef A2 second_argument_type; }; -// Helper to: -// - Apply the empty base optimisation to the executor. -// - Perform uses_executor construction of the target type, if required. +// Helper to perform uses_executor construction of the target type, if +// required. template class executor_binder_base; template class executor_binder_base - : protected Executor { protected: template From 38dabd1399dce2814cbee620dd909656ef91ddb9 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:51:22 +1000 Subject: [PATCH 19/90] Fix parameter names in co_spawn documentation. --- include/boost/asio/co_spawn.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/asio/co_spawn.hpp b/include/boost/asio/co_spawn.hpp index b19ead5c..b1923e59 100644 --- a/include/boost/asio/co_spawn.hpp +++ b/include/boost/asio/co_spawn.hpp @@ -168,7 +168,7 @@ co_spawn(const Executor& ex, awaitable a, /// Spawn a new coroutined-based thread of execution. /** - * @param ex An execution context that will provide the executor to be used to + * @param ctx An execution context that will provide the executor to be used to * schedule the new thread of execution. * * @param a The boost::asio::awaitable object that is the result of calling the @@ -235,7 +235,7 @@ co_spawn(ExecutionContext& ctx, awaitable a, /// Spawn a new coroutined-based thread of execution. /** - * @param ex An execution context that will provide the executor to be used to + * @param ctx An execution context that will provide the executor to be used to * schedule the new thread of execution. * * @param a The boost::asio::awaitable object that is the result of calling the @@ -377,7 +377,7 @@ co_spawn(const Executor& ex, F&& f, /// Spawn a new coroutined-based thread of execution. /** - * @param ex An execution context that will provide the executor to be used to + * @param ctx An execution context that will provide the executor to be used to * schedule the new thread of execution. * * @param f A nullary function object with a return type of the form From f34dd4cf2bf79240ebc336a41f1ac28c33f13d9d Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:55:57 +1000 Subject: [PATCH 20/90] Add unit test for thread_pool. --- test/Jamfile.v2 | 2 + test/thread_pool.cpp | 166 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 test/thread_pool.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a9835751..b68717e2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -190,6 +190,8 @@ test-suite "asio" : [ link system_executor.cpp : $(USE_SELECT) : system_executor_select ] [ link this_coro.cpp ] [ link this_coro.cpp : $(USE_SELECT) : this_coro_select ] + [ link thread_pool.cpp ] + [ link thread_pool.cpp : $(USE_SELECT) : thread_pool_select ] [ link time_traits.cpp ] [ link time_traits.cpp : $(USE_SELECT) : time_traits_select ] [ link ts/buffer.cpp : : ts_buffer ] diff --git a/test/thread_pool.cpp b/test/thread_pool.cpp new file mode 100644 index 00000000..7bf036f0 --- /dev/null +++ b/test/thread_pool.cpp @@ -0,0 +1,166 @@ +// +// thread_pool.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +using namespace boost::asio; + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif + +void increment(int* count) +{ + ++(*count); +} + +void decrement_to_zero(thread_pool* pool, int* count) +{ + if (*count > 0) + { + --(*count); + + int before_value = *count; + boost::asio::post(*pool, bindns::bind(decrement_to_zero, pool, count)); + + // Handler execution cannot nest, so count value should remain unchanged. + BOOST_ASIO_CHECK(*count == before_value); + } +} + +void nested_decrement_to_zero(thread_pool* pool, int* count) +{ + if (*count > 0) + { + --(*count); + + boost::asio::dispatch(*pool, + bindns::bind(nested_decrement_to_zero, pool, count)); + + // Handler execution is nested, so count value should now be zero. + BOOST_ASIO_CHECK(*count == 0); + } +} + +void thread_pool_test() +{ + thread_pool pool(1); + + int count1 = 0; + boost::asio::post(pool, bindns::bind(increment, &count1)); + + int count2 = 10; + boost::asio::post(pool, bindns::bind(decrement_to_zero, &pool, &count2)); + + int count3 = 10; + boost::asio::post(pool, bindns::bind(nested_decrement_to_zero, &pool, &count3)); + + pool.join(); + + BOOST_ASIO_CHECK(count1 == 1); + BOOST_ASIO_CHECK(count2 == 0); + BOOST_ASIO_CHECK(count3 == 0); +} + +class test_service : public boost::asio::execution_context::service +{ +public: + typedef test_service key_type; + + test_service(boost::asio::execution_context& ctx) + : boost::asio::execution_context::service(ctx) + { + } + +private: + virtual void shutdown() {} +}; + +void thread_pool_service_test() +{ + boost::asio::thread_pool pool1(1); + boost::asio::thread_pool pool2(1); + boost::asio::thread_pool pool3(1); + + // Implicit service registration. + + boost::asio::use_service(pool1); + + BOOST_ASIO_CHECK(boost::asio::has_service(pool1)); + + test_service* svc1 = new test_service(pool1); + try + { + boost::asio::add_service(pool1, svc1); + BOOST_ASIO_ERROR("add_service did not throw"); + } + catch (boost::asio::service_already_exists&) + { + } + delete svc1; + + // Explicit service registration. + + test_service& svc2 = boost::asio::make_service(pool2); + + BOOST_ASIO_CHECK(boost::asio::has_service(pool2)); + BOOST_ASIO_CHECK(&boost::asio::use_service(pool2) == &svc2); + + test_service* svc3 = new test_service(pool2); + try + { + boost::asio::add_service(pool2, svc3); + BOOST_ASIO_ERROR("add_service did not throw"); + } + catch (boost::asio::service_already_exists&) + { + } + delete svc3; + + // Explicit registration with invalid owner. + + test_service* svc4 = new test_service(pool2); + try + { + boost::asio::add_service(pool3, svc4); + BOOST_ASIO_ERROR("add_service did not throw"); + } + catch (boost::asio::invalid_service_owner&) + { + } + delete svc4; + + BOOST_ASIO_CHECK(!boost::asio::has_service(pool3)); +} + +BOOST_ASIO_TEST_SUITE +( + "thread_pool", + BOOST_ASIO_TEST_CASE(thread_pool_test) + BOOST_ASIO_TEST_CASE(thread_pool_service_test) +) From eb720ce9048e3ff5fc32c71fdfc7d7f055c61184 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:58:01 +1000 Subject: [PATCH 21/90] Changes for clang-based Embarcadero C++ compilers. --- include/boost/asio/buffer.hpp | 10 ++++++---- include/boost/asio/detail/config.hpp | 10 +++++----- include/boost/asio/detail/pop_options.hpp | 2 +- include/boost/asio/detail/push_options.hpp | 2 +- include/boost/asio/impl/src.cpp | 2 +- test/unit_test.hpp | 4 ++-- 6 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/boost/asio/buffer.hpp b/include/boost/asio/buffer.hpp index 90e10ed0..59418f26 100644 --- a/include/boost/asio/buffer.hpp +++ b/include/boost/asio/buffer.hpp @@ -50,11 +50,13 @@ #if defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) # include -# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ - || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +# if !defined(__clang__) +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) +# define BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND +# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) +# elif BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) # define BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND -# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) - // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +# endif // BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) #endif // defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) #if defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp index bff69672..8ec20741 100644 --- a/include/boost/asio/detail/config.hpp +++ b/include/boost/asio/detail/config.hpp @@ -1001,17 +1001,17 @@ // Windows: target OS version. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) # if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) -# if defined(_MSC_VER) || defined(__BORLANDC__) +# if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) # pragma message( \ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\ "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\ "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).") -# else // defined(_MSC_VER) || defined(__BORLANDC__) +# else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) # warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. # warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line. # warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target). -# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) # define _WIN32_WINNT 0x0601 # endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) # if defined(_MSC_VER) @@ -1410,9 +1410,9 @@ # if (__GNUC__ >= 3) # define BOOST_ASIO_HAS_HANDLER_HOOKS 1 # endif // (__GNUC__ >= 3) -# elif !defined(__BORLANDC__) +# elif !defined(__BORLANDC__) || defined(__clang__) # define BOOST_ASIO_HAS_HANDLER_HOOKS 1 -# endif // !defined(__BORLANDC__) +# endif // !defined(__BORLANDC__) || defined(__clang__) # endif // !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) #endif // !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) diff --git a/include/boost/asio/detail/pop_options.hpp b/include/boost/asio/detail/pop_options.hpp index a2475b47..982c42e4 100644 --- a/include/boost/asio/detail/pop_options.hpp +++ b/include/boost/asio/detail/pop_options.hpp @@ -93,7 +93,7 @@ // Greenhills C++ -#elif defined(__BORLANDC__) +#elif defined(__BORLANDC__) && !defined(__clang__) // Borland C++ diff --git a/include/boost/asio/detail/push_options.hpp b/include/boost/asio/detail/push_options.hpp index 05856fd9..201f18a0 100644 --- a/include/boost/asio/detail/push_options.hpp +++ b/include/boost/asio/detail/push_options.hpp @@ -102,7 +102,7 @@ // Greenhills C++ -#elif defined(__BORLANDC__) +#elif defined(__BORLANDC__) && !defined(__clang__) // Borland C++ diff --git a/include/boost/asio/impl/src.cpp b/include/boost/asio/impl/src.cpp index a44d3877..0ea3601e 100644 --- a/include/boost/asio/impl/src.cpp +++ b/include/boost/asio/impl/src.cpp @@ -9,7 +9,7 @@ // #if defined(_MSC_VER) \ - || defined(__BORLANDC__) \ + || (defined(__BORLANDC__) && !defined(__clang__)) \ || defined(__DMC__) # pragma message ( \ "This file is deprecated. " \ diff --git a/test/unit_test.hpp b/test/unit_test.hpp index 6d5a7847..126f53af 100644 --- a/test/unit_test.hpp +++ b/test/unit_test.hpp @@ -19,7 +19,7 @@ # include // Needed for lrand48. #endif // defined(__sun) -#if defined(__BORLANDC__) +#if defined(__BORLANDC__) && !defined(__clang__) // Prevent use of intrinsic for strcmp. # include @@ -28,7 +28,7 @@ // Suppress error about condition always being true. # pragma option -w-ccc -#endif // defined(__BORLANDC__) +#endif // defined(__BORLANDC__) && !defined(__clang__) #if defined(BOOST_ASIO_MSVC) # pragma warning (disable:4127) From 92f9cd896770abc18f0b453e0db60435e48b0b9d Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:58:16 +1000 Subject: [PATCH 22/90] Fix examples in read_until() documentation. --- include/boost/asio/read_until.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/asio/read_until.hpp b/include/boost/asio/read_until.hpp index dec8d4aa..1c204637 100644 --- a/include/boost/asio/read_until.hpp +++ b/include/boost/asio/read_until.hpp @@ -115,7 +115,7 @@ struct is_match_condition * @par Example * To read data into a @c std::string until a newline is encountered: * @code std::string data; - * std::string n = boost::asio::read_until(s, + * std::size_t n = boost::asio::read_until(s, * boost::asio::dynamic_buffer(data), '\n'); * std::string line = data.substr(0, n); * data.erase(0, n); @endcode @@ -217,7 +217,7 @@ std::size_t read_until(SyncReadStream& s, * @par Example * To read data into a @c std::string until a CR-LF sequence is encountered: * @code std::string data; - * std::string n = boost::asio::read_until(s, + * std::size_t n = boost::asio::read_until(s, * boost::asio::dynamic_buffer(data), "\r\n"); * std::string line = data.substr(0, n); * data.erase(0, n); @endcode @@ -328,7 +328,7 @@ std::size_t read_until(SyncReadStream& s, * @par Example * To read data into a @c std::string until a CR-LF sequence is encountered: * @code std::string data; - * std::string n = boost::asio::read_until(s, + * std::size_t n = boost::asio::read_until(s, * boost::asio::dynamic_buffer(data), boost::regex("\r\n")); * std::string line = data.substr(0, n); * data.erase(0, n); @endcode @@ -1056,7 +1056,7 @@ std::size_t read_until(SyncReadStream& s, * @par Example * To read data into a @c std::string until a newline is encountered: * @code std::string data; - * std::string n = boost::asio::read_until(s, + * std::size_t n = boost::asio::read_until(s, * boost::asio::dynamic_buffer(data), '\n'); * std::string line = data.substr(0, n); * data.erase(0, n); @endcode @@ -1154,7 +1154,7 @@ std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, * @par Example * To read data into a @c std::string until a CR-LF sequence is encountered: * @code std::string data; - * std::string n = boost::asio::read_until(s, + * std::size_t n = boost::asio::read_until(s, * boost::asio::dynamic_buffer(data), "\r\n"); * std::string line = data.substr(0, n); * data.erase(0, n); @endcode @@ -1260,7 +1260,7 @@ std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, * @par Example * To read data into a @c std::string until a CR-LF sequence is encountered: * @code std::string data; - * std::string n = boost::asio::read_until(s, + * std::size_t n = boost::asio::read_until(s, * boost::asio::dynamic_buffer(data), boost::regex("\r\n")); * std::string line = data.substr(0, n); * data.erase(0, n); @endcode From 26213d8a00a1b7bb066019138289c8d50b31ed03 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:58:35 +1000 Subject: [PATCH 23/90] Another tutorial fix to reflect current resolver API. --- example/cpp03/tutorial/daytime_dox.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/example/cpp03/tutorial/daytime_dox.txt b/example/cpp03/tutorial/daytime_dox.txt index 5ec49c67..ea2d8ca2 100644 --- a/example/cpp03/tutorial/daytime_dox.txt +++ b/example/cpp03/tutorial/daytime_dox.txt @@ -277,8 +277,6 @@ The boost::asio::ip::udp::resolver::resolve() function is guaranteed to return a least one endpoint in the list if it does not fail. This means it is safe to dereference the return value directly. -\until udp::endpoint - Since UDP is datagram-oriented, we will not be using a stream socket. Create an boost::asio::ip::udp::socket and initiate contact with the remote endpoint. From 0d81908cc0264bcb63ebe59c2861eec36b1bff1a Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:58:51 +1000 Subject: [PATCH 24/90] Update socks4 example to use non-deprecated resolver interface. --- example/cpp11/socks4/sync_client.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/example/cpp11/socks4/sync_client.cpp b/example/cpp11/socks4/sync_client.cpp index 1e8e6b71..2b2c4421 100644 --- a/example/cpp11/socks4/sync_client.cpp +++ b/example/cpp11/socks4/sync_client.cpp @@ -44,7 +44,8 @@ int main(int argc, char* argv[]) // Get an endpoint for the Boost website. This will be passed to the SOCKS // 4 server. Explicitly specify IPv4 since SOCKS 4 does not support IPv6. - auto http_endpoint = *resolver.resolve(tcp::v4(), "www.boost.org", "http"); + auto http_endpoint = + *resolver.resolve(tcp::v4(), "www.boost.org", "http").begin(); // Send the request to the SOCKS 4 server. socks4::request socks_request( From 98b3e502b89ef0b66e4497ebbb7fd3767b67c1d3 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 20:59:09 +1000 Subject: [PATCH 25/90] Mark the asio_handler_invoke hook as deprecated. Compiling an application with BOOST_ASIO_NO_DEPRECATED will now trigger a compile error if any handler implements the asio_handler_invoke hook. --- include/boost/asio/detail/bind_handler.hpp | 72 +++++++++++--- .../asio/detail/handler_invoke_helpers.hpp | 23 +++++ include/boost/asio/detail/wrapped_handler.hpp | 24 ++++- include/boost/asio/handler_invoke_hook.hpp | 32 ++++++- .../boost/asio/impl/buffered_read_stream.hpp | 24 ++++- .../boost/asio/impl/buffered_write_stream.hpp | 24 ++++- include/boost/asio/impl/compose.hpp | 12 ++- include/boost/asio/impl/connect.hpp | 24 ++++- include/boost/asio/impl/read.hpp | 36 +++++-- include/boost/asio/impl/read_at.hpp | 24 ++++- include/boost/asio/impl/read_until.hpp | 96 +++++++++++++++---- include/boost/asio/impl/redirect_error.hpp | 12 ++- include/boost/asio/impl/spawn.hpp | 24 ++++- include/boost/asio/impl/use_future.hpp | 8 ++ include/boost/asio/impl/write.hpp | 36 +++++-- include/boost/asio/impl/write_at.hpp | 24 ++++- include/boost/asio/ssl/detail/io.hpp | 12 ++- 17 files changed, 430 insertions(+), 77 deletions(-) diff --git a/include/boost/asio/detail/bind_handler.hpp b/include/boost/asio/detail/bind_handler.hpp index 3b610336..bdab95c4 100644 --- a/include/boost/asio/detail/bind_handler.hpp +++ b/include/boost/asio/detail/bind_handler.hpp @@ -100,19 +100,27 @@ inline bool asio_handler_is_continuation( } template -inline void asio_handler_invoke(Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, binder1* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(const Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, binder1* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -201,19 +209,27 @@ inline bool asio_handler_is_continuation( } template -inline void asio_handler_invoke(Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, binder2* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(const Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, binder2* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -309,20 +325,28 @@ inline bool asio_handler_is_continuation( template -inline void asio_handler_invoke(Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, binder3* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(const Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, binder3* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -429,20 +453,28 @@ inline bool asio_handler_is_continuation( template -inline void asio_handler_invoke(Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, binder4* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(const Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, binder4* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, binder5* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(const Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, binder5* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function, move_binder1* this_handler) { boost_asio_handler_invoke_helpers::invoke( BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -698,11 +742,15 @@ inline bool asio_handler_is_continuation( } template -inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function, move_binder2* this_handler) { boost_asio_handler_invoke_helpers::invoke( BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } #endif // defined(BOOST_ASIO_HAS_MOVE) diff --git a/include/boost/asio/detail/handler_invoke_helpers.hpp b/include/boost/asio/detail/handler_invoke_helpers.hpp index 79fc7674..35007e45 100644 --- a/include/boost/asio/detail/handler_invoke_helpers.hpp +++ b/include/boost/asio/detail/handler_invoke_helpers.hpp @@ -26,12 +26,29 @@ // namespace is defined here for that purpose. namespace boost_asio_handler_invoke_helpers { +#if defined(BOOST_ASIO_NO_DEPRECATED) +template +inline void error_if_hook_is_defined(Function& function, Context& context) +{ + using boost::asio::asio_handler_invoke; + // If you get an error here it is because some of your handlers still + // overload asio_handler_invoke, but this hook is no longer used. + (void)static_cast( + asio_handler_invoke(function, boost::asio::detail::addressof(context))); +} +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + template inline void invoke(Function& function, Context& context) { #if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) Function tmp(function); tmp(); +#elif defined(BOOST_ASIO_NO_DEPRECATED) + // The asio_handler_invoke hook is no longer used to invoke the function. + (void)&error_if_hook_is_defined; + (void)context; + function(); #else using boost::asio::asio_handler_invoke; asio_handler_invoke(function, boost::asio::detail::addressof(context)); @@ -44,6 +61,12 @@ inline void invoke(const Function& function, Context& context) #if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) Function tmp(function); tmp(); +#elif defined(BOOST_ASIO_NO_DEPRECATED) + // The asio_handler_invoke hook is no longer used to invoke the function. + (void)&error_if_hook_is_defined; + (void)context; + Function tmp(function); + tmp(); #else using boost::asio::asio_handler_invoke; asio_handler_invoke(function, boost::asio::detail::addressof(context)); diff --git a/include/boost/asio/detail/wrapped_handler.hpp b/include/boost/asio/detail/wrapped_handler.hpp index 49e7fe7d..81edf06e 100644 --- a/include/boost/asio/detail/wrapped_handler.hpp +++ b/include/boost/asio/detail/wrapped_handler.hpp @@ -226,22 +226,30 @@ inline bool asio_handler_is_continuation( template -inline void asio_handler_invoke(Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, wrapped_handler* this_handler) { this_handler->dispatcher_.dispatch( rewrapped_handler( function, this_handler->handler_)); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(const Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, wrapped_handler* this_handler) { this_handler->dispatcher_.dispatch( rewrapped_handler( function, this_handler->handler_)); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -269,19 +277,27 @@ inline bool asio_handler_is_continuation( } template -inline void asio_handler_invoke(Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, rewrapped_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->context_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(const Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, rewrapped_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->context_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } } // namespace detail diff --git a/include/boost/asio/handler_invoke_hook.hpp b/include/boost/asio/handler_invoke_hook.hpp index 74139dcb..4b4a4518 100644 --- a/include/boost/asio/handler_invoke_hook.hpp +++ b/include/boost/asio/handler_invoke_hook.hpp @@ -24,7 +24,8 @@ namespace asio { /** @defgroup asio_handler_invoke boost::asio::asio_handler_invoke * - * @brief Default invoke function for handlers. + * @brief (Deprecated: Use the associated_executor trait.) Default invoke + * function for handlers. * * Completion handlers for asynchronous operations are invoked by the * io_context associated with the corresponding object (e.g. a socket or @@ -62,19 +63,44 @@ namespace asio { */ /*@{*/ +#if defined(BOOST_ASIO_NO_DEPRECATED) + +// Places in asio that would have previously called the invocation hook to +// execute a handler, now call it only to check whether the result type is this +// type. If the result is not this type, it indicates that the user code still +// has the old hooks in place, and if so we want to trigger a compile error. +enum asio_handler_invoke_is_no_longer_used {}; + +typedef asio_handler_invoke_is_no_longer_used + asio_handler_invoke_is_deprecated; + +#else // defined(BOOST_ASIO_NO_DEPRECATED) + +typedef void asio_handler_invoke_is_deprecated; + +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + /// Default handler invocation hook used for non-const function objects. template -inline void asio_handler_invoke(Function& function, ...) +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, ...) { function(); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } /// Default handler invocation hook used for const function objects. template -inline void asio_handler_invoke(const Function& function, ...) +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, ...) { Function tmp(function); tmp(); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } /*@}*/ diff --git a/include/boost/asio/impl/buffered_read_stream.hpp b/include/boost/asio/impl/buffered_read_stream.hpp index f94c5111..3952e76e 100644 --- a/include/boost/asio/impl/buffered_read_stream.hpp +++ b/include/boost/asio/impl/buffered_read_stream.hpp @@ -126,19 +126,27 @@ namespace detail } template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, buffered_fill_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, buffered_fill_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -341,22 +349,30 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, buffered_read_some_handler< MutableBufferSequence, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, buffered_read_some_handler< MutableBufferSequence, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/buffered_write_stream.hpp b/include/boost/asio/impl/buffered_write_stream.hpp index 74095cb3..64e08804 100644 --- a/include/boost/asio/impl/buffered_write_stream.hpp +++ b/include/boost/asio/impl/buffered_write_stream.hpp @@ -111,19 +111,27 @@ namespace detail } template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, buffered_flush_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, buffered_flush_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -327,22 +335,30 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, buffered_write_some_handler< ConstBufferSequence, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, buffered_write_some_handler< ConstBufferSequence, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/compose.hpp b/include/boost/asio/impl/compose.hpp index 53b8b37a..892dd646 100644 --- a/include/boost/asio/impl/compose.hpp +++ b/include/boost/asio/impl/compose.hpp @@ -372,20 +372,28 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, composed_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, composed_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/connect.hpp b/include/boost/asio/impl/connect.hpp index 27fc66c0..4a62b3e3 100644 --- a/include/boost/asio/impl/connect.hpp +++ b/include/boost/asio/impl/connect.hpp @@ -439,23 +439,31 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, range_connect_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, range_connect_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -627,23 +635,31 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, iterator_connect_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, iterator_connect_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/read.hpp b/include/boost/asio/impl/read.hpp index 8c2eb4e2..c61e1906 100644 --- a/include/boost/asio/impl/read.hpp +++ b/include/boost/asio/impl/read.hpp @@ -425,23 +425,31 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_dynbuf_v1_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_dynbuf_v1_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -1004,23 +1020,31 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_dynbuf_v2_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_dynbuf_v2_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/read_at.hpp b/include/boost/asio/impl/read_at.hpp index e4ca93e5..a966563f 100644 --- a/include/boost/asio/impl/read_at.hpp +++ b/include/boost/asio/impl/read_at.hpp @@ -292,23 +292,31 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_at_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_at_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_at_streambuf_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_at_streambuf_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/read_until.hpp b/include/boost/asio/impl/read_until.hpp index 399eb5d0..cd84ff95 100644 --- a/include/boost/asio/impl/read_until.hpp +++ b/include/boost/asio/impl/read_until.hpp @@ -939,22 +939,30 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_until_delim_op_v1* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_until_delim_op_v1* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -1227,22 +1235,30 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_until_delim_string_op_v1* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_until_delim_string_op_v1* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -1523,22 +1539,30 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_until_expr_op_v1* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_until_expr_op_v1* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -1813,23 +1837,31 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_until_match_op_v1* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_until_match_op_v1* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -2166,22 +2198,30 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_until_delim_op_v2* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_until_delim_op_v2* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -2459,22 +2499,30 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_until_delim_string_op_v2* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_until_delim_string_op_v2* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -2762,22 +2810,30 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_until_expr_op_v2* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_until_expr_op_v2* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -3058,23 +3114,31 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, read_until_match_op_v2* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, read_until_match_op_v2* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/redirect_error.hpp b/include/boost/asio/impl/redirect_error.hpp index eb65e83d..1b06a854 100644 --- a/include/boost/asio/impl/redirect_error.hpp +++ b/include/boost/asio/impl/redirect_error.hpp @@ -150,19 +150,27 @@ inline bool asio_handler_is_continuation( } template -inline void asio_handler_invoke(Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, redirect_error_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(const Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, redirect_error_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/spawn.hpp b/include/boost/asio/impl/spawn.hpp index 3eef52c6..316ff556 100644 --- a/include/boost/asio/impl/spawn.hpp +++ b/include/boost/asio/impl/spawn.hpp @@ -132,19 +132,27 @@ namespace detail { } template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, coro_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, coro_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -359,19 +367,27 @@ namespace detail { }; template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, spawn_helper* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->data_->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, spawn_helper* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->data_->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } inline void default_spawn_handler() {} diff --git a/include/boost/asio/impl/use_future.hpp b/include/boost/asio/impl/use_future.hpp index 59de0b03..d4474482 100644 --- a/include/boost/asio/impl/use_future.hpp +++ b/include/boost/asio/impl/use_future.hpp @@ -608,6 +608,8 @@ private: Allocator allocator_; }; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + template inline void asio_handler_invoke(Function& f, promise_handler* h) @@ -626,6 +628,8 @@ inline void asio_handler_invoke(const Function& f, ex.dispatch(f, std::allocator()); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + // Helper base class for async_result specialisation. template class promise_async_result @@ -720,6 +724,8 @@ private: Allocator allocator_; }; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + template inline void asio_handler_invoke(Function& f, @@ -740,6 +746,8 @@ inline void asio_handler_invoke(const Function& f, ex.dispatch(f, std::allocator()); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + // Helper base class for async_result specialisation. template class packaged_async_result diff --git a/include/boost/asio/impl/write.hpp b/include/boost/asio/impl/write.hpp index 1b3f23c1..e423955e 100644 --- a/include/boost/asio/impl/write.hpp +++ b/include/boost/asio/impl/write.hpp @@ -390,23 +390,31 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, write_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, write_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, write_dynbuf_v1_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, write_dynbuf_v1_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -905,23 +921,31 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, write_dynbuf_v2_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, write_dynbuf_v2_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/write_at.hpp b/include/boost/asio/impl/write_at.hpp index 19d00d9b..b50c01cf 100644 --- a/include/boost/asio/impl/write_at.hpp +++ b/include/boost/asio/impl/write_at.hpp @@ -277,23 +277,31 @@ namespace detail template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, write_at_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, write_at_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(Function& function, write_at_streambuf_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_invoke(const Function& function, + inline asio_handler_invoke_is_deprecated + asio_handler_invoke(const Function& function, write_at_streambuf_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/ssl/detail/io.hpp b/include/boost/asio/ssl/detail/io.hpp index f024bdab..b69a4380 100644 --- a/include/boost/asio/ssl/detail/io.hpp +++ b/include/boost/asio/ssl/detail/io.hpp @@ -335,20 +335,28 @@ inline bool asio_handler_is_continuation( template -inline void asio_handler_invoke(Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(Function& function, io_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_invoke(const Function& function, +inline asio_handler_invoke_is_deprecated +asio_handler_invoke(const Function& function, io_op* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_invoke_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template From cb6b7e5f3c72daf4cd8a59a192d044d8937d8abe Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:00:02 +1000 Subject: [PATCH 26/90] Mark the asio_handler_allocate/deallocate hooks as deprecated. Compiling an application with BOOST_ASIO_NO_DEPRECATED will now trigger a compile error if any handler implements the asio_handler_allocate or asio_handler_deallocate hooks. --- include/boost/asio/detail/bind_handler.hpp | 98 ++++++++++++--- .../asio/detail/handler_alloc_helpers.hpp | 42 +++++++ include/boost/asio/detail/wrapped_handler.hpp | 30 ++++- include/boost/asio/handler_alloc_hook.hpp | 33 +++++- .../boost/asio/impl/buffered_read_stream.hpp | 28 ++++- .../boost/asio/impl/buffered_write_stream.hpp | 28 ++++- include/boost/asio/impl/compose.hpp | 14 ++- include/boost/asio/impl/connect.hpp | 28 ++++- .../boost/asio/impl/handler_alloc_hook.ipp | 17 ++- include/boost/asio/impl/read.hpp | 42 ++++++- include/boost/asio/impl/read_at.hpp | 28 ++++- include/boost/asio/impl/read_until.hpp | 112 +++++++++++++++--- include/boost/asio/impl/redirect_error.hpp | 14 ++- include/boost/asio/impl/spawn.hpp | 14 ++- include/boost/asio/impl/write.hpp | 42 ++++++- include/boost/asio/impl/write_at.hpp | 28 ++++- include/boost/asio/ssl/detail/io.hpp | 14 ++- test/deadline_timer.cpp | 84 ++++++++++--- test/system_timer.cpp | 84 ++++++++++--- 19 files changed, 668 insertions(+), 112 deletions(-) diff --git a/include/boost/asio/detail/bind_handler.hpp b/include/boost/asio/detail/bind_handler.hpp index bdab95c4..bc28d7b9 100644 --- a/include/boost/asio/detail/bind_handler.hpp +++ b/include/boost/asio/detail/bind_handler.hpp @@ -76,19 +76,29 @@ public: }; template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, binder1* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, binder1* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -185,19 +195,29 @@ public: }; template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, binder2* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, binder2* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -300,19 +320,29 @@ public: }; template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, binder3* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, binder3* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -426,20 +456,30 @@ public: template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, binder4* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, binder4* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, binder5* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, binder5* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, move_binder1* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, move_binder1* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -718,19 +778,29 @@ public: }; template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, move_binder2* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, move_binder2* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/detail/handler_alloc_helpers.hpp b/include/boost/asio/detail/handler_alloc_helpers.hpp index 41319d17..4d713940 100644 --- a/include/boost/asio/detail/handler_alloc_helpers.hpp +++ b/include/boost/asio/detail/handler_alloc_helpers.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -29,11 +30,41 @@ // boost_asio_handler_alloc_helpers namespace is defined here for that purpose. namespace boost_asio_handler_alloc_helpers { +#if defined(BOOST_ASIO_NO_DEPRECATED) +template +inline void error_if_hooks_are_defined(Handler& h) +{ + using boost::asio::asio_handler_allocate; + // If you get an error here it is because some of your handlers still + // overload asio_handler_allocate, but this hook is no longer used. + (void)static_cast( + asio_handler_allocate(static_cast(0), + boost::asio::detail::addressof(h))); + + using boost::asio::asio_handler_deallocate; + // If you get an error here it is because some of your handlers still + // overload asio_handler_deallocate, but this hook is no longer used. + (void)static_cast( + asio_handler_deallocate(static_cast(0), + static_cast(0), boost::asio::detail::addressof(h))); +} +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + template inline void* allocate(std::size_t s, Handler& h) { #if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) return ::operator new(s); +#elif defined(BOOST_ASIO_NO_DEPRECATED) + // The asio_handler_allocate hook is no longer used to obtain memory. + (void)&error_if_hooks_are_defined; + (void)h; +#if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return boost::asio::detail::thread_info_base::allocate( + boost::asio::detail::thread_context::thread_call_stack::top(), s); +#else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return ::operator new(size); +#endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) #else using boost::asio::asio_handler_allocate; return asio_handler_allocate(s, boost::asio::detail::addressof(h)); @@ -45,6 +76,17 @@ inline void deallocate(void* p, std::size_t s, Handler& h) { #if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) ::operator delete(p); +#elif defined(BOOST_ASIO_NO_DEPRECATED) + // The asio_handler_allocate hook is no longer used to obtain memory. + (void)&error_if_hooks_are_defined; + (void)h; +#if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + boost::asio::detail::thread_info_base::deallocate( + boost::asio::detail::thread_context::thread_call_stack::top(), p, s); +#else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + (void)s; + ::operator delete(p); +#endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) #else using boost::asio::asio_handler_deallocate; asio_handler_deallocate(p, s, boost::asio::detail::addressof(h)); diff --git a/include/boost/asio/detail/wrapped_handler.hpp b/include/boost/asio/detail/wrapped_handler.hpp index 81edf06e..3441223e 100644 --- a/include/boost/asio/detail/wrapped_handler.hpp +++ b/include/boost/asio/detail/wrapped_handler.hpp @@ -202,19 +202,29 @@ public: }; template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, wrapped_handler* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, wrapped_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -253,19 +263,29 @@ asio_handler_invoke(const Function& function, } template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, rewrapped_handler* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->context_); + size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, rewrapped_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->context_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/handler_alloc_hook.hpp b/include/boost/asio/handler_alloc_hook.hpp index 1f23a8b1..c1f53b6e 100644 --- a/include/boost/asio/handler_alloc_hook.hpp +++ b/include/boost/asio/handler_alloc_hook.hpp @@ -23,7 +23,30 @@ namespace boost { namespace asio { -/// Default allocation function for handlers. +#if defined(BOOST_ASIO_NO_DEPRECATED) + +// Places in asio that would have previously called the allocate or deallocate +// hooks to manage memory, now call them only to check whether the result types +// are these types. If the result is not the correct type, it indicates that +// the user code still has the old hooks in place, and if so we want to trigger +// a compile error. +enum asio_handler_allocate_is_no_longer_used {}; +enum asio_handler_deallocate_is_no_longer_used {}; + +typedef asio_handler_allocate_is_no_longer_used + asio_handler_allocate_is_deprecated; +typedef asio_handler_deallocate_is_no_longer_used + asio_handler_deallocate_is_deprecated; + +#else // defined(BOOST_ASIO_NO_DEPRECATED) + +typedef void* asio_handler_allocate_is_deprecated; +typedef void asio_handler_deallocate_is_deprecated; + +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + +/// (Deprecated: Use the associated_allocator trait.) Default allocation +/// function for handlers. /** * Asynchronous operations may need to allocate temporary objects. Since * asynchronous operations have a handler function object, these temporary @@ -55,8 +78,8 @@ namespace asio { * } * @endcode */ -BOOST_ASIO_DECL void* asio_handler_allocate( - std::size_t size, ...); +BOOST_ASIO_DECL asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, ...); /// Default deallocation function for handlers. /** @@ -68,8 +91,8 @@ BOOST_ASIO_DECL void* asio_handler_allocate( * * @sa asio_handler_allocate. */ -BOOST_ASIO_DECL void asio_handler_deallocate( - void* pointer, std::size_t size, ...); +BOOST_ASIO_DECL asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, ...); } // namespace asio } // namespace boost diff --git a/include/boost/asio/impl/buffered_read_stream.hpp b/include/boost/asio/impl/buffered_read_stream.hpp index 3952e76e..73f1049b 100644 --- a/include/boost/asio/impl/buffered_read_stream.hpp +++ b/include/boost/asio/impl/buffered_read_stream.hpp @@ -102,19 +102,29 @@ namespace detail }; template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, buffered_fill_handler* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, buffered_fill_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -321,21 +331,31 @@ namespace detail }; template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, buffered_read_some_handler< MutableBufferSequence, ReadHandler>* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, buffered_read_some_handler< MutableBufferSequence, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/buffered_write_stream.hpp b/include/boost/asio/impl/buffered_write_stream.hpp index 64e08804..cf33911f 100644 --- a/include/boost/asio/impl/buffered_write_stream.hpp +++ b/include/boost/asio/impl/buffered_write_stream.hpp @@ -87,19 +87,29 @@ namespace detail }; template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, buffered_flush_handler* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, buffered_flush_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template @@ -307,21 +317,31 @@ namespace detail }; template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, buffered_write_some_handler< ConstBufferSequence, WriteHandler>* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, buffered_write_some_handler< ConstBufferSequence, WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/compose.hpp b/include/boost/asio/impl/compose.hpp index 892dd646..ba9f2b06 100644 --- a/include/boost/asio/impl/compose.hpp +++ b/include/boost/asio/impl/compose.hpp @@ -346,19 +346,29 @@ namespace detail }; template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, composed_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, composed_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/connect.hpp b/include/boost/asio/impl/connect.hpp index 4a62b3e3..421ff2fc 100644 --- a/include/boost/asio/impl/connect.hpp +++ b/include/boost/asio/impl/connect.hpp @@ -408,22 +408,32 @@ namespace detail template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, range_connect_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, range_connect_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, iterator_connect_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, iterator_connect_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_dynbuf_v1_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_dynbuf_v1_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_dynbuf_v2_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_dynbuf_v2_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_at_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_at_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_at_streambuf_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_at_streambuf_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_until_delim_op_v1* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_op_v1* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_until_delim_string_op_v1* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_string_op_v1* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_until_expr_op_v1* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_until_expr_op_v1* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_until_match_op_v1* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_until_match_op_v1* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_until_delim_op_v2* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_op_v2* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_until_delim_string_op_v2* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_string_op_v2* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_until_expr_op_v2* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_until_expr_op_v2* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, read_until_match_op_v2* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, read_until_match_op_v2* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, redirect_error_handler* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, redirect_error_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/spawn.hpp b/include/boost/asio/impl/spawn.hpp index 316ff556..59e1a237 100644 --- a/include/boost/asio/impl/spawn.hpp +++ b/include/boost/asio/impl/spawn.hpp @@ -110,19 +110,29 @@ namespace detail { }; template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, coro_handler* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, coro_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/impl/write.hpp b/include/boost/asio/impl/write.hpp index e423955e..d878990d 100644 --- a/include/boost/asio/impl/write.hpp +++ b/include/boost/asio/impl/write.hpp @@ -356,23 +356,33 @@ namespace detail template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, write_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, write_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, write_dynbuf_v1_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, write_dynbuf_v1_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, write_dynbuf_v2_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, write_dynbuf_v2_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, write_at_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, write_at_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void* asio_handler_allocate(std::size_t size, + inline asio_handler_allocate_is_deprecated + asio_handler_allocate(std::size_t size, write_at_streambuf_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template - inline void asio_handler_deallocate(void* pointer, std::size_t size, + inline asio_handler_deallocate_is_deprecated + asio_handler_deallocate(void* pointer, std::size_t size, write_at_streambuf_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/include/boost/asio/ssl/detail/io.hpp b/include/boost/asio/ssl/detail/io.hpp index b69a4380..a59e96fb 100644 --- a/include/boost/asio/ssl/detail/io.hpp +++ b/include/boost/asio/ssl/detail/io.hpp @@ -310,19 +310,29 @@ public: }; template -inline void* asio_handler_allocate(std::size_t size, +inline asio_handler_allocate_is_deprecated +asio_handler_allocate(std::size_t size, io_op* this_handler) { +#if defined(BOOST_ASIO_NO_DEPRECATED) + boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); + return asio_handler_allocate_is_no_longer_used(); +#else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template -inline void asio_handler_deallocate(void* pointer, std::size_t size, +inline asio_handler_deallocate_is_deprecated +asio_handler_deallocate(void* pointer, std::size_t size, io_op* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); +#if defined(BOOST_ASIO_NO_DEPRECATED) + return asio_handler_deallocate_is_no_longer_used(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) } template diff --git a/test/deadline_timer.cpp b/test/deadline_timer.cpp index 0ff0d9bd..c6ce397b 100644 --- a/test/deadline_timer.cpp +++ b/test/deadline_timer.cpp @@ -250,22 +250,78 @@ struct custom_allocation_timer_handler custom_allocation_timer_handler(int* count) : count_(count) {} void operator()(const boost::system::error_code&) {} int* count_; + + template + struct allocator + { + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template + struct rebind + { + typedef allocator other; + }; + + explicit allocator(int* count) BOOST_ASIO_NOEXCEPT + : count_(count) + { + } + + allocator(const allocator& other) BOOST_ASIO_NOEXCEPT + : count_(other.count_) + { + } + + template + allocator(const allocator& other) BOOST_ASIO_NOEXCEPT + : count_(other.count_) + { + } + + pointer allocate(size_type n, const void* = 0) + { + ++(*count_); + return static_cast(::operator new(sizeof(T) * n)); + } + + void deallocate(pointer p, size_type) + { + --(*count_); + ::operator delete(p); + } + + size_type max_size() const + { + return ~size_type(0); + } + + void construct(pointer p, const T& v) + { + new (p) T(v); + } + + void destroy(pointer p) + { + p->~T(); + } + + int* count_; + }; + + typedef allocator allocator_type; + + allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT + { + return allocator_type(count_); + } }; -void* asio_handler_allocate(std::size_t size, - custom_allocation_timer_handler* handler) -{ - ++(*handler->count_); - return ::operator new(size); -} - -void asio_handler_deallocate(void* pointer, std::size_t, - custom_allocation_timer_handler* handler) -{ - --(*handler->count_); - ::operator delete(pointer); -} - void deadline_timer_custom_allocation_test() { static boost::asio::io_context io_context; diff --git a/test/system_timer.cpp b/test/system_timer.cpp index f81fdaf0..e9aadd3f 100644 --- a/test/system_timer.cpp +++ b/test/system_timer.cpp @@ -270,22 +270,78 @@ struct custom_allocation_timer_handler custom_allocation_timer_handler(int* count) : count_(count) {} void operator()(const boost::system::error_code&) {} int* count_; + + template + struct allocator + { + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + template + struct rebind + { + typedef allocator other; + }; + + explicit allocator(int* count) BOOST_ASIO_NOEXCEPT + : count_(count) + { + } + + allocator(const allocator& other) BOOST_ASIO_NOEXCEPT + : count_(other.count_) + { + } + + template + allocator(const allocator& other) BOOST_ASIO_NOEXCEPT + : count_(other.count_) + { + } + + pointer allocate(size_type n, const void* = 0) + { + ++(*count_); + return static_cast(::operator new(sizeof(T) * n)); + } + + void deallocate(pointer p, size_type) + { + --(*count_); + ::operator delete(p); + } + + size_type max_size() const + { + return ~size_type(0); + } + + void construct(pointer p, const T& v) + { + new (p) T(v); + } + + void destroy(pointer p) + { + p->~T(); + } + + int* count_; + }; + + typedef allocator allocator_type; + + allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT + { + return allocator_type(count_); + } }; -void* asio_handler_allocate(std::size_t size, - custom_allocation_timer_handler* handler) -{ - ++(*handler->count_); - return ::operator new(size); -} - -void asio_handler_deallocate(void* pointer, std::size_t, - custom_allocation_timer_handler* handler) -{ - --(*handler->count_); - ::operator delete(pointer); -} - void system_timer_custom_allocation_test() { static boost::asio::io_context io_context; From 9d2c453770998eba53a6161720d546bf076c8410 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:21:59 +1000 Subject: [PATCH 27/90] Explicitly disable copy construction in io_context and thread_pool. --- include/boost/asio/io_context.hpp | 4 +++- include/boost/asio/thread_pool.hpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/boost/asio/io_context.hpp b/include/boost/asio/io_context.hpp index 04ba4837..225fc86b 100644 --- a/include/boost/asio/io_context.hpp +++ b/include/boost/asio/io_context.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -595,6 +594,9 @@ public: #endif // !defined(BOOST_ASIO_NO_DEPRECATED) private: + io_context(const io_context&) BOOST_ASIO_DELETED; + io_context& operator=(const io_context&) BOOST_ASIO_DELETED; + #if !defined(BOOST_ASIO_NO_DEPRECATED) struct initiate_dispatch; struct initiate_post; diff --git a/include/boost/asio/thread_pool.hpp b/include/boost/asio/thread_pool.hpp index d1c585a7..2cd50251 100644 --- a/include/boost/asio/thread_pool.hpp +++ b/include/boost/asio/thread_pool.hpp @@ -16,7 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include -#include #include #include #include @@ -98,6 +97,9 @@ public: BOOST_ASIO_DECL void join(); private: + thread_pool(const thread_pool&) BOOST_ASIO_DELETED; + thread_pool& operator=(const thread_pool&) BOOST_ASIO_DELETED; + friend class executor_type; struct thread_function; From bfe960d7fd9d7a417cecce119e796d1795d6de56 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:24:58 +1000 Subject: [PATCH 28/90] Specify memory ordering when reference counting with standard atomics. --- include/boost/asio/detail/atomic_count.hpp | 19 +++++++++++++++++++ include/boost/asio/impl/executor.hpp | 4 ++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/boost/asio/detail/atomic_count.hpp b/include/boost/asio/detail/atomic_count.hpp index d12443dd..bd6643b5 100644 --- a/include/boost/asio/detail/atomic_count.hpp +++ b/include/boost/asio/detail/atomic_count.hpp @@ -32,12 +32,31 @@ namespace detail { #if !defined(BOOST_ASIO_HAS_THREADS) typedef long atomic_count; inline void increment(atomic_count& a, long b) { a += b; } +inline void ref_count_up(atomic_count& a) { ++a; } +inline bool ref_count_down(atomic_count& a) { return --a == 0; } #elif defined(BOOST_ASIO_HAS_STD_ATOMIC) typedef std::atomic atomic_count; inline void increment(atomic_count& a, long b) { a += b; } + +inline void ref_count_up(atomic_count& a) +{ + a.fetch_add(1, std::memory_order_relaxed); +} + +inline bool ref_count_down(atomic_count& a) +{ + if (a.fetch_sub(1, std::memory_order_release) == 1) + { + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + return false; +} #else // defined(BOOST_ASIO_HAS_STD_ATOMIC) typedef boost::detail::atomic_count atomic_count; inline void increment(atomic_count& a, long b) { while (b > 0) ++a, --b; } +inline void ref_count_up(atomic_count& a) { ++a; } +inline bool ref_count_down(atomic_count& a) { return --a == 0; } #endif // defined(BOOST_ASIO_HAS_STD_ATOMIC) } // namespace detail diff --git a/include/boost/asio/impl/executor.hpp b/include/boost/asio/impl/executor.hpp index 31a1e43b..05adf56b 100644 --- a/include/boost/asio/impl/executor.hpp +++ b/include/boost/asio/impl/executor.hpp @@ -149,13 +149,13 @@ public: impl_base* clone() const BOOST_ASIO_NOEXCEPT { - ++ref_count_; + detail::ref_count_up(ref_count_); return const_cast(static_cast(this)); } void destroy() BOOST_ASIO_NOEXCEPT { - if (--ref_count_ == 0) + if (detail::ref_count_down(ref_count_)) { allocator_type alloc(allocator_); impl* p = this; From e3ed5f0c68f54de840bf86176d27d56a46aeb99c Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:25:27 +1000 Subject: [PATCH 29/90] Add single-buffer optimisation for send and receive. When we can determine at compile time that the user has supplied a single buffer, use send/recv rather than sendmsg/recvmsg, as the former system calls can be faster. --- .../asio/detail/buffer_sequence_adapter.hpp | 14 ++ include/boost/asio/detail/impl/socket_ops.ipp | 217 ++++++++++++++++++ .../asio/detail/reactive_socket_recv_op.hpp | 25 +- .../asio/detail/reactive_socket_send_op.hpp | 33 ++- .../detail/reactive_socket_service_base.hpp | 36 ++- include/boost/asio/detail/socket_ops.hpp | 20 ++ 6 files changed, 323 insertions(+), 22 deletions(-) diff --git a/include/boost/asio/detail/buffer_sequence_adapter.hpp b/include/boost/asio/detail/buffer_sequence_adapter.hpp index fba5fb57..38276c05 100644 --- a/include/boost/asio/detail/buffer_sequence_adapter.hpp +++ b/include/boost/asio/detail/buffer_sequence_adapter.hpp @@ -105,6 +105,8 @@ class buffer_sequence_adapter : buffer_sequence_adapter_base { public: + enum { is_single_buffer = false }; + explicit buffer_sequence_adapter(const Buffers& buffer_sequence) : count_(0), total_buffer_size_(0) { @@ -246,6 +248,8 @@ class buffer_sequence_adapter : buffer_sequence_adapter_base { public: + enum { is_single_buffer = true }; + explicit buffer_sequence_adapter( const boost::asio::mutable_buffer& buffer_sequence) { @@ -306,6 +310,8 @@ class buffer_sequence_adapter : buffer_sequence_adapter_base { public: + enum { is_single_buffer = true }; + explicit buffer_sequence_adapter( const boost::asio::const_buffer& buffer_sequence) { @@ -368,6 +374,8 @@ class buffer_sequence_adapter : buffer_sequence_adapter_base { public: + enum { is_single_buffer = true }; + explicit buffer_sequence_adapter( const boost::asio::mutable_buffers_1& buffer_sequence) { @@ -428,6 +436,8 @@ class buffer_sequence_adapter : buffer_sequence_adapter_base { public: + enum { is_single_buffer = true }; + explicit buffer_sequence_adapter( const boost::asio::const_buffers_1& buffer_sequence) { @@ -490,6 +500,8 @@ class buffer_sequence_adapter > : buffer_sequence_adapter_base { public: + enum { is_single_buffer = false }; + explicit buffer_sequence_adapter( const boost::array& buffer_sequence) { @@ -560,6 +572,8 @@ class buffer_sequence_adapter > : buffer_sequence_adapter_base { public: + enum { is_single_buffer = false }; + explicit buffer_sequence_adapter( const std::array& buffer_sequence) { diff --git a/include/boost/asio/detail/impl/socket_ops.ipp b/include/boost/asio/detail/impl/socket_ops.ipp index 9699b2f5..934aee20 100644 --- a/include/boost/asio/detail/impl/socket_ops.ipp +++ b/include/boost/asio/detail/impl/socket_ops.ipp @@ -788,6 +788,38 @@ signed_size_type recv(socket_type s, buf* bufs, size_t count, #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } +signed_size_type recv1(socket_type s, void* data, size_t size, + int flags, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + WSABUF buf; + buf.buf = const_cast(static_cast(data)); + buf.len = static_cast(size); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = error_wrapper(::WSARecv(s, &buf, 1, + &bytes_transferred, &recv_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + signed_size_type result = error_wrapper(::recv(s, + static_cast(data), size, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + size_t sync_recv(socket_type s, state_type state, buf* bufs, size_t count, int flags, bool all_empty, boost::system::error_code& ec) { @@ -833,6 +865,51 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, } } +size_t sync_recv1(socket_type s, state_type state, void* data, + size_t size, int flags, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (size == 0 && (state & stream_oriented)) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if ((state & stream_oriented) && bytes == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + #if defined(BOOST_ASIO_HAS_IOCP) void complete_iocp_recv(state_type state, @@ -905,6 +982,44 @@ bool non_blocking_recv(socket_type s, } } +bool non_blocking_recv1(socket_type s, + void* data, size_t size, int flags, bool is_stream, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); + + // Check for end of stream. + if (is_stream && bytes == 0) + { + ec = boost::asio::error::eof; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + #endif // defined(BOOST_ASIO_HAS_IOCP) signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, @@ -1188,6 +1303,39 @@ signed_size_type send(socket_type s, const buf* bufs, size_t count, #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } +signed_size_type send1(socket_type s, const void* data, size_t size, + int flags, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + WSABUF buf; + buf.buf = const_cast(static_cast(data)); + buf.len = static_cast(size); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = error_wrapper(::WSASend(s, &buf, 1, + &bytes_transferred, send_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + signed_size_type result = error_wrapper(::send(s, + static_cast(data), size, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + size_t sync_send(socket_type s, state_type state, const buf* bufs, size_t count, int flags, bool all_empty, boost::system::error_code& ec) { @@ -1226,6 +1374,44 @@ size_t sync_send(socket_type s, state_type state, const buf* bufs, } } +size_t sync_send1(socket_type s, state_type state, const void* data, + size_t size, int flags, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes to a stream is a no-op. + if (size == 0 && (state & stream_oriented)) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + #if defined(BOOST_ASIO_HAS_IOCP) void complete_iocp_send( @@ -1279,6 +1465,37 @@ bool non_blocking_send(socket_type s, } } +bool non_blocking_send1(socket_type s, + const void* data, size_t size, int flags, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + #endif // defined(BOOST_ASIO_HAS_IOCP) signed_size_type sendto(socket_type s, const buf* bufs, size_t count, diff --git a/include/boost/asio/detail/reactive_socket_recv_op.hpp b/include/boost/asio/detail/reactive_socket_recv_op.hpp index 7d33c98b..e0e43c84 100644 --- a/include/boost/asio/detail/reactive_socket_recv_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recv_op.hpp @@ -49,13 +49,26 @@ public: reactive_socket_recv_op_base* o( static_cast(base)); - buffer_sequence_adapter bufs(o->buffers_); + typedef buffer_sequence_adapter bufs_type; - status result = socket_ops::non_blocking_recv(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, - (o->state_ & socket_ops::stream_oriented) != 0, - o->ec_, o->bytes_transferred_) ? done : not_done; + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_recv1(o->socket_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, + (o->state_ & socket_ops::stream_oriented) != 0, + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_recv(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + (o->state_ & socket_ops::stream_oriented) != 0, + o->ec_, o->bytes_transferred_) ? done : not_done; + } if (result == done) if ((o->state_ & socket_ops::stream_oriented) != 0) diff --git a/include/boost/asio/detail/reactive_socket_send_op.hpp b/include/boost/asio/detail/reactive_socket_send_op.hpp index ca2d4588..031d01c3 100644 --- a/include/boost/asio/detail/reactive_socket_send_op.hpp +++ b/include/boost/asio/detail/reactive_socket_send_op.hpp @@ -49,17 +49,34 @@ public: reactive_socket_send_op_base* o( static_cast(base)); - buffer_sequence_adapter bufs(o->buffers_); + typedef buffer_sequence_adapter bufs_type; - status result = socket_ops::non_blocking_send(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_send1(o->socket_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, o->ec_, o->bytes_transferred_) ? done : not_done; - if (result == done) - if ((o->state_ & socket_ops::stream_oriented) != 0) - if (o->bytes_transferred_ < bufs.total_size()) - result = done_and_exhausted; + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ < bufs_type::first(o->buffers_).size()) + result = done_and_exhausted; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_send(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ < bufs.total_size()) + result = done_and_exhausted; + } BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_send", o->ec_, o->bytes_transferred_)); diff --git a/include/boost/asio/detail/reactive_socket_service_base.hpp b/include/boost/asio/detail/reactive_socket_service_base.hpp index a8d04ca8..5ed63dde 100644 --- a/include/boost/asio/detail/reactive_socket_service_base.hpp +++ b/include/boost/asio/detail/reactive_socket_service_base.hpp @@ -238,11 +238,21 @@ public: const ConstBufferSequence& buffers, socket_base::message_flags flags, boost::system::error_code& ec) { - buffer_sequence_adapter bufs(buffers); + typedef buffer_sequence_adapter bufs_type; - return socket_ops::sync_send(impl.socket_, impl.state_, - bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + if (bufs_type::is_single_buffer) + { + return socket_ops::sync_send1(impl.socket_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, ec); + } + else + { + bufs_type bufs(buffers); + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } } // Wait until data can be sent without blocking. @@ -310,11 +320,21 @@ public: const MutableBufferSequence& buffers, socket_base::message_flags flags, boost::system::error_code& ec) { - buffer_sequence_adapter bufs(buffers); + typedef buffer_sequence_adapter bufs_type; - return socket_ops::sync_recv(impl.socket_, impl.state_, - bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + if (bufs_type::is_single_buffer) + { + return socket_ops::sync_recv1(impl.socket_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, ec); + } + else + { + bufs_type bufs(buffers); + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } } // Wait until data can be received without blocking. diff --git a/include/boost/asio/detail/socket_ops.hpp b/include/boost/asio/detail/socket_ops.hpp index aabcc84c..b4206d30 100644 --- a/include/boost/asio/detail/socket_ops.hpp +++ b/include/boost/asio/detail/socket_ops.hpp @@ -140,9 +140,15 @@ BOOST_ASIO_DECL void init_buf(buf& b, const void* data, size_t size); BOOST_ASIO_DECL signed_size_type recv(socket_type s, buf* bufs, size_t count, int flags, boost::system::error_code& ec); +BOOST_ASIO_DECL signed_size_type recv1(socket_type s, + void* data, size_t size, int flags, boost::system::error_code& ec); + BOOST_ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs, size_t count, int flags, bool all_empty, boost::system::error_code& ec); +BOOST_ASIO_DECL size_t sync_recv1(socket_type s, state_type state, + void* data, size_t size, int flags, boost::system::error_code& ec); + #if defined(BOOST_ASIO_HAS_IOCP) BOOST_ASIO_DECL void complete_iocp_recv(state_type state, @@ -155,6 +161,10 @@ BOOST_ASIO_DECL bool non_blocking_recv(socket_type s, buf* bufs, size_t count, int flags, bool is_stream, boost::system::error_code& ec, size_t& bytes_transferred); +BOOST_ASIO_DECL bool non_blocking_recv1(socket_type s, + void* data, size_t size, int flags, bool is_stream, + boost::system::error_code& ec, size_t& bytes_transferred); + #endif // defined(BOOST_ASIO_HAS_IOCP) BOOST_ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs, @@ -205,10 +215,16 @@ BOOST_ASIO_DECL bool non_blocking_recvmsg(socket_type s, BOOST_ASIO_DECL signed_size_type send(socket_type s, const buf* bufs, size_t count, int flags, boost::system::error_code& ec); +BOOST_ASIO_DECL signed_size_type send1(socket_type s, + const void* data, size_t size, int flags, boost::system::error_code& ec); + BOOST_ASIO_DECL size_t sync_send(socket_type s, state_type state, const buf* bufs, size_t count, int flags, bool all_empty, boost::system::error_code& ec); +BOOST_ASIO_DECL size_t sync_send1(socket_type s, state_type state, + const void* data, size_t size, int flags, boost::system::error_code& ec); + #if defined(BOOST_ASIO_HAS_IOCP) BOOST_ASIO_DECL void complete_iocp_send( @@ -221,6 +237,10 @@ BOOST_ASIO_DECL bool non_blocking_send(socket_type s, const buf* bufs, size_t count, int flags, boost::system::error_code& ec, size_t& bytes_transferred); +BOOST_ASIO_DECL bool non_blocking_send1(socket_type s, + const void* data, size_t size, int flags, + boost::system::error_code& ec, size_t& bytes_transferred); + #endif // defined(BOOST_ASIO_HAS_IOCP) BOOST_ASIO_DECL signed_size_type sendto(socket_type s, const buf* bufs, From 42b575ce2ccaf8a738ce00f89222bdb29deed5d7 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:26:24 +1000 Subject: [PATCH 30/90] Access errno only when on the error path. --- include/boost/asio/detail/descriptor_ops.hpp | 17 +- .../boost/asio/detail/impl/descriptor_ops.ipp | 108 ++--- .../impl/reactive_serial_port_service.ipp | 27 +- include/boost/asio/detail/impl/socket_ops.ipp | 430 ++++++++---------- .../detail/reactive_serial_port_service.hpp | 5 +- 5 files changed, 259 insertions(+), 328 deletions(-) diff --git a/include/boost/asio/detail/descriptor_ops.hpp b/include/boost/asio/detail/descriptor_ops.hpp index 55690acf..bc596a3a 100644 --- a/include/boost/asio/detail/descriptor_ops.hpp +++ b/include/boost/asio/detail/descriptor_ops.hpp @@ -51,13 +51,18 @@ enum typedef unsigned char state_type; -template -inline ReturnType error_wrapper(ReturnType return_value, - boost::system::error_code& ec) +inline void get_last_error( + boost::system::error_code& ec, bool is_error_condition) { - ec = boost::system::error_code(errno, - boost::asio::error::get_system_category()); - return return_value; + if (!is_error_condition) + { + ec = boost::system::error_code(); + } + else + { + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); + } } BOOST_ASIO_DECL int open(const char* path, int flags, diff --git a/include/boost/asio/detail/impl/descriptor_ops.ipp b/include/boost/asio/detail/impl/descriptor_ops.ipp index f4c21d55..3eb1dc45 100644 --- a/include/boost/asio/detail/impl/descriptor_ops.ipp +++ b/include/boost/asio/detail/impl/descriptor_ops.ipp @@ -33,10 +33,8 @@ namespace descriptor_ops { int open(const char* path, int flags, boost::system::error_code& ec) { - errno = 0; - int result = error_wrapper(::open(path, flags), ec); - if (result >= 0) - ec = boost::system::error_code(); + int result = ::open(path, flags); + get_last_error(ec, result < 0); return result; } @@ -45,8 +43,8 @@ int close(int d, state_type& state, boost::system::error_code& ec) int result = 0; if (d != -1) { - errno = 0; - result = error_wrapper(::close(d), ec); + result = ::close(d); + get_last_error(ec, result < 0); if (result != 0 && (ec == boost::asio::error::would_block @@ -68,13 +66,11 @@ int close(int d, state_type& state, boost::system::error_code& ec) #endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) state &= ~non_blocking; - errno = 0; - result = error_wrapper(::close(d), ec); + result = ::close(d); + get_last_error(ec, result < 0); } } - if (result == 0) - ec = boost::system::error_code(); return result; } @@ -87,23 +83,23 @@ bool set_user_non_blocking(int d, state_type& state, return false; } - errno = 0; #if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) - int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); + int result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - errno = 0; int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(d, F_SETFL, flag), ec); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); } #else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); + int result = ::ioctl(d, FIONBIO, &arg); + get_last_error(ec, result < 0); #endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) if (result >= 0) { - ec = boost::system::error_code(); if (value) state |= user_set_non_blocking; else @@ -137,23 +133,23 @@ bool set_internal_non_blocking(int d, state_type& state, return false; } - errno = 0; #if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) - int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); + int result = ::fcntl(d, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - errno = 0; int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(d, F_SETFL, flag), ec); + result = ::fcntl(d, F_SETFL, flag); + get_last_error(ec, result < 0); } #else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); + int result = ::ioctl(d, FIONBIO, &arg); + get_last_error(ec, result < 0); #endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) if (result >= 0) { - ec = boost::system::error_code(); if (value) state |= internal_non_blocking; else @@ -184,9 +180,8 @@ std::size_t sync_read(int d, state_type state, buf* bufs, for (;;) { // Try to complete the operation without blocking. - errno = 0; - signed_size_type bytes = error_wrapper(::readv( - d, bufs, static_cast(count)), ec); + signed_size_type bytes = ::readv(d, bufs, static_cast(count)); + get_last_error(ec, bytes < 0); // Check if operation succeeded. if (bytes > 0) @@ -217,9 +212,8 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count, for (;;) { // Read some data. - errno = 0; - signed_size_type bytes = error_wrapper(::readv( - d, bufs, static_cast(count)), ec); + signed_size_type bytes = ::readv(d, bufs, static_cast(count)); + get_last_error(ec, bytes < 0); // Check for end of stream. if (bytes == 0) @@ -270,9 +264,8 @@ std::size_t sync_write(int d, state_type state, const buf* bufs, for (;;) { // Try to complete the operation without blocking. - errno = 0; - signed_size_type bytes = error_wrapper(::writev( - d, bufs, static_cast(count)), ec); + signed_size_type bytes = ::writev(d, bufs, static_cast(count)); + get_last_error(ec, bytes < 0); // Check if operation succeeded. if (bytes > 0) @@ -296,9 +289,8 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count, for (;;) { // Write some data. - errno = 0; - signed_size_type bytes = error_wrapper(::writev( - d, bufs, static_cast(count)), ec); + signed_size_type bytes = ::writev(d, bufs, static_cast(count)); + get_last_error(ec, bytes < 0); // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) @@ -331,13 +323,11 @@ int ioctl(int d, state_type& state, long cmd, return -1; } - errno = 0; - int result = error_wrapper(::ioctl(d, cmd, arg), ec); + int result = ::ioctl(d, cmd, arg); + get_last_error(ec, result < 0); if (result >= 0) { - ec = boost::system::error_code(); - // When updating the non-blocking mode we always perform the ioctl syscall, // even if the flags would otherwise indicate that the descriptor is // already in the correct state. This ensures that the underlying @@ -371,10 +361,8 @@ int fcntl(int d, int cmd, boost::system::error_code& ec) return -1; } - errno = 0; - int result = error_wrapper(::fcntl(d, cmd), ec); - if (result != -1) - ec = boost::system::error_code(); + int result = ::fcntl(d, cmd); + get_last_error(ec, result < 0); return result; } @@ -386,10 +374,8 @@ int fcntl(int d, int cmd, long arg, boost::system::error_code& ec) return -1; } - errno = 0; - int result = error_wrapper(::fcntl(d, cmd, arg), ec); - if (result != -1) - ec = boost::system::error_code(); + int result = ::fcntl(d, cmd, arg); + get_last_error(ec, result < 0); return result; } @@ -406,13 +392,11 @@ int poll_read(int d, state_type state, boost::system::error_code& ec) fds.events = POLLIN; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : -1; - errno = 0; - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); if (result == 0) - ec = (state & user_set_non_blocking) - ? boost::asio::error::would_block : boost::system::error_code(); - else if (result > 0) - ec = boost::system::error_code(); + if (state & user_set_non_blocking) + ec = boost::asio::error::would_block; return result; } @@ -429,13 +413,11 @@ int poll_write(int d, state_type state, boost::system::error_code& ec) fds.events = POLLOUT; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : -1; - errno = 0; - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); if (result == 0) - ec = (state & user_set_non_blocking) - ? boost::asio::error::would_block : boost::system::error_code(); - else if (result > 0) - ec = boost::system::error_code(); + if (state & user_set_non_blocking) + ec = boost::asio::error::would_block; return result; } @@ -452,13 +434,11 @@ int poll_error(int d, state_type state, boost::system::error_code& ec) fds.events = POLLPRI | POLLERR | POLLHUP; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : -1; - errno = 0; - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); if (result == 0) - ec = (state & user_set_non_blocking) - ? boost::asio::error::would_block : boost::system::error_code(); - else if (result > 0) - ec = boost::system::error_code(); + if (state & user_set_non_blocking) + ec = boost::asio::error::would_block; return result; } diff --git a/include/boost/asio/detail/impl/reactive_serial_port_service.ipp b/include/boost/asio/detail/impl/reactive_serial_port_service.ipp index 10cbc6e3..32f749f3 100644 --- a/include/boost/asio/detail/impl/reactive_serial_port_service.ipp +++ b/include/boost/asio/detail/impl/reactive_serial_port_service.ipp @@ -70,8 +70,8 @@ boost::system::error_code reactive_serial_port_service::open( // Set up default serial port options. termios ios; - errno = 0; - s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); + s = ::tcgetattr(fd, &ios); + descriptor_ops::get_last_error(ec, s < 0); if (s >= 0) { #if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) @@ -86,8 +86,8 @@ boost::system::error_code reactive_serial_port_service::open( #endif ios.c_iflag |= IGNPAR; ios.c_cflag |= CREAD | CLOCAL; - errno = 0; - s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); + s = ::tcsetattr(fd, TCSANOW, &ios); + descriptor_ops::get_last_error(ec, s < 0); } if (s < 0) { @@ -112,18 +112,16 @@ boost::system::error_code reactive_serial_port_service::do_set_option( const void* option, boost::system::error_code& ec) { termios ios; - errno = 0; - descriptor_ops::error_wrapper(::tcgetattr( - descriptor_service_.native_handle(impl), &ios), ec); - if (ec) + int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios); + descriptor_ops::get_last_error(ec, s < 0); + if (s < 0) return ec; if (store(option, ios, ec)) return ec; - errno = 0; - descriptor_ops::error_wrapper(::tcsetattr( - descriptor_service_.native_handle(impl), TCSANOW, &ios), ec); + s = ::tcsetattr(descriptor_service_.native_handle(impl), TCSANOW, &ios); + descriptor_ops::get_last_error(ec, s < 0); return ec; } @@ -133,10 +131,9 @@ boost::system::error_code reactive_serial_port_service::do_get_option( void* option, boost::system::error_code& ec) const { termios ios; - errno = 0; - descriptor_ops::error_wrapper(::tcgetattr( - descriptor_service_.native_handle(impl), &ios), ec); - if (ec) + int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios); + descriptor_ops::get_last_error(ec, s < 0); + if (s < 0) return ec; return load(option, ios, ec); diff --git a/include/boost/asio/detail/impl/socket_ops.ipp b/include/boost/asio/detail/impl/socket_ops.ipp index 934aee20..684fe605 100644 --- a/include/boost/asio/detail/impl/socket_ops.ipp +++ b/include/boost/asio/detail/impl/socket_ops.ipp @@ -74,18 +74,23 @@ inline void clear_last_error() #if !defined(BOOST_ASIO_WINDOWS_RUNTIME) -template -inline ReturnType error_wrapper(ReturnType return_value, - boost::system::error_code& ec) +inline void get_last_error( + boost::system::error_code& ec, bool is_error_condition) { + if (!is_error_condition) + { + ec = boost::system::error_code(); + } + else + { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - ec = boost::system::error_code(WSAGetLastError(), - boost::asio::error::get_system_category()); + ec = boost::system::error_code(WSAGetLastError(), + boost::asio::error::get_system_category()); #else - ec = boost::system::error_code(errno, - boost::asio::error::get_system_category()); + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); #endif - return return_value; + } } template @@ -108,17 +113,16 @@ socket_type accept(socket_type s, socket_addr_type* addr, return invalid_socket; } - clear_last_error(); - - socket_type new_s = error_wrapper(call_accept( - &msghdr::msg_namelen, s, addr, addrlen), ec); + socket_type new_s = call_accept(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, new_s == invalid_socket); if (new_s == invalid_socket) return new_s; #if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) int optval = 1; - int result = error_wrapper(::setsockopt(new_s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + int result = ::setsockopt(new_s, SOL_SOCKET, + SO_NOSIGPIPE, &optval, sizeof(optval)); + get_last_error(ec, result != 0); if (result != 0) { ::close(new_s); @@ -283,11 +287,8 @@ int bind(socket_type s, const socket_addr_type* addr, return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(call_bind( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = boost::system::error_code(); + int result = call_bind(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); return result; } @@ -310,12 +311,12 @@ int close(socket_type s, state_type& state, SO_LINGER, &opt, sizeof(opt), ignored_ec); } - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::closesocket(s), ec); + result = ::closesocket(s); #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::close(s), ec); + result = ::close(s); #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + get_last_error(ec, result != 0); if (result != 0 && (ec == boost::asio::error::would_block @@ -342,17 +343,15 @@ int close(socket_type s, state_type& state, #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) state &= ~non_blocking; - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::closesocket(s), ec); + result = ::closesocket(s); #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - result = error_wrapper(::close(s), ec); + result = ::close(s); #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + get_last_error(ec, result != 0); } } - if (result == 0) - ec = boost::system::error_code(); return result; } @@ -365,26 +364,27 @@ bool set_user_non_blocking(socket_type s, return false; } - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); + int result = ::ioctlsocket(s, FIONBIO, &arg); + get_last_error(ec, result < 0); #elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) - int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + int result = ::fcntl(s, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - clear_last_error(); int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(s, F_SETFL, flag), ec); + result = ::fcntl(s, F_SETFL, flag); + get_last_error(ec, result < 0); } #else ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); + int result = ::ioctl(s, FIONBIO, &arg); + get_last_error(ec, result < 0); #endif if (result >= 0) { - ec = boost::system::error_code(); if (value) state |= user_set_non_blocking; else @@ -418,26 +418,27 @@ bool set_internal_non_blocking(socket_type s, return false; } - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); + int result = ::ioctlsocket(s, FIONBIO, &arg); + get_last_error(ec, result < 0); #elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) - int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + int result = ::fcntl(s, F_GETFL, 0); + get_last_error(ec, result < 0); if (result >= 0) { - clear_last_error(); int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); - result = error_wrapper(::fcntl(s, F_SETFL, flag), ec); + result = ::fcntl(s, F_SETFL, flag); + get_last_error(ec, result < 0); } #else ioctl_arg_type arg = (value ? 1 : 0); - int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); + int result = ::ioctl(s, FIONBIO, &arg); + get_last_error(ec, result < 0); #endif if (result >= 0) { - ec = boost::system::error_code(); if (value) state |= internal_non_blocking; else @@ -456,10 +457,8 @@ int shutdown(socket_type s, int what, boost::system::error_code& ec) return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(::shutdown(s, what), ec); - if (result == 0) - ec = boost::system::error_code(); + int result = ::shutdown(s, what); + get_last_error(ec, result != 0); return result; } @@ -479,13 +478,10 @@ int connect(socket_type s, const socket_addr_type* addr, return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(call_connect( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = boost::system::error_code(); + int result = call_connect(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); #if defined(__linux__) - else if (ec == boost::asio::error::try_again) + if (result != 0 && ec == boost::asio::error::try_again) ec = boost::asio::error::no_buffer_space; #endif // defined(__linux__) return result; @@ -618,10 +614,8 @@ int socketpair(int af, int type, int protocol, ec = boost::asio::error::operation_not_supported; return socket_error_retval; #else - clear_last_error(); - int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); - if (result == 0) - ec = boost::system::error_code(); + int result = ::socketpair(af, type, protocol, sv); + get_last_error(ec, result != 0); return result; #endif } @@ -637,20 +631,18 @@ bool sockatmark(socket_type s, boost::system::error_code& ec) #if defined(SIOCATMARK) ioctl_arg_type value = 0; # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec); + int result = ::ioctlsocket(s, SIOCATMARK, &value); # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec); + int result = ::ioctl(s, SIOCATMARK, &value); # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - if (result == 0) - ec = boost::system::error_code(); + get_last_error(ec, result < 0); # if defined(ENOTTY) if (ec.value() == ENOTTY) ec = boost::asio::error::not_socket; # endif // defined(ENOTTY) #else // defined(SIOCATMARK) - int value = error_wrapper(::sockatmark(s), ec); - if (value != -1) - ec = boost::system::error_code(); + int value = ::sockatmark(s); + get_last_error(ec, result < 0); #endif // defined(SIOCATMARK) return ec ? false : value != 0; @@ -666,12 +658,11 @@ size_t available(socket_type s, boost::system::error_code& ec) ioctl_arg_type value = 0; #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec); + int result = ::ioctlsocket(s, FIONREAD, &value); #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec); + int result = ::ioctl(s, FIONREAD, &value); #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - if (result == 0) - ec = boost::system::error_code(); + get_last_error(ec, result < 0); #if defined(ENOTTY) if (ec.value() == ENOTTY) ec = boost::asio::error::not_socket; @@ -688,10 +679,8 @@ int listen(socket_type s, int backlog, boost::system::error_code& ec) return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(::listen(s, backlog), ec); - if (result == 0) - ec = boost::system::error_code(); + int result = ::listen(s, backlog); + get_last_error(ec, result != 0); return result; } @@ -759,14 +748,14 @@ inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) signed_size_type recv(socket_type s, buf* bufs, size_t count, int flags, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; - int result = error_wrapper(::WSARecv(s, bufs, - recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); + int result = ::WSARecv(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = boost::asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) @@ -781,9 +770,8 @@ signed_size_type recv(socket_type s, buf* bufs, size_t count, msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = static_cast(count); - signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); - if (result >= 0) - ec = boost::system::error_code(); + signed_size_type result = ::recvmsg(s, &msg, flags); + get_last_error(ec, result < 0); return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -791,7 +779,6 @@ signed_size_type recv(socket_type s, buf* bufs, size_t count, signed_size_type recv1(socket_type s, void* data, size_t size, int flags, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. WSABUF buf; @@ -799,8 +786,9 @@ signed_size_type recv1(socket_type s, void* data, size_t size, buf.len = static_cast(size); DWORD bytes_transferred = 0; DWORD recv_flags = flags; - int result = error_wrapper(::WSARecv(s, &buf, 1, - &bytes_transferred, &recv_flags, 0, 0), ec); + int result = ::WSARecv(s, &buf, 1, + &bytes_transferred, &recv_flags, 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = boost::asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) @@ -812,10 +800,8 @@ signed_size_type recv1(socket_type s, void* data, size_t size, ec = boost::system::error_code(); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - signed_size_type result = error_wrapper(::recv(s, - static_cast(data), size, flags), ec); - if (result >= 0) - ec = boost::system::error_code(); + signed_size_type result = ::recv(s, static_cast(data), size, flags); + get_last_error(ec, result < 0); return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -1026,15 +1012,15 @@ signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int tmp_addrlen = (int)*addrlen; - int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, - &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + int result = ::WSARecvFrom(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0); + get_last_error(ec, true); *addrlen = (std::size_t)tmp_addrlen; if (ec.value() == ERROR_NETNAME_DELETED) ec = boost::asio::error::connection_reset; @@ -1052,10 +1038,9 @@ signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, msg.msg_namelen = static_cast(*addrlen); msg.msg_iov = bufs; msg.msg_iovlen = static_cast(count); - signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); + signed_size_type result = ::recvmsg(s, &msg, flags); + get_last_error(ec, result < 0); *addrlen = msg.msg_namelen; - if (result >= 0) - ec = boost::system::error_code(); return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -1157,7 +1142,6 @@ bool non_blocking_recvfrom(socket_type s, signed_size_type recvmsg(socket_type s, buf* bufs, size_t count, int in_flags, int& out_flags, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) out_flags = 0; return socket_ops::recv(s, bufs, count, in_flags, ec); @@ -1165,12 +1149,10 @@ signed_size_type recvmsg(socket_type s, buf* bufs, size_t count, msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = static_cast(count); - signed_size_type result = error_wrapper(::recvmsg(s, &msg, in_flags), ec); + signed_size_type result = ::recvmsg(s, &msg, in_flags); + get_last_error(ec, result < 0); if (result >= 0) - { - ec = boost::system::error_code(); out_flags = msg.msg_flags; - } else out_flags = 0; return result; @@ -1273,14 +1255,14 @@ bool non_blocking_recvmsg(socket_type s, signed_size_type send(socket_type s, const buf* bufs, size_t count, int flags, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD send_flags = flags; - int result = error_wrapper(::WSASend(s, const_cast(bufs), - send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); + int result = ::WSASend(s, const_cast(bufs), + send_buf_count, &bytes_transferred, send_flags, 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = boost::asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) @@ -1296,9 +1278,8 @@ signed_size_type send(socket_type s, const buf* bufs, size_t count, #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) - signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - ec = boost::system::error_code(); + signed_size_type result = ::sendmsg(s, &msg, flags); + get_last_error(ec, result < 0); return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -1306,7 +1287,6 @@ signed_size_type send(socket_type s, const buf* bufs, size_t count, signed_size_type send1(socket_type s, const void* data, size_t size, int flags, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. WSABUF buf; @@ -1314,8 +1294,9 @@ signed_size_type send1(socket_type s, const void* data, size_t size, buf.len = static_cast(size); DWORD bytes_transferred = 0; DWORD send_flags = flags; - int result = error_wrapper(::WSASend(s, &buf, 1, - &bytes_transferred, send_flags, 0, 0), ec); + int result = ::WSASend(s, &buf, 1, + &bytes_transferred, send_flags, 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = boost::asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) @@ -1328,10 +1309,9 @@ signed_size_type send1(socket_type s, const void* data, size_t size, #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) - signed_size_type result = error_wrapper(::send(s, - static_cast(data), size, flags), ec); - if (result >= 0) - ec = boost::system::error_code(); + signed_size_type result = ::send(s, + static_cast(data), size, flags); + get_last_error(ec, result < 0); return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -1502,14 +1482,14 @@ signed_size_type sendto(socket_type s, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast(count); DWORD bytes_transferred = 0; - int result = error_wrapper(::WSASendTo(s, const_cast(bufs), + int result = ::WSASendTo(s, const_cast(bufs), send_buf_count, &bytes_transferred, flags, addr, - static_cast(addrlen), 0, 0), ec); + static_cast(addrlen), 0, 0); + get_last_error(ec, true); if (ec.value() == ERROR_NETNAME_DELETED) ec = boost::asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) @@ -1527,9 +1507,8 @@ signed_size_type sendto(socket_type s, const buf* bufs, size_t count, #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) - signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - ec = boost::system::error_code(); + signed_size_type result = ::sendmsg(s, &msg, flags); + get_last_error(ec, result < 0); return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -1607,10 +1586,9 @@ bool non_blocking_sendto(socket_type s, socket_type socket(int af, int type, int protocol, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - socket_type s = error_wrapper(::WSASocketW(af, type, protocol, 0, 0, - WSA_FLAG_OVERLAPPED), ec); + socket_type s = ::WSASocketW(af, type, protocol, 0, 0, WSA_FLAG_OVERLAPPED); + get_last_error(ec, s == invalid_socket); if (s == invalid_socket) return s; @@ -1624,17 +1602,15 @@ socket_type socket(int af, int type, int protocol, reinterpret_cast(&optval), sizeof(optval)); } - ec = boost::system::error_code(); - return s; #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - socket_type s = error_wrapper(::socket(af, type, protocol), ec); - if (s == invalid_socket) - return s; + socket_type s = ::socket(af, type, protocol); + get_last_error(ec, s < 0); int optval = 1; - int result = error_wrapper(::setsockopt(s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + int result = ::setsockopt(s, SOL_SOCKET, + SO_NOSIGPIPE, &optval, sizeof(optval)); + get_last_error(ec, result != 0); if (result != 0) { ::close(s); @@ -1643,9 +1619,8 @@ socket_type socket(int af, int type, int protocol, return s; #else - int s = error_wrapper(::socket(af, type, protocol), ec); - if (s >= 0) - ec = boost::system::error_code(); + int s = ::socket(af, type, protocol); + get_last_error(ec, s < 0); return s; #endif } @@ -1703,22 +1678,21 @@ int setsockopt(socket_type s, state_type& state, int level, int optname, typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) { - clear_last_error(); - return error_wrapper(sso(s, level, optname, + int result = sso(s, level, optname, reinterpret_cast(optval), - static_cast(optlen)), ec); + static_cast(optlen)); + get_last_error(ec, result != 0); + return result; } } ec = boost::asio::error::fault; return socket_error_retval; #else // defined(__BORLANDC__) - clear_last_error(); - int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); + int result = call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); if (result == 0) { - ec = boost::system::error_code(); - #if defined(__MACH__) && defined(__APPLE__) \ || defined(__NetBSD__) || defined(__FreeBSD__) \ || defined(__OpenBSD__) || defined(__QNX__) @@ -1786,10 +1760,10 @@ int getsockopt(socket_type s, state_type state, int level, int optname, typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) { - clear_last_error(); int tmp_optlen = static_cast(*optlen); - int result = error_wrapper(gso(s, level, optname, - reinterpret_cast(optval), &tmp_optlen), ec); + int result = gso(s, level, optname, + reinterpret_cast(optval), &tmp_optlen); + get_last_error(ec, result != 0); *optlen = static_cast(tmp_optlen); if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) @@ -1808,9 +1782,9 @@ int getsockopt(socket_type s, state_type state, int level, int optname, ec = boost::asio::error::fault; return socket_error_retval; #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - clear_last_error(); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); + int result = call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) { @@ -1822,13 +1796,11 @@ int getsockopt(socket_type s, state_type state, int level, int optname, *static_cast(optval) = 1; ec = boost::system::error_code(); } - if (result == 0) - ec = boost::system::error_code(); return result; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - clear_last_error(); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); + int result = call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen); + get_last_error(ec, result != 0); #if defined(__linux__) if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) && (optname == SO_SNDBUF || optname == SO_RCVBUF)) @@ -1841,8 +1813,6 @@ int getsockopt(socket_type s, state_type state, int level, int optname, *static_cast(optval) /= 2; } #endif // defined(__linux__) - if (result == 0) - ec = boost::system::error_code(); return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } @@ -1894,11 +1864,8 @@ int getpeername(socket_type s, socket_addr_type* addr, #endif // defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP) // || defined(__CYGWIN__) - clear_last_error(); - int result = error_wrapper(call_getpeername( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = boost::system::error_code(); + int result = call_getpeername(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); return result; } @@ -1921,11 +1888,8 @@ int getsockname(socket_type s, socket_addr_type* addr, return socket_error_retval; } - clear_last_error(); - int result = error_wrapper(call_getsockname( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - ec = boost::system::error_code(); + int result = call_getsockname(&msghdr::msg_namelen, s, addr, addrlen); + get_last_error(ec, result != 0); return result; } @@ -1938,20 +1902,17 @@ int ioctl(socket_type s, state_type& state, int cmd, return socket_error_retval; } - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); + int result = ::ioctlsocket(s, cmd, arg); #elif defined(__MACH__) && defined(__APPLE__) \ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - int result = error_wrapper(::ioctl(s, - static_cast(cmd), arg), ec); + int result = ::ioctl(s, static_cast(cmd), arg); #else - int result = error_wrapper(::ioctl(s, cmd, arg), ec); + int result = ::ioctl(s, cmd, arg); #endif + get_last_error(ec, result < 0); if (result >= 0) { - ec = boost::system::error_code(); - // When updating the non-blocking mode we always perform the ioctl syscall, // even if the flags would otherwise indicate that the socket is already in // the correct state. This ensures that the underlying socket is put into @@ -1979,7 +1940,6 @@ int ioctl(socket_type s, state_type& state, int cmd, int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec) { - clear_last_error(); #if defined(__EMSCRIPTEN__) exceptfds = 0; #endif // defined(__EMSCRIPTEN__) @@ -2009,15 +1969,13 @@ int select(int nfds, fd_set* readfds, fd_set* writefds, timespec ts; ts.tv_sec = timeout ? timeout->tv_sec : 0; ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; - return error_wrapper(::pselect(nfds, readfds, - writefds, exceptfds, timeout ? &ts : 0, 0), ec); + int result = ::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0); #else - int result = error_wrapper(::select(nfds, readfds, - writefds, exceptfds, timeout), ec); - if (result >= 0) - ec = boost::system::error_code(); - return result; + int result = ::select(nfds, readfds, writefds, exceptfds, timeout); #endif + get_last_error(ec, result < 0); + return result; } int poll_read(socket_type s, state_type state, @@ -2051,8 +2009,8 @@ int poll_read(socket_type s, state_type state, } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select(s + 1, &fds, 0, 0, timeout), ec); + int result = ::select(s + 1, &fds, 0, 0, timeout); + get_last_error(ec, result < 0); #else // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) @@ -2061,16 +2019,14 @@ int poll_read(socket_type s, state_type state, fds.events = POLLIN; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : msec; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); #endif // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) - ec = (state & user_set_non_blocking) - ? boost::asio::error::would_block : boost::system::error_code(); - else if (result > 0) - ec = boost::system::error_code(); + if (state & user_set_non_blocking) + ec = boost::asio::error::would_block; return result; } @@ -2105,8 +2061,8 @@ int poll_write(socket_type s, state_type state, } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select(s + 1, 0, &fds, 0, timeout), ec); + int result = ::select(s + 1, 0, &fds, 0, timeout); + get_last_error(ec, result < 0); #else // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) @@ -2115,16 +2071,14 @@ int poll_write(socket_type s, state_type state, fds.events = POLLOUT; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : msec; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); #endif // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) - ec = (state & user_set_non_blocking) - ? boost::asio::error::would_block : boost::system::error_code(); - else if (result > 0) - ec = boost::system::error_code(); + if (state & user_set_non_blocking) + ec = boost::asio::error::would_block; return result; } @@ -2159,8 +2113,8 @@ int poll_error(socket_type s, state_type state, } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select(s + 1, 0, 0, &fds, timeout), ec); + int result = ::select(s + 1, 0, 0, &fds, timeout); + get_last_error(ec, result < 0); #else // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) @@ -2169,16 +2123,14 @@ int poll_error(socket_type s, state_type state, fds.events = POLLPRI | POLLERR | POLLHUP; fds.revents = 0; int timeout = (state & user_set_non_blocking) ? 0 : msec; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, timeout), ec); + int result = ::poll(&fds, 1, timeout); + get_last_error(ec, result < 0); #endif // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) - ec = (state & user_set_non_blocking) - ? boost::asio::error::would_block : boost::system::error_code(); - else if (result > 0) - ec = boost::system::error_code(); + if (state & user_set_non_blocking) + ec = boost::asio::error::would_block; return result; } @@ -2209,11 +2161,8 @@ int poll_connect(socket_type s, int msec, boost::system::error_code& ec) } else timeout = 0; - clear_last_error(); - int result = error_wrapper(::select( - s + 1, 0, &write_fds, &except_fds, timeout), ec); - if (result >= 0) - ec = boost::system::error_code(); + int result = ::select(s + 1, 0, &write_fds, &except_fds, timeout); + get_last_error(ec, result < 0); return result; #else // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) @@ -2222,10 +2171,8 @@ int poll_connect(socket_type s, int msec, boost::system::error_code& ec) fds.fd = s; fds.events = POLLOUT; fds.revents = 0; - clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, msec), ec); - if (result >= 0) - ec = boost::system::error_code(); + int result = ::poll(&fds, 1, msec); + get_last_error(ec, result < 0); return result; #endif // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) @@ -2310,13 +2257,15 @@ const char* inet_ntop(int af, const void* src, char* dest, size_t length, DWORD string_length = static_cast(length); #if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); - int result = error_wrapper(::WSAAddressToStringW(&address.base, - address_length, 0, string_buffer, &string_length), ec); + int result = ::WSAAddressToStringW(&address.base, + address_length, 0, string_buffer, &string_length); + get_last_error(ec, true); ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, static_cast(length), 0, 0); #else - int result = error_wrapper(::WSAAddressToStringA( - &address.base, address_length, 0, dest, &string_length), ec); + int result = ::WSAAddressToStringA(&address.base, + address_length, 0, dest, &string_length); + get_last_error(ec, true); #endif // Windows may set error code on success. @@ -2329,8 +2278,8 @@ const char* inet_ntop(int af, const void* src, char* dest, size_t length, return result == socket_error_retval ? 0 : dest; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - const char* result = error_wrapper(::inet_ntop( - af, src, dest, static_cast(length)), ec); + const char* result = ::inet_ntop(af, src, dest, static_cast(length)); + get_last_error(ec, true); if (result == 0 && !ec) ec = boost::asio::error::invalid_argument; if (result != 0 && af == BOOST_ASIO_OS_DEF(AF_INET6) && scope_id != 0) @@ -2520,11 +2469,13 @@ int inet_pton(int af, const char* src, void* dest, int num_wide_chars = static_cast(strlen(src)) + 1; LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); - int result = error_wrapper(::WSAStringToAddressW( - wide_buffer, af, 0, &address.base, &address_length), ec); + int result = ::WSAStringToAddressW(wide_buffer, + af, 0, &address.base, &address_length); + get_last_error(ec, true); #else - int result = error_wrapper(::WSAStringToAddressA( - const_cast(src), af, 0, &address.base, &address_length), ec); + int result = ::WSAStringToAddressA(const_cast(src), + af, 0, &address.base, &address_length); + get_last_error(ec, true); #endif if (af == BOOST_ASIO_OS_DEF(AF_INET)) @@ -2580,7 +2531,8 @@ int inet_pton(int af, const char* src, void* dest, src_ptr = src_buf; } - int result = error_wrapper(::inet_pton(af, src_ptr, dest), ec); + int result = ::inet_pton(af, src_ptr, dest); + get_last_error(ec, true); if (result <= 0 && !ec) ec = boost::asio::error::invalid_argument; if (result > 0 && is_v6 && scope_id) @@ -2606,7 +2558,6 @@ int inet_pton(int af, const char* src, void* dest, int gethostname(char* name, int namelen, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS_RUNTIME) try { @@ -2637,11 +2588,8 @@ int gethostname(char* name, int namelen, boost::system::error_code& ec) return -1; } #else // defined(BOOST_ASIO_WINDOWS_RUNTIME) - int result = error_wrapper(::gethostname(name, namelen), ec); -# if defined(BOOST_ASIO_WINDOWS) - if (result == 0) - ec = boost::system::error_code(); -# endif // defined(BOOST_ASIO_WINDOWS) + int result = ::gethostname(name, namelen); + get_last_error(ec, result != 0); return result; #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) } @@ -2676,20 +2624,20 @@ inline boost::system::error_code translate_netdb_error(int error) inline hostent* gethostbyaddr(const char* addr, int length, int af, hostent* result, char* buffer, int buflength, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); - hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); + hostent* retval = ::gethostbyaddr(addr, length, af); + get_last_error(ec, !retval); if (!retval) return 0; - ec = boost::system::error_code(); *result = *retval; return retval; #elif defined(__sun) || defined(__QNX__) int error = 0; - hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, - buffer, buflength, &error), ec); + hostent* retval = ::gethostbyaddr_r(addr, length, + af, result, buffer, buflength, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); return retval; @@ -2697,8 +2645,8 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, (void)(buffer); (void)(buflength); int error = 0; - hostent* retval = error_wrapper(::getipnodebyaddr( - addr, length, af, &error), ec); + hostent* retval = ::getipnodebyaddr(addr, length, af, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); if (!retval) @@ -2708,8 +2656,10 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, #else hostent* retval = 0; int error = 0; - error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, - buflength, &retval, &error), ec); + clear_last_error(); + ::gethostbyaddr_r(addr, length, af, result, + buffer, buflength, &retval, &error); + get_last_error(ec, true); if (error) ec = translate_netdb_error(error); return retval; @@ -2719,7 +2669,6 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, inline hostent* gethostbyname(const char* name, int af, struct hostent* result, char* buffer, int buflength, int ai_flags, boost::system::error_code& ec) { - clear_last_error(); #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); @@ -2729,10 +2678,10 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, ec = boost::asio::error::address_family_not_supported; return 0; } - hostent* retval = error_wrapper(::gethostbyname(name), ec); + hostent* retval = ::gethostbyname(name); + get_last_error(ec, !retval); if (!retval) return 0; - ec = boost::system::error_code(); *result = *retval; return result; #elif defined(__sun) || defined(__QNX__) @@ -2743,8 +2692,8 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, return 0; } int error = 0; - hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, - buflength, &error), ec); + hostent* retval = ::gethostbyname_r(name, result, buffer, buflength, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); return retval; @@ -2752,8 +2701,8 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, (void)(buffer); (void)(buflength); int error = 0; - hostent* retval = error_wrapper(::getipnodebyname( - name, af, ai_flags, &error), ec); + hostent* retval = ::getipnodebyname(name, af, ai_flags, &error); + get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); if (!retval) @@ -2769,8 +2718,9 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, } hostent* retval = 0; int error = 0; - error_wrapper(::gethostbyname_r(name, result, - buffer, buflength, &retval, &error), ec); + clear_last_error(); + ::gethostbyname_r(name, result, buffer, buflength, &retval, &error); + get_last_error(ec, true); if (error) ec = translate_netdb_error(error); return retval; diff --git a/include/boost/asio/detail/reactive_serial_port_service.hpp b/include/boost/asio/detail/reactive_serial_port_service.hpp index 8f50f5b1..776762fc 100644 --- a/include/boost/asio/detail/reactive_serial_port_service.hpp +++ b/include/boost/asio/detail/reactive_serial_port_service.hpp @@ -140,9 +140,8 @@ public: boost::system::error_code send_break(implementation_type& impl, boost::system::error_code& ec) { - errno = 0; - descriptor_ops::error_wrapper(::tcsendbreak( - descriptor_service_.native_handle(impl), 0), ec); + int result = ::tcsendbreak(descriptor_service_.native_handle(impl), 0); + descriptor_ops::get_last_error(ec, result < 0); return ec; } From b614b8d56cbaf903542b4120e6e8221b73a612db Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:26:58 +1000 Subject: [PATCH 31/90] Return earlier on success in send/receive and read/write operations. --- .../boost/asio/detail/impl/descriptor_ops.ipp | 36 ++--- include/boost/asio/detail/impl/socket_ops.ipp | 126 +++++++++--------- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/include/boost/asio/detail/impl/descriptor_ops.ipp b/include/boost/asio/detail/impl/descriptor_ops.ipp index 3eb1dc45..c575b273 100644 --- a/include/boost/asio/detail/impl/descriptor_ops.ipp +++ b/include/boost/asio/detail/impl/descriptor_ops.ipp @@ -222,6 +222,13 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count, return true; } + // Check if operation succeeded. + if (bytes > 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) continue; @@ -231,15 +238,8 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count, || ec == boost::asio::error::try_again) return false; - // Operation is complete. - if (bytes > 0) - { - ec = boost::system::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } @@ -292,6 +292,13 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count, signed_size_type bytes = ::writev(d, bufs, static_cast(count)); get_last_error(ec, bytes < 0); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) continue; @@ -301,15 +308,8 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count, || ec == boost::asio::error::try_again) return false; - // Operation is complete. - if (bytes >= 0) - { - ec = boost::system::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } diff --git a/include/boost/asio/detail/impl/socket_ops.ipp b/include/boost/asio/detail/impl/socket_ops.ipp index 684fe605..0d7eb84b 100644 --- a/include/boost/asio/detail/impl/socket_ops.ipp +++ b/include/boost/asio/detail/impl/socket_ops.ipp @@ -946,6 +946,13 @@ bool non_blocking_recv(socket_type s, return true; } + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) continue; @@ -955,15 +962,8 @@ bool non_blocking_recv(socket_type s, || ec == boost::asio::error::try_again) return false; - // Operation is complete. - if (bytes >= 0) - { - ec = boost::system::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } @@ -984,6 +984,13 @@ bool non_blocking_recv1(socket_type s, return true; } + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) continue; @@ -993,15 +1000,8 @@ bool non_blocking_recv1(socket_type s, || ec == boost::asio::error::try_again) return false; - // Operation is complete. - if (bytes >= 0) - { - ec = boost::system::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1115,6 +1115,13 @@ bool non_blocking_recvfrom(socket_type s, signed_size_type bytes = socket_ops::recvfrom( s, bufs, count, flags, addr, addrlen, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) continue; @@ -1124,15 +1131,8 @@ bool non_blocking_recvfrom(socket_type s, || ec == boost::asio::error::try_again) return false; - // Operation is complete. - if (bytes >= 0) - { - ec = boost::system::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1228,6 +1228,13 @@ bool non_blocking_recvmsg(socket_type s, signed_size_type bytes = socket_ops::recvmsg( s, bufs, count, in_flags, out_flags, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) continue; @@ -1237,15 +1244,8 @@ bool non_blocking_recvmsg(socket_type s, || ec == boost::asio::error::try_again) return false; - // Operation is complete. - if (bytes >= 0) - { - ec = boost::system::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1423,6 +1423,13 @@ bool non_blocking_send(socket_type s, // Write some data. signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) continue; @@ -1432,15 +1439,8 @@ bool non_blocking_send(socket_type s, || ec == boost::asio::error::try_again) return false; - // Operation is complete. - if (bytes >= 0) - { - ec = boost::system::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1454,6 +1454,13 @@ bool non_blocking_send1(socket_type s, // Write some data. signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) continue; @@ -1463,15 +1470,8 @@ bool non_blocking_send1(socket_type s, || ec == boost::asio::error::try_again) return false; - // Operation is complete. - if (bytes >= 0) - { - ec = boost::system::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } @@ -1559,6 +1559,13 @@ bool non_blocking_sendto(socket_type s, signed_size_type bytes = socket_ops::sendto( s, bufs, count, flags, addr, addrlen, ec); + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) continue; @@ -1568,15 +1575,8 @@ bool non_blocking_sendto(socket_type s, || ec == boost::asio::error::try_again) return false; - // Operation is complete. - if (bytes >= 0) - { - ec = boost::system::error_code(); - bytes_transferred = bytes; - } - else - bytes_transferred = 0; - + // Operation failed. + bytes_transferred = 0; return true; } } From bd514b467f75fbe6b889eec74a32c066f81c5f72 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:27:27 +1000 Subject: [PATCH 32/90] Use a cached success error code to avoid touching the category singleton. --- .../boost/asio/detail/descriptor_read_op.hpp | 13 ++++--- .../boost/asio/detail/descriptor_write_op.hpp | 13 ++++--- .../asio/detail/impl/signal_set_service.ipp | 3 +- .../detail/reactive_descriptor_service.hpp | 13 ++++--- .../asio/detail/reactive_null_buffers_op.hpp | 5 +-- .../asio/detail/reactive_socket_accept_op.hpp | 34 +++++++++++-------- .../detail/reactive_socket_connect_op.hpp | 12 ++++--- .../asio/detail/reactive_socket_recv_op.hpp | 15 ++++---- .../detail/reactive_socket_recvfrom_op.hpp | 11 +++--- .../detail/reactive_socket_recvmsg_op.hpp | 18 ++++++---- .../asio/detail/reactive_socket_send_op.hpp | 13 ++++--- .../asio/detail/reactive_socket_sendto_op.hpp | 23 +++++++------ .../asio/detail/reactive_socket_service.hpp | 22 ++++++------ .../detail/reactive_socket_service_base.hpp | 23 +++++++------ .../boost/asio/detail/reactive_wait_op.hpp | 5 +-- include/boost/asio/detail/reactor_op.hpp | 4 ++- .../asio/detail/win_iocp_null_buffers_op.hpp | 3 +- .../detail/win_iocp_socket_connect_op.hpp | 3 +- .../boost/asio/detail/win_iocp_wait_op.hpp | 3 +- 19 files changed, 139 insertions(+), 97 deletions(-) diff --git a/include/boost/asio/detail/descriptor_read_op.hpp b/include/boost/asio/detail/descriptor_read_op.hpp index f0b6be7b..f63fa4bf 100644 --- a/include/boost/asio/detail/descriptor_read_op.hpp +++ b/include/boost/asio/detail/descriptor_read_op.hpp @@ -37,9 +37,11 @@ template class descriptor_read_op_base : public reactor_op { public: - descriptor_read_op_base(int descriptor, - const MutableBufferSequence& buffers, func_type complete_func) - : reactor_op(&descriptor_read_op_base::do_perform, complete_func), + descriptor_read_op_base(const boost::system::error_code& success_ec, + int descriptor, const MutableBufferSequence& buffers, + func_type complete_func) + : reactor_op(success_ec, + &descriptor_read_op_base::do_perform, complete_func), descriptor_(descriptor), buffers_(buffers) { @@ -74,9 +76,10 @@ class descriptor_read_op public: BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); - descriptor_read_op(int descriptor, const MutableBufferSequence& buffers, + descriptor_read_op(const boost::system::error_code& success_ec, + int descriptor, const MutableBufferSequence& buffers, Handler& handler, const IoExecutor& io_ex) - : descriptor_read_op_base( + : descriptor_read_op_base(success_ec, descriptor, buffers, &descriptor_read_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) diff --git a/include/boost/asio/detail/descriptor_write_op.hpp b/include/boost/asio/detail/descriptor_write_op.hpp index abc36a5b..94759d03 100644 --- a/include/boost/asio/detail/descriptor_write_op.hpp +++ b/include/boost/asio/detail/descriptor_write_op.hpp @@ -37,9 +37,11 @@ template class descriptor_write_op_base : public reactor_op { public: - descriptor_write_op_base(int descriptor, - const ConstBufferSequence& buffers, func_type complete_func) - : reactor_op(&descriptor_write_op_base::do_perform, complete_func), + descriptor_write_op_base(const boost::system::error_code& success_ec, + int descriptor, const ConstBufferSequence& buffers, + func_type complete_func) + : reactor_op(success_ec, + &descriptor_write_op_base::do_perform, complete_func), descriptor_(descriptor), buffers_(buffers) { @@ -74,9 +76,10 @@ class descriptor_write_op public: BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); - descriptor_write_op(int descriptor, const ConstBufferSequence& buffers, + descriptor_write_op(const boost::system::error_code& success_ec, + int descriptor, const ConstBufferSequence& buffers, Handler& handler, const IoExecutor& io_ex) - : descriptor_write_op_base( + : descriptor_write_op_base(success_ec, descriptor, buffers, &descriptor_write_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) diff --git a/include/boost/asio/detail/impl/signal_set_service.ipp b/include/boost/asio/detail/impl/signal_set_service.ipp index b4e45686..421f8387 100644 --- a/include/boost/asio/detail/impl/signal_set_service.ipp +++ b/include/boost/asio/detail/impl/signal_set_service.ipp @@ -90,7 +90,8 @@ class signal_set_service::pipe_read_op : public reactor_op { public: pipe_read_op() - : reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete) + : reactor_op(boost::system::error_code(), + &pipe_read_op::do_perform, pipe_read_op::do_complete) { } diff --git a/include/boost/asio/detail/reactive_descriptor_service.hpp b/include/boost/asio/detail/reactive_descriptor_service.hpp index bdd3a426..9c91e7cb 100644 --- a/include/boost/asio/detail/reactive_descriptor_service.hpp +++ b/include/boost/asio/detail/reactive_descriptor_service.hpp @@ -202,7 +202,7 @@ public: typedef reactive_wait_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler, io_ex); + p.p = new (p.v) op(success_ec_, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_wait")); @@ -266,7 +266,7 @@ public: typedef descriptor_write_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.descriptor_, buffers, handler, io_ex); + p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_write_some")); @@ -289,7 +289,7 @@ public: typedef reactive_null_buffers_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler, io_ex); + p.p = new (p.v) op(success_ec_, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_write_some(null_buffers)")); @@ -335,7 +335,7 @@ public: typedef descriptor_read_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.descriptor_, buffers, handler, io_ex); + p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_read_some")); @@ -358,7 +358,7 @@ public: typedef reactive_null_buffers_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler, io_ex); + p.p = new (p.v) op(success_ec_, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_read_some(null_buffers)")); @@ -374,6 +374,9 @@ private: // The selector that performs event demultiplexing for the service. reactor& reactor_; + + // Cached success value to avoid accessing category singleton. + const boost::system::error_code success_ec_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_null_buffers_op.hpp b/include/boost/asio/detail/reactive_null_buffers_op.hpp index efa91902..ecdca8b5 100644 --- a/include/boost/asio/detail/reactive_null_buffers_op.hpp +++ b/include/boost/asio/detail/reactive_null_buffers_op.hpp @@ -34,8 +34,9 @@ class reactive_null_buffers_op : public reactor_op public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); - reactive_null_buffers_op(Handler& handler, const IoExecutor& io_ex) - : reactor_op(&reactive_null_buffers_op::do_perform, + reactive_null_buffers_op(const boost::system::error_code& success_ec, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(success_ec, &reactive_null_buffers_op::do_perform, &reactive_null_buffers_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) diff --git a/include/boost/asio/detail/reactive_socket_accept_op.hpp b/include/boost/asio/detail/reactive_socket_accept_op.hpp index f182caa7..b2e84dd7 100644 --- a/include/boost/asio/detail/reactive_socket_accept_op.hpp +++ b/include/boost/asio/detail/reactive_socket_accept_op.hpp @@ -34,10 +34,12 @@ template class reactive_socket_accept_op_base : public reactor_op { public: - reactive_socket_accept_op_base(socket_type socket, - socket_ops::state_type state, Socket& peer, const Protocol& protocol, - typename Protocol::endpoint* peer_endpoint, func_type complete_func) - : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func), + reactive_socket_accept_op_base(const boost::system::error_code& success_ec, + socket_type socket, socket_ops::state_type state, Socket& peer, + const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, + func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_accept_op_base::do_perform, complete_func), socket_(socket), state_(state), peer_(peer), @@ -94,12 +96,13 @@ class reactive_socket_accept_op : public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); - reactive_socket_accept_op(socket_type socket, - socket_ops::state_type state, Socket& peer, const Protocol& protocol, - typename Protocol::endpoint* peer_endpoint, Handler& handler, - const IoExecutor& io_ex) - : reactive_socket_accept_op_base(socket, state, peer, - protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), + reactive_socket_accept_op(const boost::system::error_code& success_ec, + socket_type socket, socket_ops::state_type state, Socket& peer, + const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_accept_op_base( + success_ec, socket, state, peer, protocol, peer_endpoint, + &reactive_socket_accept_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) { @@ -160,13 +163,14 @@ class reactive_socket_move_accept_op : public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op); - reactive_socket_move_accept_op(const PeerIoExecutor& peer_io_ex, - socket_type socket, socket_ops::state_type state, - const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, - Handler& handler, const IoExecutor& io_ex) + reactive_socket_move_accept_op(const boost::system::error_code& success_ec, + const PeerIoExecutor& peer_io_ex, socket_type socket, + socket_ops::state_type state, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler& handler, + const IoExecutor& io_ex) : peer_socket_type(peer_io_ex), reactive_socket_accept_op_base( - socket, state, *this, protocol, peer_endpoint, + success_ec, socket, state, *this, protocol, peer_endpoint, &reactive_socket_move_accept_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) diff --git a/include/boost/asio/detail/reactive_socket_connect_op.hpp b/include/boost/asio/detail/reactive_socket_connect_op.hpp index b0a31c08..f5162765 100644 --- a/include/boost/asio/detail/reactive_socket_connect_op.hpp +++ b/include/boost/asio/detail/reactive_socket_connect_op.hpp @@ -32,8 +32,10 @@ namespace detail { class reactive_socket_connect_op_base : public reactor_op { public: - reactive_socket_connect_op_base(socket_type socket, func_type complete_func) - : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func), + reactive_socket_connect_op_base(const boost::system::error_code& success_ec, + socket_type socket, func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_connect_op_base::do_perform, complete_func), socket_(socket) { } @@ -61,9 +63,9 @@ class reactive_socket_connect_op : public reactive_socket_connect_op_base public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); - reactive_socket_connect_op(socket_type socket, - Handler& handler, const IoExecutor& io_ex) - : reactive_socket_connect_op_base(socket, + reactive_socket_connect_op(const boost::system::error_code& success_ec, + socket_type socket, Handler& handler, const IoExecutor& io_ex) + : reactive_socket_connect_op_base(success_ec, socket, &reactive_socket_connect_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) diff --git a/include/boost/asio/detail/reactive_socket_recv_op.hpp b/include/boost/asio/detail/reactive_socket_recv_op.hpp index e0e43c84..5d834a5c 100644 --- a/include/boost/asio/detail/reactive_socket_recv_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recv_op.hpp @@ -33,10 +33,12 @@ template class reactive_socket_recv_op_base : public reactor_op { public: - reactive_socket_recv_op_base(socket_type socket, - socket_ops::state_type state, const MutableBufferSequence& buffers, + reactive_socket_recv_op_base(const boost::system::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, socket_base::message_flags flags, func_type complete_func) - : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func), + : reactor_op(success_ec, + &reactive_socket_recv_op_base::do_perform, complete_func), socket_(socket), state_(state), buffers_(buffers), @@ -95,11 +97,12 @@ class reactive_socket_recv_op : public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); - reactive_socket_recv_op(socket_type socket, socket_ops::state_type state, + reactive_socket_recv_op(const boost::system::error_code& success_ec, + socket_type socket, socket_ops::state_type state, const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler& handler, const IoExecutor& io_ex) - : reactive_socket_recv_op_base(socket, state, - buffers, flags, &reactive_socket_recv_op::do_complete), + : reactive_socket_recv_op_base(success_ec, socket, + state, buffers, flags, &reactive_socket_recv_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) { diff --git a/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp index 9f641d58..17554000 100644 --- a/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp @@ -33,10 +33,12 @@ template class reactive_socket_recvfrom_op_base : public reactor_op { public: - reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type, + reactive_socket_recvfrom_op_base(const boost::system::error_code& success_ec, + socket_type socket, int protocol_type, const MutableBufferSequence& buffers, Endpoint& endpoint, socket_base::message_flags flags, func_type complete_func) - : reactor_op(&reactive_socket_recvfrom_op_base::do_perform, complete_func), + : reactor_op(success_ec, + &reactive_socket_recvfrom_op_base::do_perform, complete_func), socket_(socket), protocol_type_(protocol_type), buffers_(buffers), @@ -84,12 +86,13 @@ class reactive_socket_recvfrom_op : public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); - reactive_socket_recvfrom_op(socket_type socket, int protocol_type, + reactive_socket_recvfrom_op(const boost::system::error_code& success_ec, + socket_type socket, int protocol_type, const MutableBufferSequence& buffers, Endpoint& endpoint, socket_base::message_flags flags, Handler& handler, const IoExecutor& io_ex) : reactive_socket_recvfrom_op_base( - socket, protocol_type, buffers, endpoint, flags, + success_ec, socket, protocol_type, buffers, endpoint, flags, &reactive_socket_recvfrom_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) diff --git a/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp b/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp index d4472c49..1f1b2df1 100644 --- a/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp @@ -34,10 +34,12 @@ template class reactive_socket_recvmsg_op_base : public reactor_op { public: - reactive_socket_recvmsg_op_base(socket_type socket, - const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + reactive_socket_recvmsg_op_base(const boost::system::error_code& success_ec, + socket_type socket, const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, socket_base::message_flags& out_flags, func_type complete_func) - : reactor_op(&reactive_socket_recvmsg_op_base::do_perform, complete_func), + : reactor_op(success_ec, + &reactive_socket_recvmsg_op_base::do_perform, complete_func), socket_(socket), buffers_(buffers), in_flags_(in_flags), @@ -78,12 +80,14 @@ class reactive_socket_recvmsg_op : public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op); - reactive_socket_recvmsg_op(socket_type socket, - const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + reactive_socket_recvmsg_op(const boost::system::error_code& success_ec, + socket_type socket, const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, socket_base::message_flags& out_flags, Handler& handler, const IoExecutor& io_ex) - : reactive_socket_recvmsg_op_base(socket, buffers, - in_flags, out_flags, &reactive_socket_recvmsg_op::do_complete), + : reactive_socket_recvmsg_op_base( + success_ec, socket, buffers, in_flags, out_flags, + &reactive_socket_recvmsg_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) { diff --git a/include/boost/asio/detail/reactive_socket_send_op.hpp b/include/boost/asio/detail/reactive_socket_send_op.hpp index 031d01c3..e38b9d08 100644 --- a/include/boost/asio/detail/reactive_socket_send_op.hpp +++ b/include/boost/asio/detail/reactive_socket_send_op.hpp @@ -33,10 +33,12 @@ template class reactive_socket_send_op_base : public reactor_op { public: - reactive_socket_send_op_base(socket_type socket, - socket_ops::state_type state, const ConstBufferSequence& buffers, + reactive_socket_send_op_base(const boost::system::error_code& success_ec, + socket_type socket, socket_ops::state_type state, + const ConstBufferSequence& buffers, socket_base::message_flags flags, func_type complete_func) - : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func), + : reactor_op(success_ec, + &reactive_socket_send_op_base::do_perform, complete_func), socket_(socket), state_(state), buffers_(buffers), @@ -98,10 +100,11 @@ class reactive_socket_send_op : public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); - reactive_socket_send_op(socket_type socket, socket_ops::state_type state, + reactive_socket_send_op(const boost::system::error_code& success_ec, + socket_type socket, socket_ops::state_type state, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler& handler, const IoExecutor& io_ex) - : reactive_socket_send_op_base(socket, + : reactive_socket_send_op_base(success_ec, socket, state, buffers, flags, &reactive_socket_send_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) diff --git a/include/boost/asio/detail/reactive_socket_sendto_op.hpp b/include/boost/asio/detail/reactive_socket_sendto_op.hpp index a4366ddd..c4b5c454 100644 --- a/include/boost/asio/detail/reactive_socket_sendto_op.hpp +++ b/include/boost/asio/detail/reactive_socket_sendto_op.hpp @@ -33,10 +33,12 @@ template class reactive_socket_sendto_op_base : public reactor_op { public: - reactive_socket_sendto_op_base(socket_type socket, - const ConstBufferSequence& buffers, const Endpoint& endpoint, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func), + reactive_socket_sendto_op_base(const boost::system::error_code& success_ec, + socket_type socket, const ConstBufferSequence& buffers, + const Endpoint& endpoint, socket_base::message_flags flags, + func_type complete_func) + : reactor_op(success_ec, + &reactive_socket_sendto_op_base::do_perform, complete_func), socket_(socket), buffers_(buffers), destination_(endpoint), @@ -78,12 +80,13 @@ class reactive_socket_sendto_op : public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); - reactive_socket_sendto_op(socket_type socket, - const ConstBufferSequence& buffers, const Endpoint& endpoint, - socket_base::message_flags flags, Handler& handler, - const IoExecutor& io_ex) - : reactive_socket_sendto_op_base(socket, - buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), + reactive_socket_sendto_op(const boost::system::error_code& success_ec, + socket_type socket, const ConstBufferSequence& buffers, + const Endpoint& endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_sendto_op_base( + success_ec, socket, buffers, endpoint, flags, + &reactive_socket_sendto_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) { diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 9cc0db30..01249521 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -255,8 +255,8 @@ public: endpoint_type, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, buffers, - destination, flags, handler, io_ex); + p.p = new (p.v) op(success_ec_, impl.socket_, + buffers, destination, flags, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send_to")); @@ -278,7 +278,7 @@ public: typedef reactive_null_buffers_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler, io_ex); + p.p = new (p.v) op(success_ec_, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send_to(null_buffers)")); @@ -342,8 +342,8 @@ public: typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; int protocol = impl.protocol_.type(); - p.p = new (p.v) op(impl.socket_, protocol, buffers, - sender_endpoint, flags, handler, io_ex); + p.p = new (p.v) op(success_ec_, impl.socket_, protocol, + buffers, sender_endpoint, flags, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_from")); @@ -368,7 +368,7 @@ public: typedef reactive_null_buffers_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler, io_ex); + p.p = new (p.v) op(success_ec_, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_from(null_buffers)")); @@ -426,8 +426,8 @@ public: typedef reactive_socket_accept_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, impl.state_, peer, - impl.protocol_, peer_endpoint, handler, io_ex); + p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, + peer, impl.protocol_, peer_endpoint, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_accept")); @@ -452,8 +452,8 @@ public: PeerIoExecutor, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(peer_io_ex, impl.socket_, impl.state_, - impl.protocol_, peer_endpoint, handler, io_ex); + p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_, + impl.state_, impl.protocol_, peer_endpoint, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_accept")); @@ -485,7 +485,7 @@ public: typedef reactive_socket_connect_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, handler, io_ex); + p.p = new (p.v) op(success_ec_, impl.socket_, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_connect")); diff --git a/include/boost/asio/detail/reactive_socket_service_base.hpp b/include/boost/asio/detail/reactive_socket_service_base.hpp index 5ed63dde..29b379f0 100644 --- a/include/boost/asio/detail/reactive_socket_service_base.hpp +++ b/include/boost/asio/detail/reactive_socket_service_base.hpp @@ -204,7 +204,7 @@ public: typedef reactive_wait_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler, io_ex); + p.p = new (p.v) op(success_ec_, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_wait")); @@ -280,8 +280,8 @@ public: ConstBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, impl.state_, - buffers, flags, handler, io_ex); + p.p = new (p.v) op(success_ec_, impl.socket_, + impl.state_, buffers, flags, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send")); @@ -305,7 +305,7 @@ public: typedef reactive_null_buffers_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler, io_ex); + p.p = new (p.v) op(success_ec_, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_send(null_buffers)")); @@ -363,8 +363,8 @@ public: MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, impl.state_, - buffers, flags, handler, io_ex); + p.p = new (p.v) op(success_ec_, impl.socket_, + impl.state_, buffers, flags, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive")); @@ -393,7 +393,7 @@ public: typedef reactive_null_buffers_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler, io_ex); + p.p = new (p.v) op(success_ec_, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive(null_buffers)")); @@ -452,8 +452,8 @@ public: MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(impl.socket_, buffers, - in_flags, out_flags, handler, io_ex); + p.p = new (p.v) op(success_ec_, impl.socket_, + buffers, in_flags, out_flags, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_with_flags")); @@ -480,7 +480,7 @@ public: typedef reactive_null_buffers_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler, io_ex); + p.p = new (p.v) op(success_ec_, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); @@ -522,6 +522,9 @@ protected: // The selector that performs event demultiplexing for the service. reactor& reactor_; + + // Cached success value to avoid accessing category singleton. + const boost::system::error_code success_ec_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_wait_op.hpp b/include/boost/asio/detail/reactive_wait_op.hpp index f8b1b18d..023e9c44 100644 --- a/include/boost/asio/detail/reactive_wait_op.hpp +++ b/include/boost/asio/detail/reactive_wait_op.hpp @@ -34,8 +34,9 @@ class reactive_wait_op : public reactor_op public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_wait_op); - reactive_wait_op(Handler& handler, const IoExecutor& io_ex) - : reactor_op(&reactive_wait_op::do_perform, + reactive_wait_op(const boost::system::error_code& success_ec, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(success_ec, &reactive_wait_op::do_perform, &reactive_wait_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), io_executor_(io_ex) diff --git a/include/boost/asio/detail/reactor_op.hpp b/include/boost/asio/detail/reactor_op.hpp index 4ec24326..5985e935 100644 --- a/include/boost/asio/detail/reactor_op.hpp +++ b/include/boost/asio/detail/reactor_op.hpp @@ -47,8 +47,10 @@ public: protected: typedef status (*perform_func_type)(reactor_op*); - reactor_op(perform_func_type perform_func, func_type complete_func) + reactor_op(const boost::system::error_code& success_ec, + perform_func_type perform_func, func_type complete_func) : operation(complete_func), + ec_(success_ec), bytes_transferred_(0), perform_func_(perform_func) { diff --git a/include/boost/asio/detail/win_iocp_null_buffers_op.hpp b/include/boost/asio/detail/win_iocp_null_buffers_op.hpp index f0615659..335f0269 100644 --- a/include/boost/asio/detail/win_iocp_null_buffers_op.hpp +++ b/include/boost/asio/detail/win_iocp_null_buffers_op.hpp @@ -43,7 +43,8 @@ public: win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token, Handler& handler, const IoExecutor& io_ex) - : reactor_op(&win_iocp_null_buffers_op::do_perform, + : reactor_op(boost::system::error_code(), + &win_iocp_null_buffers_op::do_perform, &win_iocp_null_buffers_op::do_complete), cancel_token_(cancel_token), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), diff --git a/include/boost/asio/detail/win_iocp_socket_connect_op.hpp b/include/boost/asio/detail/win_iocp_socket_connect_op.hpp index 5b53fe25..25319303 100644 --- a/include/boost/asio/detail/win_iocp_socket_connect_op.hpp +++ b/include/boost/asio/detail/win_iocp_socket_connect_op.hpp @@ -38,7 +38,8 @@ class win_iocp_socket_connect_op_base : public reactor_op { public: win_iocp_socket_connect_op_base(socket_type socket, func_type complete_func) - : reactor_op(&win_iocp_socket_connect_op_base::do_perform, complete_func), + : reactor_op(boost::system::error_code(), + &win_iocp_socket_connect_op_base::do_perform, complete_func), socket_(socket), connect_ex_(false) { diff --git a/include/boost/asio/detail/win_iocp_wait_op.hpp b/include/boost/asio/detail/win_iocp_wait_op.hpp index bf93e4a6..41ee2624 100644 --- a/include/boost/asio/detail/win_iocp_wait_op.hpp +++ b/include/boost/asio/detail/win_iocp_wait_op.hpp @@ -43,7 +43,8 @@ public: win_iocp_wait_op(socket_ops::weak_cancel_token_type cancel_token, Handler& handler, const IoExecutor& io_ex) - : reactor_op(&win_iocp_wait_op::do_perform, + : reactor_op(boost::system::error_code(), + &win_iocp_wait_op::do_perform, &win_iocp_wait_op::do_complete), cancel_token_(cancel_token), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), From bed41e4f4c4bac1754d36154f53c7383f01ee2d9 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:28:15 +1000 Subject: [PATCH 33/90] On success, zero only the error_code value. --- include/boost/asio/detail/descriptor_ops.hpp | 2 +- .../boost/asio/detail/impl/descriptor_ops.ipp | 4 +- include/boost/asio/detail/impl/socket_ops.ipp | 54 +++++++++---------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/include/boost/asio/detail/descriptor_ops.hpp b/include/boost/asio/detail/descriptor_ops.hpp index bc596a3a..3ff4a637 100644 --- a/include/boost/asio/detail/descriptor_ops.hpp +++ b/include/boost/asio/detail/descriptor_ops.hpp @@ -56,7 +56,7 @@ inline void get_last_error( { if (!is_error_condition) { - ec = boost::system::error_code(); + ec.assign(0, ec.category()); } else { diff --git a/include/boost/asio/detail/impl/descriptor_ops.ipp b/include/boost/asio/detail/impl/descriptor_ops.ipp index c575b273..338b29cd 100644 --- a/include/boost/asio/detail/impl/descriptor_ops.ipp +++ b/include/boost/asio/detail/impl/descriptor_ops.ipp @@ -172,7 +172,7 @@ std::size_t sync_read(int d, state_type state, buf* bufs, // A request to read 0 bytes on a stream is a no-op. if (all_empty) { - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -256,7 +256,7 @@ std::size_t sync_write(int d, state_type state, const buf* bufs, // A request to write 0 bytes on a stream is a no-op. if (all_empty) { - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 0; } diff --git a/include/boost/asio/detail/impl/socket_ops.ipp b/include/boost/asio/detail/impl/socket_ops.ipp index 0d7eb84b..695ccdc3 100644 --- a/include/boost/asio/detail/impl/socket_ops.ipp +++ b/include/boost/asio/detail/impl/socket_ops.ipp @@ -79,7 +79,7 @@ inline void get_last_error( { if (!is_error_condition) { - ec = boost::system::error_code(); + ec.assign(0, ec.category()); } else { @@ -130,7 +130,7 @@ socket_type accept(socket_type s, socket_addr_type* addr, } #endif - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return new_s; } @@ -597,7 +597,7 @@ bool non_blocking_connect(socket_type s, boost::system::error_code& ec) boost::asio::error::get_system_category()); } else - ec = boost::system::error_code(); + ec.assign(0, ec.category()); } return true; @@ -764,7 +764,7 @@ signed_size_type recv(socket_type s, buf* bufs, size_t count, result = 0; if (result != 0) return socket_error_retval; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -797,7 +797,7 @@ signed_size_type recv1(socket_type s, void* data, size_t size, result = 0; if (result != 0) return socket_error_retval; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) signed_size_type result = ::recv(s, static_cast(data), size, flags); @@ -818,7 +818,7 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, // A request to read 0 bytes on a stream is a no-op. if (all_empty && (state & stream_oriented)) { - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -863,7 +863,7 @@ size_t sync_recv1(socket_type s, state_type state, void* data, // A request to read 0 bytes on a stream is a no-op. if (size == 0 && (state & stream_oriented)) { - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -1030,7 +1030,7 @@ signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, result = 0; if (result != 0) return socket_error_retval; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -1269,7 +1269,7 @@ signed_size_type send(socket_type s, const buf* bufs, size_t count, ec = boost::asio::error::connection_refused; if (result != 0) return socket_error_retval; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -1303,7 +1303,7 @@ signed_size_type send1(socket_type s, const void* data, size_t size, ec = boost::asio::error::connection_refused; if (result != 0) return socket_error_retval; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #if defined(__linux__) @@ -1328,7 +1328,7 @@ size_t sync_send(socket_type s, state_type state, const buf* bufs, // A request to write 0 bytes to a stream is a no-op. if (all_empty && (state & stream_oriented)) { - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -1366,7 +1366,7 @@ size_t sync_send1(socket_type s, state_type state, const void* data, // A request to write 0 bytes to a stream is a no-op. if (size == 0 && (state & stream_oriented)) { - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -1496,7 +1496,7 @@ signed_size_type sendto(socket_type s, const buf* bufs, size_t count, ec = boost::asio::error::connection_refused; if (result != 0) return socket_error_retval; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); @@ -1662,7 +1662,7 @@ int setsockopt(socket_type s, state_type& state, int level, int optname, state |= enable_connection_aborted; else state &= ~enable_connection_aborted; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -1747,7 +1747,7 @@ int getsockopt(socket_type s, state_type state, int level, int optname, } *static_cast(optval) = (state & enable_connection_aborted) ? 1 : 0; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -1774,7 +1774,7 @@ int getsockopt(socket_type s, state_type state, int level, int optname, // value is non-zero (i.e. true). This corresponds to the behavior of // IPv6 sockets on Windows platforms pre-Vista. *static_cast(optval) = 1; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); } return result; } @@ -1794,7 +1794,7 @@ int getsockopt(socket_type s, state_type state, int level, int optname, // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets // on Windows platforms pre-Vista. *static_cast(optval) = 1; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); } return result; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -1855,7 +1855,7 @@ int getpeername(socket_type s, socket_addr_type* addr, } // The cached value is still valid. - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 0; } #else // defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP) @@ -1950,7 +1950,7 @@ int select(int nfds, fd_set* readfds, fd_set* writefds, if (milliseconds == 0) milliseconds = 1; // Force context switch. ::Sleep(milliseconds); - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 0; } @@ -2270,7 +2270,7 @@ const char* inet_ntop(int af, const void* src, char* dest, size_t length, // Windows may set error code on success. if (result != socket_error_retval) - ec = boost::system::error_code(); + ec.assign(0, ec.category()); // Windows may not set an error code on failure. else if (result == socket_error_retval && !ec) @@ -2324,7 +2324,7 @@ int inet_pton(int af, const char* src, void* dest, bytes[1] = static_cast(b1); bytes[2] = static_cast(b2); bytes[3] = static_cast(b3); - ec = boost::system::error_code(); + ec.assign(), ec.category()); return 1; } else if (af == BOOST_ASIO_OS_DEF(AF_INET6)) @@ -2440,7 +2440,7 @@ int inet_pton(int af, const char* src, void* dest, for (int i = 0; i < num_back_bytes; ++i) bytes[16 - num_back_bytes + i] = back_bytes[i]; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return 1; } else @@ -2483,12 +2483,12 @@ int inet_pton(int af, const char* src, void* dest, if (result != socket_error_retval) { memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); - ec = boost::system::error_code(); + ec.assign(0, ec.category()); } else if (strcmp(src, "255.255.255.255") == 0) { static_cast(dest)->s_addr = INADDR_NONE; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); } } else // AF_INET6 @@ -2498,7 +2498,7 @@ int inet_pton(int af, const char* src, void* dest, memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); if (scope_id) *scope_id = address.v6.sin6_scope_id; - ec = boost::system::error_code(); + ec.assign(0, ec.category()); } } @@ -2507,7 +2507,7 @@ int inet_pton(int af, const char* src, void* dest, ec = boost::asio::error::invalid_argument; if (result != socket_error_retval) - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return result == socket_error_retval ? -1 : 1; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -3436,7 +3436,7 @@ inline boost::system::error_code getnameinfo_emulation( } } - ec = boost::system::error_code(); + ec.assign(0, ec.category()); return ec; } From bab9d0fa72d7aabf15213314e335972a24f34807 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:28:46 +1000 Subject: [PATCH 34/90] Remove unnecessary allocator_ member. --- include/boost/asio/impl/executor.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/boost/asio/impl/executor.hpp b/include/boost/asio/impl/executor.hpp index 05adf56b..58f78f37 100644 --- a/include/boost/asio/impl/executor.hpp +++ b/include/boost/asio/impl/executor.hpp @@ -123,7 +123,7 @@ private: #endif // defined(BOOST_ASIO_HAS_MOVE) -// Default polymorphic allocator implementation. +// Default polymorphic executor implementation. template class executor::impl : public executor::impl_base @@ -247,7 +247,7 @@ private: }; }; -// Polymorphic allocator specialisation for system_executor. +// Polymorphic executor specialisation for system_executor. template class executor::impl : public executor::impl_base @@ -290,17 +290,20 @@ public: void dispatch(BOOST_ASIO_MOVE_ARG(function) f) { - executor_.dispatch(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + executor_.dispatch(BOOST_ASIO_MOVE_CAST(function)(f), + std::allocator()); } void post(BOOST_ASIO_MOVE_ARG(function) f) { - executor_.post(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + executor_.post(BOOST_ASIO_MOVE_CAST(function)(f), + std::allocator()); } void defer(BOOST_ASIO_MOVE_ARG(function) f) { - executor_.defer(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + executor_.defer(BOOST_ASIO_MOVE_CAST(function)(f), + std::allocator()); } type_id_result_type target_type() const BOOST_ASIO_NOEXCEPT @@ -325,7 +328,6 @@ public: private: system_executor executor_; - Allocator allocator_; }; template From bbe2dbe3e8e8f7e0bcee6394c853de086a6c8849 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:29:07 +1000 Subject: [PATCH 35/90] Add single-buffer optimisation for recvfrom and sendto. When we can determine at compile time that the user has supplied a single buffer, use recvfrom/sendto rather than recvmsg/sendmsg, as the former system calls can be faster. --- include/boost/asio/detail/impl/socket_ops.ipp | 220 ++++++++++++++++++ .../detail/reactive_socket_recvfrom_op.hpp | 25 +- .../asio/detail/reactive_socket_sendto_op.hpp | 19 +- .../asio/detail/reactive_socket_service.hpp | 43 +++- include/boost/asio/detail/socket_ops.hpp | 26 +++ 5 files changed, 314 insertions(+), 19 deletions(-) diff --git a/include/boost/asio/detail/impl/socket_ops.ipp b/include/boost/asio/detail/impl/socket_ops.ipp index 695ccdc3..f7b8822d 100644 --- a/include/boost/asio/detail/impl/socket_ops.ipp +++ b/include/boost/asio/detail/impl/socket_ops.ipp @@ -1045,6 +1045,53 @@ signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } +template +inline signed_size_type call_recvfrom(SockLenType msghdr::*, + socket_type s, void* data, size_t size, int flags, + socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + signed_size_type result = ::recvfrom(s, static_cast(data), + size, flags, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +signed_size_type recvfrom1(socket_type s, void* data, size_t size, + int flags, socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + WSABUF buf; + buf.buf = static_cast(data); + buf.len = static_cast(size); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = ::WSARecvFrom(s, &buf, 1, &bytes_transferred, + &recv_flags, addr, &tmp_addrlen, 0, 0); + get_last_error(ec, true); + *addrlen = (std::size_t)tmp_addrlen; + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + signed_size_type result = call_recvfrom(&msghdr::msg_namelen, + s, data, size, flags, addr, addrlen); + get_last_error(ec, result < 0); + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec) @@ -1078,6 +1125,39 @@ size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, } } +size_t sync_recvfrom1(socket_type s, state_type state, void* data, + size_t size, int flags, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recvfrom1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + #if defined(BOOST_ASIO_HAS_IOCP) void complete_iocp_recvfrom( @@ -1137,6 +1217,39 @@ bool non_blocking_recvfrom(socket_type s, } } +bool non_blocking_recvfrom1(socket_type s, + void* data, size_t size, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recvfrom1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + #endif // defined(BOOST_ASIO_HAS_IOCP) signed_size_type recvmsg(socket_type s, buf* bufs, size_t count, @@ -1513,6 +1626,47 @@ signed_size_type sendto(socket_type s, const buf* bufs, size_t count, #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } +template +inline signed_size_type call_sendto(SockLenType msghdr::*, + socket_type s, const void* data, size_t size, int flags, + const socket_addr_type* addr, std::size_t addrlen) +{ + return ::sendto(s, static_cast(const_cast(data)), + size, flags, addr, (SockLenType)addrlen); +} + +signed_size_type sendto1(socket_type s, const void* data, size_t size, + int flags, const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + WSABUF buf; + buf.buf = const_cast(static_cast(data)); + buf.len = static_cast(size); + DWORD bytes_transferred = 0; + int result = ::WSASendTo(s, &buf, 1, &bytes_transferred, + flags, addr, static_cast(addrlen), 0, 0); + get_last_error(ec, true); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec.assign(0, ec.category()); + return bytes_transferred; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + signed_size_type result = call_sendto(&msghdr::msg_namelen, + s, data, size, flags, addr, addrlen); + get_last_error(ec, result < 0); + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + size_t sync_sendto(socket_type s, state_type state, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, boost::system::error_code& ec) @@ -1546,6 +1700,39 @@ size_t sync_sendto(socket_type s, state_type state, const buf* bufs, } } +size_t sync_sendto1(socket_type s, state_type state, const void* data, + size_t size, int flags, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::sendto1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + #if !defined(BOOST_ASIO_HAS_IOCP) bool non_blocking_sendto(socket_type s, @@ -1581,6 +1768,39 @@ bool non_blocking_sendto(socket_type s, } } +bool non_blocking_sendto1(socket_type s, + const void* data, size_t size, int flags, + const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::sendto1( + s, data, size, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + #endif // !defined(BOOST_ASIO_HAS_IOCP) socket_type socket(int af, int type, int protocol, diff --git a/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp index 17554000..e0e0268f 100644 --- a/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp @@ -52,14 +52,27 @@ public: reactive_socket_recvfrom_op_base* o( static_cast(base)); - buffer_sequence_adapter bufs(o->buffers_); + typedef buffer_sequence_adapter bufs_type; std::size_t addr_len = o->sender_endpoint_.capacity(); - status result = socket_ops::non_blocking_recvfrom(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, - o->sender_endpoint_.data(), &addr_len, - o->ec_, o->bytes_transferred_) ? done : not_done; + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_recvfrom1( + o->socket_, bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_recvfrom(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_) ? done : not_done; + } if (result && !o->ec_) o->sender_endpoint_.resize(addr_len); diff --git a/include/boost/asio/detail/reactive_socket_sendto_op.hpp b/include/boost/asio/detail/reactive_socket_sendto_op.hpp index c4b5c454..5692b12f 100644 --- a/include/boost/asio/detail/reactive_socket_sendto_op.hpp +++ b/include/boost/asio/detail/reactive_socket_sendto_op.hpp @@ -51,13 +51,26 @@ public: reactive_socket_sendto_op_base* o( static_cast(base)); - buffer_sequence_adapter bufs(o->buffers_); + typedef buffer_sequence_adapter bufs_type; - status result = socket_ops::non_blocking_sendto(o->socket_, + status result; + if (bufs_type::is_single_buffer) + { + result = socket_ops::non_blocking_sendto1(o->socket_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = socket_ops::non_blocking_sendto(o->socket_, bufs.buffers(), bufs.count(), o->flags_, o->destination_.data(), o->destination_.size(), o->ec_, o->bytes_transferred_) ? done : not_done; + } BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_sendto", o->ec_, o->bytes_transferred_)); diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 01249521..74ca8ae0 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -220,12 +220,23 @@ public: const endpoint_type& destination, socket_base::message_flags flags, boost::system::error_code& ec) { - buffer_sequence_adapter bufs(buffers); + typedef buffer_sequence_adapter bufs_type; - return socket_ops::sync_sendto(impl.socket_, impl.state_, - bufs.buffers(), bufs.count(), flags, - destination.data(), destination.size(), ec); + if (bufs_type::is_single_buffer) + { + return socket_ops::sync_sendto1(impl.socket_, impl.state_, + bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, + destination.data(), destination.size(), ec); + } + else + { + bufs_type bufs(buffers); + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); + } } // Wait until data can be sent without blocking. @@ -295,13 +306,25 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags, boost::system::error_code& ec) { - buffer_sequence_adapter bufs(buffers); + typedef buffer_sequence_adapter bufs_type; std::size_t addr_len = sender_endpoint.capacity(); - std::size_t bytes_recvd = socket_ops::sync_recvfrom( - impl.socket_, impl.state_, bufs.buffers(), bufs.count(), - flags, sender_endpoint.data(), &addr_len, ec); + std::size_t bytes_recvd; + if (bufs_type::is_single_buffer) + { + bytes_recvd = socket_ops::sync_recvfrom1(impl.socket_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), flags, + sender_endpoint.data(), &addr_len, ec); + } + else + { + bufs_type bufs(buffers); + bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); + } if (!ec) sender_endpoint.resize(addr_len); diff --git a/include/boost/asio/detail/socket_ops.hpp b/include/boost/asio/detail/socket_ops.hpp index b4206d30..6f101888 100644 --- a/include/boost/asio/detail/socket_ops.hpp +++ b/include/boost/asio/detail/socket_ops.hpp @@ -171,10 +171,18 @@ BOOST_ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec); +BOOST_ASIO_DECL signed_size_type recvfrom1(socket_type s, void* data, + size_t size, int flags, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); + BOOST_ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec); +BOOST_ASIO_DECL size_t sync_recvfrom1(socket_type s, state_type state, + void* data, size_t size, int flags, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); + #if defined(BOOST_ASIO_HAS_IOCP) BOOST_ASIO_DECL void complete_iocp_recvfrom( @@ -188,6 +196,11 @@ BOOST_ASIO_DECL bool non_blocking_recvfrom(socket_type s, socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec, size_t& bytes_transferred); +BOOST_ASIO_DECL bool non_blocking_recvfrom1(socket_type s, + void* data, size_t size, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, size_t& bytes_transferred); + #endif // defined(BOOST_ASIO_HAS_IOCP) BOOST_ASIO_DECL signed_size_type recvmsg(socket_type s, buf* bufs, @@ -247,10 +260,18 @@ BOOST_ASIO_DECL signed_size_type sendto(socket_type s, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, boost::system::error_code& ec); +BOOST_ASIO_DECL signed_size_type sendto1(socket_type s, const void* data, + size_t size, int flags, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + BOOST_ASIO_DECL size_t sync_sendto(socket_type s, state_type state, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, boost::system::error_code& ec); +BOOST_ASIO_DECL size_t sync_sendto1(socket_type s, state_type state, + const void* data, size_t size, int flags, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + #if !defined(BOOST_ASIO_HAS_IOCP) BOOST_ASIO_DECL bool non_blocking_sendto(socket_type s, @@ -258,6 +279,11 @@ BOOST_ASIO_DECL bool non_blocking_sendto(socket_type s, const socket_addr_type* addr, std::size_t addrlen, boost::system::error_code& ec, size_t& bytes_transferred); +BOOST_ASIO_DECL bool non_blocking_sendto1(socket_type s, + const void* data, size_t size, int flags, + const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec, size_t& bytes_transferred); + #endif // !defined(BOOST_ASIO_HAS_IOCP) BOOST_ASIO_DECL socket_type socket(int af, int type, int protocol, From 7f41b8ed6bdd4d268adaa5fd7e9611d4014d05dd Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:29:40 +1000 Subject: [PATCH 36/90] Add single-buffer optimisation for descriptor read and write. When we can determine at compile time that the user has supplied a single buffer, use read/write rather than readv/writev, as the former system calls can be faster. --- include/boost/asio/detail/descriptor_ops.hpp | 13 ++ .../boost/asio/detail/descriptor_read_op.hpp | 22 ++- .../boost/asio/detail/descriptor_write_op.hpp | 22 ++- .../boost/asio/detail/impl/descriptor_ops.ipp | 154 ++++++++++++++++++ .../detail/reactive_descriptor_service.hpp | 38 ++++- 5 files changed, 231 insertions(+), 18 deletions(-) diff --git a/include/boost/asio/detail/descriptor_ops.hpp b/include/boost/asio/detail/descriptor_ops.hpp index 3ff4a637..7efbf822 100644 --- a/include/boost/asio/detail/descriptor_ops.hpp +++ b/include/boost/asio/detail/descriptor_ops.hpp @@ -82,17 +82,30 @@ typedef iovec buf; BOOST_ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs, std::size_t count, bool all_empty, boost::system::error_code& ec); +BOOST_ASIO_DECL std::size_t sync_read1(int d, state_type state, void* data, + std::size_t size, boost::system::error_code& ec); + BOOST_ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count, boost::system::error_code& ec, std::size_t& bytes_transferred); +BOOST_ASIO_DECL bool non_blocking_read1(int d, void* data, std::size_t size, + boost::system::error_code& ec, std::size_t& bytes_transferred); + BOOST_ASIO_DECL std::size_t sync_write(int d, state_type state, const buf* bufs, std::size_t count, bool all_empty, boost::system::error_code& ec); +BOOST_ASIO_DECL std::size_t sync_write1(int d, state_type state, + const void* data, std::size_t size, boost::system::error_code& ec); + BOOST_ASIO_DECL bool non_blocking_write(int d, const buf* bufs, std::size_t count, boost::system::error_code& ec, std::size_t& bytes_transferred); +BOOST_ASIO_DECL bool non_blocking_write1(int d, + const void* data, std::size_t size, + boost::system::error_code& ec, std::size_t& bytes_transferred); + BOOST_ASIO_DECL int ioctl(int d, state_type& state, long cmd, ioctl_arg_type* arg, boost::system::error_code& ec); diff --git a/include/boost/asio/detail/descriptor_read_op.hpp b/include/boost/asio/detail/descriptor_read_op.hpp index f63fa4bf..4a6b8653 100644 --- a/include/boost/asio/detail/descriptor_read_op.hpp +++ b/include/boost/asio/detail/descriptor_read_op.hpp @@ -51,12 +51,24 @@ public: { descriptor_read_op_base* o(static_cast(base)); - buffer_sequence_adapter bufs(o->buffers_); + typedef buffer_sequence_adapter bufs_type; - status result = descriptor_ops::non_blocking_read(o->descriptor_, - bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) - ? done : not_done; + status result; + if (bufs_type::is_single_buffer) + { + result = descriptor_ops::non_blocking_read1(o->descriptor_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = descriptor_ops::non_blocking_read(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + } BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read", o->ec_, o->bytes_transferred_)); diff --git a/include/boost/asio/detail/descriptor_write_op.hpp b/include/boost/asio/detail/descriptor_write_op.hpp index 94759d03..c2aec81d 100644 --- a/include/boost/asio/detail/descriptor_write_op.hpp +++ b/include/boost/asio/detail/descriptor_write_op.hpp @@ -51,12 +51,24 @@ public: { descriptor_write_op_base* o(static_cast(base)); - buffer_sequence_adapter bufs(o->buffers_); + typedef buffer_sequence_adapter bufs_type; - status result = descriptor_ops::non_blocking_write(o->descriptor_, - bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) - ? done : not_done; + status result; + if (bufs_type::is_single_buffer) + { + result = descriptor_ops::non_blocking_write1(o->descriptor_, + bufs_type::first(o->buffers_).data(), + bufs_type::first(o->buffers_).size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + } + else + { + bufs_type bufs(o->buffers_); + result = descriptor_ops::non_blocking_write(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + } BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write", o->ec_, o->bytes_transferred_)); diff --git a/include/boost/asio/detail/impl/descriptor_ops.ipp b/include/boost/asio/detail/impl/descriptor_ops.ipp index 338b29cd..16c04f3e 100644 --- a/include/boost/asio/detail/impl/descriptor_ops.ipp +++ b/include/boost/asio/detail/impl/descriptor_ops.ipp @@ -206,6 +206,52 @@ std::size_t sync_read(int d, state_type state, buf* bufs, } } +std::size_t sync_read1(int d, state_type state, void* data, + std::size_t size, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (size == 0) + { + ec.assign(0, ec.category()); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::read(d, data, size); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + bool non_blocking_read(int d, buf* bufs, std::size_t count, boost::system::error_code& ec, std::size_t& bytes_transferred) { @@ -244,6 +290,44 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count, } } +bool non_blocking_read1(int d, void* data, std::size_t size, + boost::system::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = ::read(d, data, size); + get_last_error(ec, bytes < 0); + + // Check for end of stream. + if (bytes == 0) + { + ec = boost::asio::error::eof; + return true; + } + + // Check if operation succeeded. + if (bytes > 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + std::size_t sync_write(int d, state_type state, const buf* bufs, std::size_t count, bool all_empty, boost::system::error_code& ec) { @@ -283,6 +367,45 @@ std::size_t sync_write(int d, state_type state, const buf* bufs, } } +std::size_t sync_write1(int d, state_type state, const void* data, + std::size_t size, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (size == 0) + { + ec.assign(0, ec.category()); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = ::write(d, data, size); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + bool non_blocking_write(int d, const buf* bufs, std::size_t count, boost::system::error_code& ec, std::size_t& bytes_transferred) { @@ -314,6 +437,37 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count, } } +bool non_blocking_write1(int d, const void* data, std::size_t size, + boost::system::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = ::write(d, data, size); + get_last_error(ec, bytes < 0); + + // Check if operation succeeded. + if (bytes >= 0) + { + bytes_transferred = bytes; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation failed. + bytes_transferred = 0; + return true; + } +} + int ioctl(int d, state_type& state, long cmd, ioctl_arg_type* arg, boost::system::error_code& ec) { diff --git a/include/boost/asio/detail/reactive_descriptor_service.hpp b/include/boost/asio/detail/reactive_descriptor_service.hpp index 9c91e7cb..4ed42a26 100644 --- a/include/boost/asio/detail/reactive_descriptor_service.hpp +++ b/include/boost/asio/detail/reactive_descriptor_service.hpp @@ -235,11 +235,22 @@ public: size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, boost::system::error_code& ec) { - buffer_sequence_adapter bufs(buffers); + typedef buffer_sequence_adapter bufs_type; - return descriptor_ops::sync_write(impl.descriptor_, impl.state_, - bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + if (bufs_type::is_single_buffer) + { + return descriptor_ops::sync_write1(impl.descriptor_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), ec); + } + else + { + bufs_type bufs(buffers); + + return descriptor_ops::sync_write(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } } // Wait until data can be written without blocking. @@ -303,11 +314,22 @@ public: size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, boost::system::error_code& ec) { - buffer_sequence_adapter bufs(buffers); + typedef buffer_sequence_adapter bufs_type; - return descriptor_ops::sync_read(impl.descriptor_, impl.state_, - bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + if (bufs_type::is_single_buffer) + { + return descriptor_ops::sync_read1(impl.descriptor_, + impl.state_, bufs_type::first(buffers).data(), + bufs_type::first(buffers).size(), ec); + } + else + { + bufs_type bufs(buffers); + + return descriptor_ops::sync_read(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } } // Wait until data can be read without blocking. From 3122e49c63a239a92a65bbc545e10fdb9d2e0861 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:30:58 +1000 Subject: [PATCH 37/90] Avoid touching errors when we get a 0-length receive on a non-stream. --- include/boost/asio/detail/impl/socket_ops.ipp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/boost/asio/detail/impl/socket_ops.ipp b/include/boost/asio/detail/impl/socket_ops.ipp index f7b8822d..ef4462e5 100644 --- a/include/boost/asio/detail/impl/socket_ops.ipp +++ b/include/boost/asio/detail/impl/socket_ops.ipp @@ -828,10 +828,6 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, // Try to complete the operation without blocking. signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec); - // Check if operation succeeded. - if (bytes > 0) - return bytes; - // Check for EOF. if ((state & stream_oriented) && bytes == 0) { @@ -839,6 +835,10 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, return 0; } + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + // Operation failed. if ((state & user_set_non_blocking) || (ec != boost::asio::error::would_block @@ -873,10 +873,6 @@ size_t sync_recv1(socket_type s, state_type state, void* data, // Try to complete the operation without blocking. signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); - // Check if operation succeeded. - if (bytes > 0) - return bytes; - // Check for EOF. if ((state & stream_oriented) && bytes == 0) { @@ -884,6 +880,10 @@ size_t sync_recv1(socket_type s, state_type state, void* data, return 0; } + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + // Operation failed. if ((state & user_set_non_blocking) || (ec != boost::asio::error::would_block From deb0b72619dfdfa48c818ac110b5043e1b89d203 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:31:21 +1000 Subject: [PATCH 38/90] Change detail::handler_work<> to use an RAII-based approach. --- .../boost/asio/detail/completion_handler.hpp | 10 ++-- .../boost/asio/detail/descriptor_read_op.hpp | 11 ++-- .../boost/asio/detail/descriptor_write_op.hpp | 11 ++-- include/boost/asio/detail/handler_work.hpp | 51 ++++++++++++------- .../asio/detail/reactive_null_buffers_op.hpp | 13 +++-- .../asio/detail/reactive_socket_accept_op.hpp | 26 ++++++---- .../detail/reactive_socket_connect_op.hpp | 15 ++++-- .../asio/detail/reactive_socket_recv_op.hpp | 14 +++-- .../detail/reactive_socket_recvfrom_op.hpp | 14 +++-- .../detail/reactive_socket_recvmsg_op.hpp | 14 +++-- .../asio/detail/reactive_socket_send_op.hpp | 14 +++-- .../asio/detail/reactive_socket_sendto_op.hpp | 14 +++-- .../boost/asio/detail/reactive_wait_op.hpp | 13 +++-- .../boost/asio/detail/resolve_endpoint_op.hpp | 18 ++++--- .../boost/asio/detail/resolve_query_op.hpp | 20 ++++---- include/boost/asio/detail/signal_handler.hpp | 12 +++-- include/boost/asio/detail/wait_handler.hpp | 15 +++--- .../asio/detail/win_iocp_handle_read_op.hpp | 14 +++-- .../asio/detail/win_iocp_handle_write_op.hpp | 14 +++-- .../asio/detail/win_iocp_null_buffers_op.hpp | 13 +++-- .../asio/detail/win_iocp_overlapped_op.hpp | 14 +++-- .../asio/detail/win_iocp_socket_accept_op.hpp | 26 ++++++---- .../detail/win_iocp_socket_connect_op.hpp | 12 +++-- .../asio/detail/win_iocp_socket_recv_op.hpp | 12 +++-- .../detail/win_iocp_socket_recvfrom_op.hpp | 12 +++-- .../detail/win_iocp_socket_recvmsg_op.hpp | 12 +++-- .../asio/detail/win_iocp_socket_send_op.hpp | 12 +++-- .../boost/asio/detail/win_iocp_wait_op.hpp | 12 +++-- .../boost/asio/detail/winrt_resolve_op.hpp | 12 +++-- .../asio/detail/winrt_socket_connect_op.hpp | 12 +++-- .../asio/detail/winrt_socket_recv_op.hpp | 12 +++-- .../asio/detail/winrt_socket_send_op.hpp | 12 +++-- 32 files changed, 316 insertions(+), 170 deletions(-) diff --git a/include/boost/asio/detail/completion_handler.hpp b/include/boost/asio/detail/completion_handler.hpp index 7ad8e36b..6684e954 100644 --- a/include/boost/asio/detail/completion_handler.hpp +++ b/include/boost/asio/detail/completion_handler.hpp @@ -36,9 +36,9 @@ public: completion_handler(Handler& h) : operation(&completion_handler::do_complete), - handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)) + handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)), + work_(handler_) { - handler_work::start(handler_); } static void do_complete(void* owner, operation* base, @@ -48,10 +48,13 @@ public: // Take ownership of the handler object. completion_handler* h(static_cast(base)); ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; - handler_work w(h->handler_); BOOST_ASIO_HANDLER_COMPLETION((*h)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST(handler_work)(h->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -74,6 +77,7 @@ public: private: Handler handler_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/descriptor_read_op.hpp b/include/boost/asio/detail/descriptor_read_op.hpp index 4a6b8653..f3bfe952 100644 --- a/include/boost/asio/detail/descriptor_read_op.hpp +++ b/include/boost/asio/detail/descriptor_read_op.hpp @@ -94,9 +94,8 @@ public: : descriptor_read_op_base(success_ec, descriptor, buffers, &descriptor_read_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -106,10 +105,14 @@ public: // Take ownership of the handler object. descriptor_read_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -133,7 +136,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/descriptor_write_op.hpp b/include/boost/asio/detail/descriptor_write_op.hpp index c2aec81d..77646649 100644 --- a/include/boost/asio/detail/descriptor_write_op.hpp +++ b/include/boost/asio/detail/descriptor_write_op.hpp @@ -94,9 +94,8 @@ public: : descriptor_write_op_base(success_ec, descriptor, buffers, &descriptor_write_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -106,10 +105,14 @@ public: // Take ownership of the handler object. descriptor_write_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -133,7 +136,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/handler_work.hpp b/include/boost/asio/detail/handler_work.hpp index e2c860fc..5ae76e26 100644 --- a/include/boost/asio/detail/handler_work.hpp +++ b/include/boost/asio/detail/handler_work.hpp @@ -36,34 +36,51 @@ class handler_work public: explicit handler_work(Handler& handler) BOOST_ASIO_NOEXCEPT : io_executor_(), - executor_(boost::asio::get_associated_executor(handler, io_executor_)) + executor_(boost::asio::get_associated_executor(handler, io_executor_)), + owns_work_(true) { + io_executor_.on_work_started(); + executor_.on_work_started(); } handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT : io_executor_(io_ex), - executor_(boost::asio::get_associated_executor(handler, io_executor_)) + executor_(boost::asio::get_associated_executor(handler, io_executor_)), + owns_work_(true) { + io_executor_.on_work_started(); + executor_.on_work_started(); } - static void start(Handler& handler) BOOST_ASIO_NOEXCEPT + handler_work(const handler_work& other) + : io_executor_(other.io_executor_), + executor_(other.executor_), + owns_work_(other.owns_work_) { - HandlerExecutor ex(boost::asio::get_associated_executor(handler)); - ex.on_work_started(); + if (owns_work_) + { + io_executor_.on_work_started(); + executor_.on_work_started(); + } } - static void start(Handler& handler, - const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT +#if defined(BOOST_ASIO_HAS_MOVE) + handler_work(handler_work&& other) + : io_executor_(BOOST_ASIO_MOVE_CAST(IoExecutor)(other.io_executor_)), + executor_(BOOST_ASIO_MOVE_CAST(HandlerExecutor)(other.executor_)), + owns_work_(other.owns_work_) { - HandlerExecutor ex(boost::asio::get_associated_executor(handler, io_ex)); - ex.on_work_started(); - io_ex.on_work_started(); + other.owns_work_ = false; } +#endif // defined(BOOST_ASIO_HAS_MOVE) ~handler_work() { - io_executor_.on_work_finished(); - executor_.on_work_finished(); + if (owns_work_) + { + io_executor_.on_work_finished(); + executor_.on_work_finished(); + } } template @@ -74,12 +91,12 @@ public: } private: - // Disallow copying and assignment. - handler_work(const handler_work&); + // Disallow assignment. handler_work& operator=(const handler_work&); IoExecutor io_executor_; HandlerExecutor executor_; + bool owns_work_; }; // This specialisation dispatches a handler through the old invocation hook. @@ -91,8 +108,7 @@ class handler_work { public: explicit handler_work(Handler&) BOOST_ASIO_NOEXCEPT {} - static void start(Handler&) BOOST_ASIO_NOEXCEPT {} - ~handler_work() {} + handler_work(Handler&, const system_executor&) BOOST_ASIO_NOEXCEPT {} template void complete(Function& function, Handler& handler) @@ -101,8 +117,7 @@ public: } private: - // Disallow copying and assignment. - handler_work(const handler_work&); + // Disallow assignment. handler_work& operator=(const handler_work&); }; diff --git a/include/boost/asio/detail/reactive_null_buffers_op.hpp b/include/boost/asio/detail/reactive_null_buffers_op.hpp index ecdca8b5..87de33bb 100644 --- a/include/boost/asio/detail/reactive_null_buffers_op.hpp +++ b/include/boost/asio/detail/reactive_null_buffers_op.hpp @@ -16,9 +16,11 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include +#include #include #include #include +#include #include #include @@ -39,9 +41,8 @@ public: : reactor_op(success_ec, &reactive_null_buffers_op::do_perform, &reactive_null_buffers_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static status do_perform(reactor_op*) @@ -56,10 +57,14 @@ public: // Take ownership of the handler object. reactive_null_buffers_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -83,7 +88,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_socket_accept_op.hpp b/include/boost/asio/detail/reactive_socket_accept_op.hpp index b2e84dd7..878ffc7e 100644 --- a/include/boost/asio/detail/reactive_socket_accept_op.hpp +++ b/include/boost/asio/detail/reactive_socket_accept_op.hpp @@ -17,8 +17,10 @@ #include #include -#include #include +#include +#include +#include #include #include #include @@ -104,9 +106,8 @@ public: success_ec, socket, state, peer, protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -116,7 +117,6 @@ public: // Take ownership of the handler object. reactive_socket_accept_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); // On success, assign new connection to peer socket object. if (owner) @@ -124,6 +124,11 @@ public: BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -147,7 +152,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; #if defined(BOOST_ASIO_HAS_MOVE) @@ -173,9 +178,8 @@ public: success_ec, socket, state, *this, protocol, peer_endpoint, &reactive_socket_move_accept_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -186,7 +190,6 @@ public: reactive_socket_move_accept_op* o( static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); // On success, assign new connection to peer socket object. if (owner) @@ -194,6 +197,11 @@ public: BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -222,7 +230,7 @@ private: rebind_executor::other peer_socket_type; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; #endif // defined(BOOST_ASIO_HAS_MOVE) diff --git a/include/boost/asio/detail/reactive_socket_connect_op.hpp b/include/boost/asio/detail/reactive_socket_connect_op.hpp index f5162765..81091b72 100644 --- a/include/boost/asio/detail/reactive_socket_connect_op.hpp +++ b/include/boost/asio/detail/reactive_socket_connect_op.hpp @@ -17,8 +17,10 @@ #include #include -#include #include +#include +#include +#include #include #include #include @@ -68,9 +70,8 @@ public: : reactive_socket_connect_op_base(success_ec, socket, &reactive_socket_connect_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -81,10 +82,14 @@ public: reactive_socket_connect_op* o (static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -108,7 +113,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_socket_recv_op.hpp b/include/boost/asio/detail/reactive_socket_recv_op.hpp index 5d834a5c..f58de9ad 100644 --- a/include/boost/asio/detail/reactive_socket_recv_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recv_op.hpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -104,9 +107,8 @@ public: : reactive_socket_recv_op_base(success_ec, socket, state, buffers, flags, &reactive_socket_recv_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -116,10 +118,14 @@ public: // Take ownership of the handler object. reactive_socket_recv_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -143,7 +149,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp index e0e0268f..b91dd02a 100644 --- a/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -108,9 +111,8 @@ public: success_ec, socket, protocol_type, buffers, endpoint, flags, &reactive_socket_recvfrom_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -121,10 +123,14 @@ public: reactive_socket_recvfrom_op* o( static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -148,7 +154,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp b/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp index 1f1b2df1..15d5c7ea 100644 --- a/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp +++ b/include/boost/asio/detail/reactive_socket_recvmsg_op.hpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -89,9 +92,8 @@ public: success_ec, socket, buffers, in_flags, out_flags, &reactive_socket_recvmsg_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -102,10 +104,14 @@ public: reactive_socket_recvmsg_op* o( static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -129,7 +135,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_socket_send_op.hpp b/include/boost/asio/detail/reactive_socket_send_op.hpp index e38b9d08..9840e4c4 100644 --- a/include/boost/asio/detail/reactive_socket_send_op.hpp +++ b/include/boost/asio/detail/reactive_socket_send_op.hpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -107,9 +110,8 @@ public: : reactive_socket_send_op_base(success_ec, socket, state, buffers, flags, &reactive_socket_send_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -119,10 +121,14 @@ public: // Take ownership of the handler object. reactive_socket_send_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -146,7 +152,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_socket_sendto_op.hpp b/include/boost/asio/detail/reactive_socket_sendto_op.hpp index 5692b12f..834fe555 100644 --- a/include/boost/asio/detail/reactive_socket_sendto_op.hpp +++ b/include/boost/asio/detail/reactive_socket_sendto_op.hpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -101,9 +104,8 @@ public: success_ec, socket, buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -113,10 +115,14 @@ public: // Take ownership of the handler object. reactive_socket_sendto_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -140,7 +146,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_wait_op.hpp b/include/boost/asio/detail/reactive_wait_op.hpp index 023e9c44..424c28a1 100644 --- a/include/boost/asio/detail/reactive_wait_op.hpp +++ b/include/boost/asio/detail/reactive_wait_op.hpp @@ -16,9 +16,11 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include +#include #include #include #include +#include #include #include @@ -39,9 +41,8 @@ public: : reactor_op(success_ec, &reactive_wait_op::do_perform, &reactive_wait_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static status do_perform(reactor_op*) @@ -56,10 +57,14 @@ public: // Take ownership of the handler object. reactive_wait_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -83,7 +88,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/resolve_endpoint_op.hpp b/include/boost/asio/detail/resolve_endpoint_op.hpp index aae503c4..6d6e37cc 100644 --- a/include/boost/asio/detail/resolve_endpoint_op.hpp +++ b/include/boost/asio/detail/resolve_endpoint_op.hpp @@ -16,15 +16,16 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include -#include -#include #include #include #include #include +#include #include #include #include +#include +#include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -61,9 +62,8 @@ public: endpoint_(endpoint), scheduler_(sched), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -96,11 +96,13 @@ public: // The operation has been returned to the main io_context. The completion // handler is ready to be delivered. - // Take ownership of the operation's outstanding work. - handler_work w(o->handler_, o->io_executor_); - BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated // before the upcall is made. Even if we're not about to make an upcall, // a sub-object of the handler may be the true owner of the memory @@ -127,7 +129,7 @@ private: endpoint_type endpoint_; scheduler_impl& scheduler_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; results_type results_; }; diff --git a/include/boost/asio/detail/resolve_query_op.hpp b/include/boost/asio/detail/resolve_query_op.hpp index d1e0717f..2b2ca2d9 100644 --- a/include/boost/asio/detail/resolve_query_op.hpp +++ b/include/boost/asio/detail/resolve_query_op.hpp @@ -16,16 +16,17 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include -#include -#include -#include #include #include #include #include +#include #include #include #include +#include +#include +#include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -62,10 +63,9 @@ public: query_(query), scheduler_(sched), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex), + work_(handler_, io_ex), addrinfo_(0) { - handler_work::start(handler_, io_executor_); } ~resolve_query_op() @@ -101,11 +101,13 @@ public: // The operation has been returned to the main io_context. The completion // handler is ready to be delivered. - // Take ownership of the operation's outstanding work. - handler_work w(o->handler_, o->io_executor_); - BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated // before the upcall is made. Even if we're not about to make an upcall, // a sub-object of the handler may be the true owner of the memory @@ -137,7 +139,7 @@ private: query_type query_; scheduler_impl& scheduler_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; boost::asio::detail::addrinfo_type* addrinfo_; }; diff --git a/include/boost/asio/detail/signal_handler.hpp b/include/boost/asio/detail/signal_handler.hpp index 3bb35ecd..459b81ab 100644 --- a/include/boost/asio/detail/signal_handler.hpp +++ b/include/boost/asio/detail/signal_handler.hpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -39,9 +38,8 @@ public: signal_handler(Handler& h, const IoExecutor& io_ex) : signal_op(&signal_handler::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -51,10 +49,14 @@ public: // Take ownership of the handler object. signal_handler* h(static_cast(base)); ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; - handler_work w(h->handler_, h->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*h)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + h->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -78,7 +80,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/wait_handler.hpp b/include/boost/asio/detail/wait_handler.hpp index 7ec6a4f7..3f732640 100644 --- a/include/boost/asio/detail/wait_handler.hpp +++ b/include/boost/asio/detail/wait_handler.hpp @@ -16,9 +16,9 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include +#include #include #include -#include #include #include #include @@ -35,12 +35,11 @@ class wait_handler : public wait_op public: BOOST_ASIO_DEFINE_HANDLER_PTR(wait_handler); - wait_handler(Handler& h, const IoExecutor& ex) + wait_handler(Handler& h, const IoExecutor& io_ex) : wait_op(&wait_handler::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)), - io_executor_(ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -50,10 +49,14 @@ public: // Take ownership of the handler object. wait_handler* h(static_cast(base)); ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; - handler_work w(h->handler_, h->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*h)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + h->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -77,7 +80,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_handle_read_op.hpp b/include/boost/asio/detail/win_iocp_handle_read_op.hpp index b17f639c..13369f73 100644 --- a/include/boost/asio/detail/win_iocp_handle_read_op.hpp +++ b/include/boost/asio/detail/win_iocp_handle_read_op.hpp @@ -20,14 +20,15 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include #include #include #include #include #include +#include #include #include +#include #include @@ -46,9 +47,8 @@ public: : operation(&win_iocp_handle_read_op::do_complete), buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -60,10 +60,14 @@ public: // Take ownership of the operation object. win_iocp_handle_read_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) if (owner) { @@ -101,7 +105,7 @@ public: private: MutableBufferSequence buffers_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_handle_write_op.hpp b/include/boost/asio/detail/win_iocp_handle_write_op.hpp index b24ffad2..e1706f16 100644 --- a/include/boost/asio/detail/win_iocp_handle_write_op.hpp +++ b/include/boost/asio/detail/win_iocp_handle_write_op.hpp @@ -20,14 +20,15 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include #include #include #include #include #include +#include #include #include +#include #include @@ -46,9 +47,8 @@ public: : operation(&win_iocp_handle_write_op::do_complete), buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -57,10 +57,14 @@ public: // Take ownership of the operation object. win_iocp_handle_write_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) if (owner) { @@ -94,7 +98,7 @@ public: private: ConstBufferSequence buffers_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_null_buffers_op.hpp b/include/boost/asio/detail/win_iocp_null_buffers_op.hpp index 335f0269..ec636dbd 100644 --- a/include/boost/asio/detail/win_iocp_null_buffers_op.hpp +++ b/include/boost/asio/detail/win_iocp_null_buffers_op.hpp @@ -20,10 +20,10 @@ #if defined(BOOST_ASIO_HAS_IOCP) #include -#include #include #include #include +#include #include #include #include @@ -48,9 +48,8 @@ public: &win_iocp_null_buffers_op::do_complete), cancel_token_(cancel_token), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static status do_perform(reactor_op*) @@ -67,10 +66,14 @@ public: // Take ownership of the operation object. win_iocp_null_buffers_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // The reactor may have stored a result in the operation object. if (o->ec_) ec = o->ec_; @@ -112,7 +115,7 @@ public: private: socket_ops::weak_cancel_token_type cancel_token_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_overlapped_op.hpp b/include/boost/asio/detail/win_iocp_overlapped_op.hpp index 57bbe2df..be3f2929 100644 --- a/include/boost/asio/detail/win_iocp_overlapped_op.hpp +++ b/include/boost/asio/detail/win_iocp_overlapped_op.hpp @@ -19,13 +19,14 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include #include #include #include #include +#include #include #include +#include #include @@ -42,9 +43,8 @@ public: win_iocp_overlapped_op(Handler& handler, const IoExecutor& io_ex) : operation(&win_iocp_overlapped_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -53,10 +53,14 @@ public: // Take ownership of the operation object. win_iocp_overlapped_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -80,7 +84,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_socket_accept_op.hpp b/include/boost/asio/detail/win_iocp_socket_accept_op.hpp index 39fc5da0..eac8f77d 100644 --- a/include/boost/asio/detail/win_iocp_socket_accept_op.hpp +++ b/include/boost/asio/detail/win_iocp_socket_accept_op.hpp @@ -20,10 +20,10 @@ #if defined(BOOST_ASIO_HAS_IOCP) #include -#include #include #include #include +#include #include #include #include @@ -55,9 +55,8 @@ public: peer_endpoint_(peer_endpoint), enable_connection_aborted_(enable_connection_aborted), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } socket_holder& new_socket() @@ -84,7 +83,6 @@ public: // Take ownership of the operation object. win_iocp_socket_accept_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); if (owner) { @@ -100,7 +98,6 @@ public: if (ec == boost::asio::error::connection_aborted && !o->enable_connection_aborted_) { - handler_work::start(o->handler_, o->io_executor_); o->reset(); o->socket_service_.restart_accept_op(o->socket_, o->new_socket_, o->protocol_.family(), @@ -128,6 +125,11 @@ public: BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -159,7 +161,7 @@ private: unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; bool enable_connection_aborted_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; #if defined(BOOST_ASIO_HAS_MOVE) @@ -184,9 +186,8 @@ public: peer_endpoint_(peer_endpoint), enable_connection_aborted_(enable_connection_aborted), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } socket_holder& new_socket() @@ -214,7 +215,6 @@ public: win_iocp_socket_move_accept_op* o( static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); if (owner) { @@ -230,7 +230,6 @@ public: if (ec == boost::asio::error::connection_aborted && !o->enable_connection_aborted_) { - handler_work::start(o->handler_, o->io_executor_); o->reset(); o->socket_service_.restart_accept_op(o->socket_, o->new_socket_, o->protocol_.family(), @@ -258,6 +257,11 @@ public: BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -294,7 +298,7 @@ private: unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; bool enable_connection_aborted_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; #endif // defined(BOOST_ASIO_HAS_MOVE) diff --git a/include/boost/asio/detail/win_iocp_socket_connect_op.hpp b/include/boost/asio/detail/win_iocp_socket_connect_op.hpp index 25319303..67d94b7c 100644 --- a/include/boost/asio/detail/win_iocp_socket_connect_op.hpp +++ b/include/boost/asio/detail/win_iocp_socket_connect_op.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -69,9 +70,8 @@ public: : win_iocp_socket_connect_op_base(socket, &win_iocp_socket_connect_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -84,7 +84,6 @@ public: win_iocp_socket_connect_op* o( static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); if (owner) { @@ -96,6 +95,11 @@ public: BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -119,7 +123,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_socket_recv_op.hpp b/include/boost/asio/detail/win_iocp_socket_recv_op.hpp index 120742e0..520678cb 100644 --- a/include/boost/asio/detail/win_iocp_socket_recv_op.hpp +++ b/include/boost/asio/detail/win_iocp_socket_recv_op.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -50,9 +51,8 @@ public: cancel_token_(cancel_token), buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -64,10 +64,14 @@ public: // Take ownership of the operation object. win_iocp_socket_recv_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -108,7 +112,7 @@ private: socket_ops::weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp b/include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp index e97d4be4..27524f7c 100644 --- a/include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp +++ b/include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -52,9 +53,8 @@ public: cancel_token_(cancel_token), buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } int& endpoint_size() @@ -72,10 +72,14 @@ public: win_iocp_socket_recvfrom_op* o( static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -117,7 +121,7 @@ private: socket_ops::weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp b/include/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp index 44d99d19..62dee6b8 100644 --- a/include/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp +++ b/include/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -52,9 +53,8 @@ public: buffers_(buffers), out_flags_(out_flags), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -67,10 +67,14 @@ public: win_iocp_socket_recvmsg_op* o( static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -109,7 +113,7 @@ private: MutableBufferSequence buffers_; socket_base::message_flags& out_flags_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_socket_send_op.hpp b/include/boost/asio/detail/win_iocp_socket_send_op.hpp index 394431cc..6d20d741 100644 --- a/include/boost/asio/detail/win_iocp_socket_send_op.hpp +++ b/include/boost/asio/detail/win_iocp_socket_send_op.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -48,9 +49,8 @@ public: cancel_token_(cancel_token), buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -62,10 +62,14 @@ public: // Take ownership of the operation object. win_iocp_socket_send_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -102,7 +106,7 @@ private: socket_ops::weak_cancel_token_type cancel_token_; ConstBufferSequence buffers_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_wait_op.hpp b/include/boost/asio/detail/win_iocp_wait_op.hpp index 41ee2624..54d42206 100644 --- a/include/boost/asio/detail/win_iocp_wait_op.hpp +++ b/include/boost/asio/detail/win_iocp_wait_op.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -48,9 +49,8 @@ public: &win_iocp_wait_op::do_complete), cancel_token_(cancel_token), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static status do_perform(reactor_op*) @@ -67,10 +67,14 @@ public: // Take ownership of the operation object. win_iocp_wait_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // The reactor may have stored a result in the operation object. if (o->ec_) ec = o->ec_; @@ -112,7 +116,7 @@ public: private: socket_ops::weak_cancel_token_type cancel_token_; Handler handler_; - IoExecutor io_executor_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/winrt_resolve_op.hpp b/include/boost/asio/detail/winrt_resolve_op.hpp index 2b025efd..d75fbefd 100644 --- a/include/boost/asio/detail/winrt_resolve_op.hpp +++ b/include/boost/asio/detail/winrt_resolve_op.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -55,9 +56,8 @@ public: &winrt_resolve_op::do_complete), query_(query), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -66,10 +66,14 @@ public: // Take ownership of the operation object. winrt_resolve_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + results_type results = results_type(); if (!o->ec_) { @@ -109,7 +113,7 @@ public: private: query_type query_; Handler handler_; - IoExecutor io_executor_; + handler_work executor_; }; } // namespace detail diff --git a/include/boost/asio/detail/winrt_socket_connect_op.hpp b/include/boost/asio/detail/winrt_socket_connect_op.hpp index cadfe435..7cd6e8e8 100644 --- a/include/boost/asio/detail/winrt_socket_connect_op.hpp +++ b/include/boost/asio/detail/winrt_socket_connect_op.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -44,9 +45,8 @@ public: winrt_socket_connect_op(Handler& handler, const IoExecutor& io_ex) : winrt_async_op(&winrt_socket_connect_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -55,10 +55,14 @@ public: // Take ownership of the operation object. winrt_socket_connect_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated @@ -82,7 +86,7 @@ public: private: Handler handler_; - IoExecutor io_executor_; + handler_work executor_; }; } // namespace detail diff --git a/include/boost/asio/detail/winrt_socket_recv_op.hpp b/include/boost/asio/detail/winrt_socket_recv_op.hpp index 5539f35f..80cb056b 100644 --- a/include/boost/asio/detail/winrt_socket_recv_op.hpp +++ b/include/boost/asio/detail/winrt_socket_recv_op.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -47,9 +48,8 @@ public: &winrt_socket_recv_op::do_complete), buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -58,10 +58,14 @@ public: // Take ownership of the operation object. winrt_socket_recv_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -103,7 +107,7 @@ public: private: MutableBufferSequence buffers_; Handler handler_; - IoExecutor io_executor_; + handler_work executor_; }; } // namespace detail diff --git a/include/boost/asio/detail/winrt_socket_send_op.hpp b/include/boost/asio/detail/winrt_socket_send_op.hpp index c1ec3dd5..f9624d04 100644 --- a/include/boost/asio/detail/winrt_socket_send_op.hpp +++ b/include/boost/asio/detail/winrt_socket_send_op.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -46,9 +47,8 @@ public: : winrt_async_op(&winrt_socket_send_op::do_complete), buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - io_executor_(io_ex) + work_(handler_, io_ex) { - handler_work::start(handler_, io_executor_); } static void do_complete(void* owner, operation* base, @@ -57,10 +57,14 @@ public: // Take ownership of the operation object. winrt_socket_send_op* o(static_cast(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - handler_work w(o->handler_, o->io_executor_); BOOST_ASIO_HANDLER_COMPLETION((*o)); + // Take ownership of the operation's outstanding work. + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + o->work_)); + #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) @@ -94,7 +98,7 @@ public: private: ConstBufferSequence buffers_; Handler handler_; - IoExecutor io_executor_; + handler_work executor_; }; } // namespace detail From 59d6542f2a4365decdb1424fc821351b6ba763cd Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:39:34 +1000 Subject: [PATCH 39/90] Test for native I/O executors in detail::handler_work<>. The detail::io_object_executor wrapper has been removed, and the job of detecting, and optimising for, native I/O executors is now performed directly in the detail::handler_work implementation. --- include/boost/asio/basic_datagram_socket.hpp | 12 +- include/boost/asio/basic_deadline_timer.hpp | 4 +- include/boost/asio/basic_raw_socket.hpp | 12 +- .../boost/asio/basic_seq_packet_socket.hpp | 6 +- include/boost/asio/basic_serial_port.hpp | 8 +- include/boost/asio/basic_signal_set.hpp | 4 +- include/boost/asio/basic_socket.hpp | 6 +- include/boost/asio/basic_socket_acceptor.hpp | 8 +- include/boost/asio/basic_stream_socket.hpp | 4 +- include/boost/asio/basic_waitable_timer.hpp | 4 +- include/boost/asio/detail/handler_work.hpp | 232 ++++++++++++++---- .../boost/asio/detail/io_object_executor.hpp | 169 ------------- include/boost/asio/detail/io_object_impl.hpp | 60 +---- .../asio/detail/win_iocp_overlapped_ptr.hpp | 5 +- include/boost/asio/ip/basic_resolver.hpp | 4 +- include/boost/asio/posix/basic_descriptor.hpp | 4 +- .../asio/posix/basic_stream_descriptor.hpp | 8 +- .../asio/windows/basic_object_handle.hpp | 4 +- .../windows/basic_random_access_handle.hpp | 8 +- .../asio/windows/basic_stream_handle.hpp | 8 +- 20 files changed, 249 insertions(+), 321 deletions(-) delete mode 100644 include/boost/asio/detail/io_object_executor.hpp diff --git a/include/boost/asio/basic_datagram_socket.hpp b/include/boost/asio/basic_datagram_socket.hpp index cdcae844..b436fc9e 100644 --- a/include/boost/asio/basic_datagram_socket.hpp +++ b/include/boost/asio/basic_datagram_socket.hpp @@ -1094,7 +1094,7 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_send( self_->impl_.get_implementation(), buffers, flags, - handler2.value, self_->impl_.get_implementation_executor()); + handler2.value, self_->impl_.get_executor()); } private: @@ -1127,8 +1127,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_send_to( - self_->impl_.get_implementation(), buffers, destination, flags, - handler2.value, self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, destination, + flags, handler2.value, self_->impl_.get_executor()); } private: @@ -1162,7 +1162,7 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_receive( self_->impl_.get_implementation(), buffers, flags, - handler2.value, self_->impl_.get_implementation_executor()); + handler2.value, self_->impl_.get_executor()); } private: @@ -1195,8 +1195,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_receive_from( - self_->impl_.get_implementation(), buffers, *sender_endpoint, flags, - handler2.value, self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, *sender_endpoint, + flags, handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/basic_deadline_timer.hpp b/include/boost/asio/basic_deadline_timer.hpp index 181c7d1d..0a0f5b19 100644 --- a/include/boost/asio/basic_deadline_timer.hpp +++ b/include/boost/asio/basic_deadline_timer.hpp @@ -672,8 +672,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_wait( - self_->impl_.get_implementation(), handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/basic_raw_socket.hpp b/include/boost/asio/basic_raw_socket.hpp index 3b47b9e9..d86fabd1 100644 --- a/include/boost/asio/basic_raw_socket.hpp +++ b/include/boost/asio/basic_raw_socket.hpp @@ -1086,7 +1086,7 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_send( self_->impl_.get_implementation(), buffers, flags, - handler2.value, self_->impl_.get_implementation_executor()); + handler2.value, self_->impl_.get_executor()); } private: @@ -1119,8 +1119,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_send_to( - self_->impl_.get_implementation(), buffers, destination, flags, - handler2.value, self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, destination, + flags, handler2.value, self_->impl_.get_executor()); } private: @@ -1154,7 +1154,7 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_receive( self_->impl_.get_implementation(), buffers, flags, - handler2.value, self_->impl_.get_implementation_executor()); + handler2.value, self_->impl_.get_executor()); } private: @@ -1187,8 +1187,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_receive_from( - self_->impl_.get_implementation(), buffers, *sender_endpoint, flags, - handler2.value, self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, *sender_endpoint, + flags, handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/basic_seq_packet_socket.hpp b/include/boost/asio/basic_seq_packet_socket.hpp index 6ceca2e6..cc005b0b 100644 --- a/include/boost/asio/basic_seq_packet_socket.hpp +++ b/include/boost/asio/basic_seq_packet_socket.hpp @@ -707,7 +707,7 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_send( self_->impl_.get_implementation(), buffers, flags, - handler2.value, self_->impl_.get_implementation_executor()); + handler2.value, self_->impl_.get_executor()); } private: @@ -741,8 +741,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_receive_with_flags( - self_->impl_.get_implementation(), buffers, in_flags, *out_flags, - handler2.value, self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, in_flags, + *out_flags, handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/basic_serial_port.hpp b/include/boost/asio/basic_serial_port.hpp index 883f191e..7163c37a 100644 --- a/include/boost/asio/basic_serial_port.hpp +++ b/include/boost/asio/basic_serial_port.hpp @@ -850,8 +850,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_write_some( - self_->impl_.get_implementation(), buffers, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); } private: @@ -883,8 +883,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_read_some( - self_->impl_.get_implementation(), buffers, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/basic_signal_set.hpp b/include/boost/asio/basic_signal_set.hpp index 5ea391c0..8584b243 100644 --- a/include/boost/asio/basic_signal_set.hpp +++ b/include/boost/asio/basic_signal_set.hpp @@ -553,8 +553,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_wait( - self_->impl_.get_implementation(), handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/basic_socket.hpp b/include/boost/asio/basic_socket.hpp index 33565b93..4a00c404 100644 --- a/include/boost/asio/basic_socket.hpp +++ b/include/boost/asio/basic_socket.hpp @@ -1847,7 +1847,7 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_connect( self_->impl_.get_implementation(), peer_endpoint, - handler2.value, self_->impl_.get_implementation_executor()); + handler2.value, self_->impl_.get_executor()); } } @@ -1879,8 +1879,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_wait( - self_->impl_.get_implementation(), w, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), w, + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/basic_socket_acceptor.hpp b/include/boost/asio/basic_socket_acceptor.hpp index 7897853d..c55e3aaa 100644 --- a/include/boost/asio/basic_socket_acceptor.hpp +++ b/include/boost/asio/basic_socket_acceptor.hpp @@ -2401,8 +2401,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_wait( - self_->impl_.get_implementation(), w, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), w, + handler2.value, self_->impl_.get_executor()); } private: @@ -2436,7 +2436,7 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_accept( self_->impl_.get_implementation(), *peer, peer_endpoint, - handler2.value, self_->impl_.get_implementation_executor()); + handler2.value, self_->impl_.get_executor()); } private: @@ -2470,7 +2470,7 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_move_accept( self_->impl_.get_implementation(), peer_ex, peer_endpoint, - handler2.value, self_->impl_.get_implementation_executor()); + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/basic_stream_socket.hpp b/include/boost/asio/basic_stream_socket.hpp index ee9c0ee5..0afa3abb 100644 --- a/include/boost/asio/basic_stream_socket.hpp +++ b/include/boost/asio/basic_stream_socket.hpp @@ -1001,7 +1001,7 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_send( self_->impl_.get_implementation(), buffers, flags, - handler2.value, self_->impl_.get_implementation_executor()); + handler2.value, self_->impl_.get_executor()); } private: @@ -1035,7 +1035,7 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_receive( self_->impl_.get_implementation(), buffers, flags, - handler2.value, self_->impl_.get_implementation_executor()); + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/basic_waitable_timer.hpp b/include/boost/asio/basic_waitable_timer.hpp index d2e7cd97..86273745 100644 --- a/include/boost/asio/basic_waitable_timer.hpp +++ b/include/boost/asio/basic_waitable_timer.hpp @@ -791,8 +791,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_wait( - self_->impl_.get_implementation(), handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/detail/handler_work.hpp b/include/boost/asio/detail/handler_work.hpp index 5ae76e26..79a53ce7 100644 --- a/include/boost/asio/detail/handler_work.hpp +++ b/include/boost/asio/detail/handler_work.hpp @@ -18,85 +18,221 @@ #include #include #include +#include #include namespace boost { namespace asio { + +class executor; +class io_context; + namespace detail { +template +class handler_work_base +{ +public: + explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT + : executor_(ex), + owns_work_(true) + { + executor_.on_work_started(); + } + + handler_work_base(const Executor& ex, + const Executor& candidate) BOOST_ASIO_NOEXCEPT + : executor_(ex), + owns_work_(ex != candidate) + { + if (owns_work_) + executor_.on_work_started(); + } + + template + handler_work_base(const Executor& ex, + const OtherExecutor&) BOOST_ASIO_NOEXCEPT + : executor_(ex), + owns_work_(true) + { + executor_.on_work_started(); + } + + handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_), + owns_work_(other.owns_work_) + { + if (owns_work_) + executor_.on_work_started(); + } + +#if defined(BOOST_ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT + : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), + owns_work_(other.owns_work_) + { + other.owns_work_ = false; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + ~handler_work_base() + { + if (owns_work_) + executor_.on_work_finished(); + } + + bool owns_work() const BOOST_ASIO_NOEXCEPT + { + return owns_work_; + } + + const Executor& get_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_; + } + +private: + Executor executor_; + bool owns_work_; +}; + +template +class handler_work_base::value + >::type> +{ +public: + explicit handler_work_base(const Executor&) + { + } + + bool owns_work() const BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +class handler_work_base +{ +public: + explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT +#if !defined(BOOST_ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? Executor() : ex) +#else // !defined(BOOST_ASIO_NO_TYPEID) + : executor_(ex) +#endif // !defined(BOOST_ASIO_NO_TYPEID) + { + if (executor_) + executor_.on_work_started(); + } + + handler_work_base(const Executor& ex, + const Executor& candidate) BOOST_ASIO_NOEXCEPT + : executor_(ex != candidate ? ex : Executor()) + { + if (executor_) + executor_.on_work_started(); + } + + template + handler_work_base(const Executor& ex, + const OtherExecutor&) BOOST_ASIO_NOEXCEPT + : executor_(ex) + { + executor_.on_work_started(); + } + + handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_) + { + if (executor_) + executor_.on_work_started(); + } + +#if defined(BOOST_ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT + : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + ~handler_work_base() + { + if (executor_) + executor_.on_work_finished(); + } + + bool owns_work() const BOOST_ASIO_NOEXCEPT + { + return !!executor_; + } + + const Executor& get_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_; + } + +private: + Executor executor_; +}; + // A helper class template to allow completion handlers to be dispatched // through either the new executors framework or the old invocaton hook. The // primary template uses the new executors framework. template ::type> -class handler_work +class handler_work : + handler_work_base, + handler_work_base { public: explicit handler_work(Handler& handler) BOOST_ASIO_NOEXCEPT - : io_executor_(), - executor_(boost::asio::get_associated_executor(handler, io_executor_)), - owns_work_(true) + : handler_work_base(IoExecutor()), + handler_work_base( + boost::asio::get_associated_executor(handler), IoExecutor()) { - io_executor_.on_work_started(); - executor_.on_work_started(); } handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT - : io_executor_(io_ex), - executor_(boost::asio::get_associated_executor(handler, io_executor_)), - owns_work_(true) + : handler_work_base(io_ex), + handler_work_base( + boost::asio::get_associated_executor(handler, io_ex), io_ex) { - io_executor_.on_work_started(); - executor_.on_work_started(); - } - - handler_work(const handler_work& other) - : io_executor_(other.io_executor_), - executor_(other.executor_), - owns_work_(other.owns_work_) - { - if (owns_work_) - { - io_executor_.on_work_started(); - executor_.on_work_started(); - } - } - -#if defined(BOOST_ASIO_HAS_MOVE) - handler_work(handler_work&& other) - : io_executor_(BOOST_ASIO_MOVE_CAST(IoExecutor)(other.io_executor_)), - executor_(BOOST_ASIO_MOVE_CAST(HandlerExecutor)(other.executor_)), - owns_work_(other.owns_work_) - { - other.owns_work_ = false; - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - ~handler_work() - { - if (owns_work_) - { - io_executor_.on_work_finished(); - executor_.on_work_finished(); - } } template void complete(Function& function, Handler& handler) { - executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function), - boost::asio::get_associated_allocator(handler)); + if (!handler_work_base::owns_work() + && !handler_work_base::owns_work()) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. + boost_asio_handler_invoke_helpers::invoke(function, handler); + } + else + { + handler_work_base::get_executor().dispatch( + BOOST_ASIO_MOVE_CAST(Function)(function), + boost::asio::get_associated_allocator(handler)); + } } private: // Disallow assignment. handler_work& operator=(const handler_work&); - - IoExecutor io_executor_; - HandlerExecutor executor_; - bool owns_work_; }; // This specialisation dispatches a handler through the old invocation hook. diff --git a/include/boost/asio/detail/io_object_executor.hpp b/include/boost/asio/detail/io_object_executor.hpp deleted file mode 100644 index dd775b45..00000000 --- a/include/boost/asio/detail/io_object_executor.hpp +++ /dev/null @@ -1,169 +0,0 @@ -// -// io_object_executor.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP -#define BOOST_ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include -#include -#include -#include - -#include - -namespace boost { -namespace asio { -namespace detail { - -// Wrap the (potentially polymorphic) executor so that we can bypass it when -// dispatching on a target executor that has a native I/O implementation. -template -class io_object_executor -{ -public: - io_object_executor(const Executor& ex, - bool native_implementation) BOOST_ASIO_NOEXCEPT - : executor_(ex), - has_native_impl_(native_implementation) - { - } - - io_object_executor(const io_object_executor& other) BOOST_ASIO_NOEXCEPT - : executor_(other.executor_), - has_native_impl_(other.has_native_impl_) - { - } - - template - io_object_executor( - const io_object_executor& other) BOOST_ASIO_NOEXCEPT - : executor_(other.inner_executor()), - has_native_impl_(other.has_native_implementation()) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - io_object_executor(io_object_executor&& other) BOOST_ASIO_NOEXCEPT - : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), - has_native_impl_(other.has_native_impl_) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - const Executor& inner_executor() const BOOST_ASIO_NOEXCEPT - { - return executor_; - } - - bool has_native_implementation() const BOOST_ASIO_NOEXCEPT - { - return has_native_impl_; - } - - execution_context& context() const BOOST_ASIO_NOEXCEPT - { - return executor_.context(); - } - - void on_work_started() const BOOST_ASIO_NOEXCEPT - { - if (is_same::value - || has_native_impl_) - { - // When using a native implementation, work is already counted by the - // execution context. - } - else - { - executor_.on_work_started(); - } - } - - void on_work_finished() const BOOST_ASIO_NOEXCEPT - { - if (is_same::value - || has_native_impl_) - { - // When using a native implementation, work is already counted by the - // execution context. - } - else - { - executor_.on_work_finished(); - } - } - - template - void dispatch(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const - { - if (is_same::value - || has_native_impl_) - { - // When using a native implementation, I/O completion handlers are - // already dispatched according to the execution context's executor's - // rules. We can call the function directly. -#if defined(BOOST_ASIO_HAS_MOVE) - if (is_same::type>::value) - { - boost_asio_handler_invoke_helpers::invoke(f, f); - return; - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - typename decay::type function(BOOST_ASIO_MOVE_CAST(F)(f)); - boost_asio_handler_invoke_helpers::invoke(function, function); - } - else - { - executor_.dispatch(BOOST_ASIO_MOVE_CAST(F)(f), a); - } - } - - template - void post(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const - { - executor_.post(BOOST_ASIO_MOVE_CAST(F)(f), a); - } - - template - void defer(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const - { - executor_.defer(BOOST_ASIO_MOVE_CAST(F)(f), a); - } - - friend bool operator==(const io_object_executor& a, - const io_object_executor& b) BOOST_ASIO_NOEXCEPT - { - return a.executor_ == b.executor_ - && a.has_native_impl_ == b.has_native_impl_; - } - - friend bool operator!=(const io_object_executor& a, - const io_object_executor& b) BOOST_ASIO_NOEXCEPT - { - return a.executor_ != b.executor_ - || a.has_native_impl_ != b.has_native_impl_; - } - -private: - Executor executor_; - const bool has_native_impl_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP diff --git a/include/boost/asio/detail/io_object_impl.hpp b/include/boost/asio/detail/io_object_impl.hpp index 23b2e8ae..06287709 100644 --- a/include/boost/asio/detail/io_object_impl.hpp +++ b/include/boost/asio/detail/io_object_impl.hpp @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -25,34 +24,8 @@ namespace boost { namespace asio { - -class executor; - namespace detail { -inline bool is_native_io_executor(const io_context::executor_type&) -{ - return true; -} - -template -inline bool is_native_io_executor(const Executor&, - typename enable_if::value>::type* = 0) -{ - return false; -} - -template -inline bool is_native_io_executor(const Executor& ex, - typename enable_if::value>::type* = 0) -{ -#if !defined (BOOST_ASIO_NO_TYPEID) - return ex.target_type() == typeid(io_context::executor_type); -#else // !defined (BOOST_ASIO_NO_TYPEID) - return false; -#endif // !defined (BOOST_ASIO_NO_TYPEID) -} - template class io_object_impl @@ -67,13 +40,10 @@ public: // The type of the executor associated with the object. typedef Executor executor_type; - // The type of executor to be used when implementing asynchronous operations. - typedef io_object_executor implementation_executor_type; - // Construct an I/O object using an executor. explicit io_object_impl(const executor_type& ex) : service_(&boost::asio::use_service(ex.context())), - implementation_executor_(ex, (is_native_io_executor)(ex)) + executor_(ex) { service_->construct(implementation_); } @@ -84,8 +54,7 @@ public: typename enable_if::value>::type* = 0) : service_(&boost::asio::use_service(context)), - implementation_executor_(context.get_executor(), - is_same::value) + executor_(context.get_executor()) { service_->construct(implementation_); } @@ -94,7 +63,7 @@ public: // Move-construct an I/O object. io_object_impl(io_object_impl&& other) : service_(&other.get_service()), - implementation_executor_(other.get_implementation_executor()) + executor_(other.get_executor()) { service_->move_construct(implementation_, other.implementation_); } @@ -103,8 +72,8 @@ public: template io_object_impl(io_object_impl&& other) : service_(&boost::asio::use_service( - other.get_implementation_executor().context())), - implementation_executor_(other.get_implementation_executor()) + other.get_executor().context())), + executor_(other.get_executor()) { service_->converting_move_construct(implementation_, other.get_service(), other.get_implementation()); @@ -125,9 +94,9 @@ public: { service_->move_assign(implementation_, *other.service_, other.implementation_); - implementation_executor_.~implementation_executor_type(); - new (&implementation_executor_) implementation_executor_type( - std::move(other.implementation_executor_)); + executor_.~executor_type(); + new (&executor_) executor_type( + std::move(other.executor_)); service_ = other.service_; } return *this; @@ -135,16 +104,9 @@ public: #endif // defined(BOOST_ASIO_HAS_MOVE) // Get the executor associated with the object. - executor_type get_executor() BOOST_ASIO_NOEXCEPT + const executor_type& get_executor() BOOST_ASIO_NOEXCEPT { - return implementation_executor_.inner_executor(); - } - - // Get the executor to be used when implementing asynchronous operations. - const implementation_executor_type& get_implementation_executor() - BOOST_ASIO_NOEXCEPT - { - return implementation_executor_; + return executor_; } // Get the service associated with the I/O object. @@ -183,7 +145,7 @@ private: implementation_type implementation_; // The associated executor. - implementation_executor_type implementation_executor_; + executor_type executor_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp b/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp index 061ce3f9..ad32f87e 100644 --- a/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp +++ b/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -81,10 +80,10 @@ public: const bool native = is_same::value; win_iocp_io_context* iocp_service = this->get_iocp_service(ex); - typedef win_iocp_overlapped_op > op; + typedef win_iocp_overlapped_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler, io_object_executor(ex, native)); + p.p = new (p.v) op(handler, ex); BOOST_ASIO_HANDLER_CREATION((ex.context(), *p.p, "iocp_service", iocp_service, 0, "overlapped")); diff --git a/include/boost/asio/ip/basic_resolver.hpp b/include/boost/asio/ip/basic_resolver.hpp index 50f5d56b..48fae095 100644 --- a/include/boost/asio/ip/basic_resolver.hpp +++ b/include/boost/asio/ip/basic_resolver.hpp @@ -1004,8 +1004,8 @@ private: boost::asio::detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_resolve( - self_->impl_.get_implementation(), q, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), q, + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/posix/basic_descriptor.hpp b/include/boost/asio/posix/basic_descriptor.hpp index f5b97033..83faf3b3 100644 --- a/include/boost/asio/posix/basic_descriptor.hpp +++ b/include/boost/asio/posix/basic_descriptor.hpp @@ -678,8 +678,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_wait( - self_->impl_.get_implementation(), w, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), w, + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/posix/basic_stream_descriptor.hpp b/include/boost/asio/posix/basic_stream_descriptor.hpp index 7132f3da..7c375df7 100644 --- a/include/boost/asio/posix/basic_stream_descriptor.hpp +++ b/include/boost/asio/posix/basic_stream_descriptor.hpp @@ -420,8 +420,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_write_some( - self_->impl_.get_implementation(), buffers, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); } private: @@ -453,8 +453,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_read_some( - self_->impl_.get_implementation(), buffers, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/windows/basic_object_handle.hpp b/include/boost/asio/windows/basic_object_handle.hpp index 283dbb04..f03d1fb3 100644 --- a/include/boost/asio/windows/basic_object_handle.hpp +++ b/include/boost/asio/windows/basic_object_handle.hpp @@ -413,8 +413,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_wait( - self_->impl_.get_implementation(), handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/windows/basic_random_access_handle.hpp b/include/boost/asio/windows/basic_random_access_handle.hpp index e1d04c78..1677d50e 100644 --- a/include/boost/asio/windows/basic_random_access_handle.hpp +++ b/include/boost/asio/windows/basic_random_access_handle.hpp @@ -438,8 +438,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_write_some_at( - self_->impl_.get_implementation(), offset, buffers, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), offset, buffers, + handler2.value, self_->impl_.get_executor()); } private: @@ -471,8 +471,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_read_some_at( - self_->impl_.get_implementation(), offset, buffers, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), offset, buffers, + handler2.value, self_->impl_.get_executor()); } private: diff --git a/include/boost/asio/windows/basic_stream_handle.hpp b/include/boost/asio/windows/basic_stream_handle.hpp index c0323dc2..32ac165e 100644 --- a/include/boost/asio/windows/basic_stream_handle.hpp +++ b/include/boost/asio/windows/basic_stream_handle.hpp @@ -422,8 +422,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_write_some( - self_->impl_.get_implementation(), buffers, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); } private: @@ -455,8 +455,8 @@ private: detail::non_const_lvalue handler2(handler); self_->impl_.get_service().async_read_some( - self_->impl_.get_implementation(), buffers, handler2.value, - self_->impl_.get_implementation_executor()); + self_->impl_.get_implementation(), buffers, + handler2.value, self_->impl_.get_executor()); } private: From 24bb388fb90156629563849d3cd2d3765559887e Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:41:46 +1000 Subject: [PATCH 40/90] Change detail::completion_handler<> to use an I/O executor. --- .../boost/asio/detail/completion_handler.hpp | 13 +++++++------ .../boost/asio/detail/impl/strand_service.hpp | 17 ++++++++--------- .../boost/asio/detail/impl/strand_service.ipp | 9 +++++---- include/boost/asio/detail/strand_service.hpp | 5 ++++- include/boost/asio/impl/io_context.hpp | 8 ++++---- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/include/boost/asio/detail/completion_handler.hpp b/include/boost/asio/detail/completion_handler.hpp index 6684e954..4d7ac23a 100644 --- a/include/boost/asio/detail/completion_handler.hpp +++ b/include/boost/asio/detail/completion_handler.hpp @@ -28,16 +28,16 @@ namespace boost { namespace asio { namespace detail { -template +template class completion_handler : public operation { public: BOOST_ASIO_DEFINE_HANDLER_PTR(completion_handler); - completion_handler(Handler& h) + completion_handler(Handler& h, const IoExecutor& io_ex) : operation(&completion_handler::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)), - work_(handler_) + work_(handler_, io_ex) { } @@ -52,8 +52,9 @@ public: BOOST_ASIO_HANDLER_COMPLETION((*h)); // Take ownership of the operation's outstanding work. - handler_work w( - BOOST_ASIO_MOVE_CAST(handler_work)(h->work_)); + handler_work w( + BOOST_ASIO_MOVE_CAST2(handler_work)( + h->work_)); // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a @@ -77,7 +78,7 @@ public: private: Handler handler_; - handler_work work_; + handler_work work_; }; } // namespace detail diff --git a/include/boost/asio/detail/impl/strand_service.hpp b/include/boost/asio/detail/impl/strand_service.hpp index 6ca4673c..fe95d630 100644 --- a/include/boost/asio/detail/impl/strand_service.hpp +++ b/include/boost/asio/detail/impl/strand_service.hpp @@ -36,7 +36,7 @@ inline strand_service::strand_impl::strand_impl() struct strand_service::on_dispatch_exit { - io_context_impl* io_context_; + io_context_impl* io_context_impl_; strand_impl* impl_; ~on_dispatch_exit() @@ -47,7 +47,7 @@ struct strand_service::on_dispatch_exit impl_->mutex_.unlock(); if (more_handlers) - io_context_->post_immediate_completion(impl_, false); + io_context_impl_->post_immediate_completion(impl_, false); } }; @@ -64,10 +64,10 @@ void strand_service::dispatch(strand_service::implementation_type& impl, } // Allocate and construct an operation to wrap the handler. - typedef completion_handler op; + typedef completion_handler op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(handler, io_context_.get_executor()); BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, "strand", impl, 0, "dispatch")); @@ -82,11 +82,10 @@ void strand_service::dispatch(strand_service::implementation_type& impl, call_stack::context ctx(impl); // Ensure the next handler, if any, is scheduled on block exit. - on_dispatch_exit on_exit = { &io_context_, impl }; + on_dispatch_exit on_exit = { &io_context_impl_, impl }; (void)on_exit; - completion_handler::do_complete( - &io_context_, o, boost::system::error_code(), 0); + op::do_complete(&io_context_impl_, o, boost::system::error_code(), 0); } } @@ -99,10 +98,10 @@ void strand_service::post(strand_service::implementation_type& impl, boost_asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. - typedef completion_handler op; + typedef completion_handler op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; - p.p = new (p.v) op(handler); + p.p = new (p.v) op(handler, io_context_.get_executor()); BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, "strand", impl, 0, "post")); diff --git a/include/boost/asio/detail/impl/strand_service.ipp b/include/boost/asio/detail/impl/strand_service.ipp index e7f5f1be..885bb0aa 100644 --- a/include/boost/asio/detail/impl/strand_service.ipp +++ b/include/boost/asio/detail/impl/strand_service.ipp @@ -44,7 +44,8 @@ struct strand_service::on_do_complete_exit strand_service::strand_service(boost::asio::io_context& io_context) : boost::asio::detail::service_base(io_context), - io_context_(boost::asio::use_service(io_context)), + io_context_(io_context), + io_context_impl_(boost::asio::use_service(io_context)), mutex_(), salt_(0) { @@ -95,7 +96,7 @@ bool strand_service::do_dispatch(implementation_type& impl, operation* op) { // If we are running inside the io_context, and no other handler already // holds the strand lock, then the handler can run immediately. - bool can_dispatch = io_context_.can_dispatch(); + bool can_dispatch = io_context_impl_.can_dispatch(); impl->mutex_.lock(); if (can_dispatch && !impl->locked_) { @@ -118,7 +119,7 @@ bool strand_service::do_dispatch(implementation_type& impl, operation* op) impl->locked_ = true; impl->mutex_.unlock(); impl->ready_queue_.push(op); - io_context_.post_immediate_completion(impl, false); + io_context_impl_.post_immediate_completion(impl, false); } return false; @@ -141,7 +142,7 @@ void strand_service::do_post(implementation_type& impl, impl->locked_ = true; impl->mutex_.unlock(); impl->ready_queue_.push(op); - io_context_.post_immediate_completion(impl, is_continuation); + io_context_impl_.post_immediate_completion(impl, is_continuation); } } diff --git a/include/boost/asio/detail/strand_service.hpp b/include/boost/asio/detail/strand_service.hpp index 68635d62..17fdb749 100644 --- a/include/boost/asio/detail/strand_service.hpp +++ b/include/boost/asio/detail/strand_service.hpp @@ -109,8 +109,11 @@ private: operation* base, const boost::system::error_code& ec, std::size_t bytes_transferred); + // The io_context used to obtain an I/O executor. + io_context& io_context_; + // The io_context implementation used to post completions. - io_context_impl& io_context_; + io_context_impl& io_context_impl_; // Mutex to protect access to the array of implementations. boost::asio::detail::mutex mutex_; diff --git a/include/boost/asio/impl/io_context.hpp b/include/boost/asio/impl/io_context.hpp index 91d2d7b2..ef33eec3 100644 --- a/include/boost/asio/impl/io_context.hpp +++ b/include/boost/asio/impl/io_context.hpp @@ -157,10 +157,10 @@ struct io_context::initiate_dispatch { // Allocate and construct an operation to wrap the handler. typedef detail::completion_handler< - typename decay::type> op; + typename decay::type, executor_type> op; typename op::ptr p = { detail::addressof(handler2.value), op::ptr::allocate(handler2.value), 0 }; - p.p = new (p.v) op(handler2.value); + p.p = new (p.v) op(handler2.value, self->get_executor()); BOOST_ASIO_HANDLER_CREATION((*self, *p.p, "io_context", self, 0, "dispatch")); @@ -197,10 +197,10 @@ struct io_context::initiate_post // Allocate and construct an operation to wrap the handler. typedef detail::completion_handler< - typename decay::type> op; + typename decay::type, executor_type> op; typename op::ptr p = { detail::addressof(handler2.value), op::ptr::allocate(handler2.value), 0 }; - p.p = new (p.v) op(handler2.value); + p.p = new (p.v) op(handler2.value, self->get_executor()); BOOST_ASIO_HANDLER_CREATION((*self, *p.p, "io_context", self, 0, "post")); From 7dad754997a03eb482f2beb4de8c7f3990a0a324 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:46:10 +1000 Subject: [PATCH 41/90] Don't default the IoExecutor in detail::handler_work<>. --- include/boost/asio/detail/handler_work.hpp | 38 ++-------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/include/boost/asio/detail/handler_work.hpp b/include/boost/asio/detail/handler_work.hpp index 79a53ce7..d398d776 100644 --- a/include/boost/asio/detail/handler_work.hpp +++ b/include/boost/asio/detail/handler_work.hpp @@ -186,24 +186,14 @@ private: Executor executor_; }; -// A helper class template to allow completion handlers to be dispatched -// through either the new executors framework or the old invocaton hook. The -// primary template uses the new executors framework. -template ::type> +template ::type> class handler_work : handler_work_base, handler_work_base { public: - explicit handler_work(Handler& handler) BOOST_ASIO_NOEXCEPT - : handler_work_base(IoExecutor()), - handler_work_base( - boost::asio::get_associated_executor(handler), IoExecutor()) - { - } - handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT : handler_work_base(io_ex), handler_work_base( @@ -235,28 +225,6 @@ private: handler_work& operator=(const handler_work&); }; -// This specialisation dispatches a handler through the old invocation hook. -// The specialisation is not strictly required for correctness, as the -// system_executor will dispatch through the hook anyway. However, by doing -// this we avoid an extra copy of the handler. -template -class handler_work -{ -public: - explicit handler_work(Handler&) BOOST_ASIO_NOEXCEPT {} - handler_work(Handler&, const system_executor&) BOOST_ASIO_NOEXCEPT {} - - template - void complete(Function& function, Handler& handler) - { - boost_asio_handler_invoke_helpers::invoke(function, handler); - } - -private: - // Disallow assignment. - handler_work& operator=(const handler_work&); -}; - } // namespace detail } // namespace asio } // namespace boost From 0d0e36be72b2e36d3dca1f985b7170ecddd61ad4 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:49:59 +1000 Subject: [PATCH 42/90] Fix compile error on MSVC 2017. --- include/boost/asio/impl/compose.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/asio/impl/compose.hpp b/include/boost/asio/impl/compose.hpp index ba9f2b06..048ad310 100644 --- a/include/boost/asio/impl/compose.hpp +++ b/include/boost/asio/impl/compose.hpp @@ -291,7 +291,7 @@ namespace detail template void operator()(BOOST_ASIO_MOVE_ARG(T)... t) { - if (invocations_ < ~unsigned(0)) + if (invocations_ < ~0u) ++invocations_; impl_(*this, BOOST_ASIO_MOVE_CAST(T)(t)...); } @@ -306,7 +306,7 @@ namespace detail void operator()() { - if (invocations_ < ~unsigned(0)) + if (invocations_ < ~0u) ++invocations_; impl_(*this); } @@ -321,7 +321,7 @@ namespace detail template \ void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ { \ - if (invocations_ < ~unsigned(0)) \ + if (invocations_ < ~0u) \ ++invocations_; \ impl_(*this, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ From 5d65dba5c8d607b451f4b8f12c5a4092e872b674 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 21:50:23 +1000 Subject: [PATCH 43/90] Fix copy/paste errors in "Networking TS compatibility" docs. --- doc/net_ts.qbk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/net_ts.qbk b/doc/net_ts.qbk index 32ab46d9..4ffee0ad 100644 --- a/doc/net_ts.qbk +++ b/doc/net_ts.qbk @@ -44,14 +44,14 @@ below shows the new Networking TS interfaces and the facilities they replace: ExecutionContext].] ] [ - [[link boost_asio.reference.dispatch `post`]] + [[link boost_asio.reference.post `post`]] [[link boost_asio.reference.io_context.post `io_service::post`]] - [The `dispatch` free function can be used to submit functions to any [link + [The `post` free function can be used to submit functions to any [link boost_asio.reference.Executor1 Executor] or [link boost_asio.reference.ExecutionContext ExecutionContext].] ] [ - [[link boost_asio.reference.dispatch `defer`]] + [[link boost_asio.reference.defer `defer`]] [[link boost_asio.reference.io_context.post `io_service::post`] when the [link boost_asio.reference.asio_handler_is_continuation `asio_handler_is_continuation`] hook returns true] From 4d7ad03b7fca2185b62825eda1e0532e646defba Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:10:22 +1000 Subject: [PATCH 44/90] Add ability to run function templates as tests. --- test/unit_test.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/unit_test.hpp b/test/unit_test.hpp index 126f53af..de1f55d5 100644 --- a/test/unit_test.hpp +++ b/test/unit_test.hpp @@ -154,6 +154,21 @@ void throw_exception(const T& t) #define BOOST_ASIO_TEST_CASE(test) \ boost::asio::detail::run_test<&test>(#test); +#define BOOST_ASIO_TEST_CASE2(test1, test2) \ + boost::asio::detail::run_test<&test1, test2>(#test1 "," #test2); + +#define BOOST_ASIO_TEST_CASE3(test1, test2, test3) \ + boost::asio::detail::run_test<&test1, test2, test3>( \ + #test1 "," #test2 "," #test3); + +#define BOOST_ASIO_TEST_CASE4(test1, test2, test3, test4) \ + boost::asio::detail::run_test<&test1, test2, test3, test4>( \ + #test1 "," #test2 "," #test3 "," #test4); + +#define BOOST_ASIO_TEST_CASE5(test1, test2, test3, test4, test5) \ + boost::asio::detail::run_test<&test1, test2, test3, test4, test5>( \ + #test1 "," #test2 "," #test3 "," #test4 "," #test5); + #define BOOST_ASIO_COMPILE_TEST_CASE(test) \ boost::asio::detail::compile_test<&test>(#test); From fac4056517b31292c9c599b093638b660245de25 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:21:37 +1000 Subject: [PATCH 45/90] Add properties implementation. --- include/boost/asio.hpp | 5 + include/boost/asio/detail/config.hpp | 115 ++- include/boost/asio/detail/type_traits.hpp | 2 + include/boost/asio/is_applicable_property.hpp | 63 ++ include/boost/asio/prefer.hpp | 660 ++++++++++++++++++ include/boost/asio/query.hpp | 300 ++++++++ include/boost/asio/require.hpp | 528 ++++++++++++++ include/boost/asio/require_concept.hpp | 314 +++++++++ include/boost/asio/traits/prefer_free.hpp | 110 +++ include/boost/asio/traits/prefer_member.hpp | 110 +++ include/boost/asio/traits/query_free.hpp | 110 +++ include/boost/asio/traits/query_member.hpp | 110 +++ .../asio/traits/require_concept_free.hpp | 110 +++ .../asio/traits/require_concept_member.hpp | 110 +++ include/boost/asio/traits/require_free.hpp | 110 +++ include/boost/asio/traits/require_member.hpp | 110 +++ include/boost/asio/traits/static_query.hpp | 110 +++ include/boost/asio/traits/static_require.hpp | 125 ++++ .../asio/traits/static_require_concept.hpp | 125 ++++ test/properties/cpp03/Jamfile.v2 | 101 +++ .../cpp03/can_prefer_free_prefer.cpp | 61 ++ .../cpp03/can_prefer_free_require.cpp | 61 ++ .../cpp03/can_prefer_member_prefer.cpp | 61 ++ .../cpp03/can_prefer_member_require.cpp | 61 ++ .../can_prefer_not_applicable_free_prefer.cpp | 54 ++ ...can_prefer_not_applicable_free_require.cpp | 54 ++ ...an_prefer_not_applicable_member_prefer.cpp | 54 ++ ...n_prefer_not_applicable_member_require.cpp | 54 ++ .../can_prefer_not_applicable_static.cpp | 47 ++ .../can_prefer_not_applicable_unsupported.cpp | 33 + .../can_prefer_not_preferable_free_prefer.cpp | 61 ++ ...can_prefer_not_preferable_free_require.cpp | 61 ++ ...an_prefer_not_preferable_member_prefer.cpp | 61 ++ ...n_prefer_not_preferable_member_require.cpp | 61 ++ .../can_prefer_not_preferable_static.cpp | 54 ++ .../can_prefer_not_preferable_unsupported.cpp | 45 ++ test/properties/cpp03/can_prefer_static.cpp | 54 ++ .../cpp03/can_prefer_unsupported.cpp | 45 ++ test/properties/cpp03/can_query_free.cpp | 50 ++ test/properties/cpp03/can_query_member.cpp | 50 ++ .../cpp03/can_query_not_applicable_free.cpp | 43 ++ .../cpp03/can_query_not_applicable_member.cpp | 43 ++ .../cpp03/can_query_not_applicable_static.cpp | 43 ++ .../can_query_not_applicable_unsupported.cpp | 26 + test/properties/cpp03/can_query_static.cpp | 50 ++ .../cpp03/can_query_unsupported.cpp | 38 + .../cpp03/can_require_concept_free.cpp | 57 ++ .../cpp03/can_require_concept_member.cpp | 57 ++ ...an_require_concept_not_applicable_free.cpp | 50 ++ ..._require_concept_not_applicable_member.cpp | 50 ++ ..._require_concept_not_applicable_static.cpp | 43 ++ ...ire_concept_not_applicable_unsupported.cpp | 28 + .../cpp03/can_require_concept_static.cpp | 50 ++ .../cpp03/can_require_concept_unsupported.cpp | 40 ++ test/properties/cpp03/can_require_free.cpp | 61 ++ test/properties/cpp03/can_require_member.cpp | 61 ++ .../cpp03/can_require_not_applicable_free.cpp | 54 ++ .../can_require_not_applicable_member.cpp | 54 ++ .../can_require_not_applicable_static.cpp | 47 ++ ...can_require_not_applicable_unsupported.cpp | 32 + test/properties/cpp03/can_require_static.cpp | 54 ++ .../cpp03/can_require_unsupported.cpp | 44 ++ test/properties/cpp03/prefer_free_prefer.cpp | 70 ++ test/properties/cpp03/prefer_free_require.cpp | 70 ++ .../properties/cpp03/prefer_member_prefer.cpp | 70 ++ .../cpp03/prefer_member_require.cpp | 70 ++ test/properties/cpp03/prefer_static.cpp | 63 ++ test/properties/cpp03/prefer_unsupported.cpp | 48 ++ test/properties/cpp03/query_free.cpp | 57 ++ test/properties/cpp03/query_member.cpp | 57 ++ test/properties/cpp03/query_static.cpp | 57 ++ .../properties/cpp03/require_concept_free.cpp | 62 ++ .../cpp03/require_concept_member.cpp | 62 ++ .../cpp03/require_concept_static.cpp | 57 ++ test/properties/cpp03/require_free.cpp | 70 ++ test/properties/cpp03/require_member.cpp | 70 ++ test/properties/cpp03/require_static.cpp | 63 ++ test/properties/cpp11/Jamfile.v2 | 101 +++ .../cpp11/can_prefer_free_prefer.cpp | 50 ++ .../cpp11/can_prefer_free_require.cpp | 50 ++ .../cpp11/can_prefer_member_prefer.cpp | 50 ++ .../cpp11/can_prefer_member_require.cpp | 50 ++ .../can_prefer_not_applicable_free_prefer.cpp | 38 + ...can_prefer_not_applicable_free_require.cpp | 38 + ...an_prefer_not_applicable_member_prefer.cpp | 38 + ...n_prefer_not_applicable_member_require.cpp | 38 + .../can_prefer_not_applicable_static.cpp | 47 ++ .../can_prefer_not_applicable_unsupported.cpp | 33 + .../can_prefer_not_preferable_free_prefer.cpp | 50 ++ ...can_prefer_not_preferable_free_require.cpp | 50 ++ ...an_prefer_not_preferable_member_prefer.cpp | 50 ++ ...n_prefer_not_preferable_member_require.cpp | 50 ++ .../can_prefer_not_preferable_static.cpp | 45 ++ .../can_prefer_not_preferable_unsupported.cpp | 45 ++ test/properties/cpp11/can_prefer_static.cpp | 54 ++ .../cpp11/can_prefer_unsupported.cpp | 45 ++ test/properties/cpp11/can_query_free.cpp | 39 ++ test/properties/cpp11/can_query_member.cpp | 39 ++ .../cpp11/can_query_not_applicable_free.cpp | 27 + .../cpp11/can_query_not_applicable_member.cpp | 27 + .../cpp11/can_query_not_applicable_static.cpp | 43 ++ .../can_query_not_applicable_unsupported.cpp | 26 + test/properties/cpp11/can_query_static.cpp | 50 ++ .../cpp11/can_query_unsupported.cpp | 38 + .../cpp11/can_require_concept_free.cpp | 46 ++ .../cpp11/can_require_concept_member.cpp | 46 ++ ...an_require_concept_not_applicable_free.cpp | 34 + ..._require_concept_not_applicable_member.cpp | 34 + ..._require_concept_not_applicable_static.cpp | 43 ++ ...ire_concept_not_applicable_unsupported.cpp | 28 + .../cpp11/can_require_concept_static.cpp | 50 ++ .../cpp11/can_require_concept_unsupported.cpp | 40 ++ test/properties/cpp11/can_require_free.cpp | 50 ++ test/properties/cpp11/can_require_member.cpp | 50 ++ .../cpp11/can_require_not_applicable_free.cpp | 38 + .../can_require_not_applicable_member.cpp | 38 + .../can_require_not_applicable_static.cpp | 47 ++ ...can_require_not_applicable_unsupported.cpp | 32 + test/properties/cpp11/can_require_static.cpp | 54 ++ .../cpp11/can_require_unsupported.cpp | 44 ++ test/properties/cpp11/prefer_free_prefer.cpp | 66 ++ test/properties/cpp11/prefer_free_require.cpp | 66 ++ .../properties/cpp11/prefer_member_prefer.cpp | 66 ++ .../cpp11/prefer_member_require.cpp | 66 ++ test/properties/cpp11/prefer_static.cpp | 70 ++ test/properties/cpp11/prefer_unsupported.cpp | 61 ++ test/properties/cpp11/query_free.cpp | 51 ++ test/properties/cpp11/query_member.cpp | 51 ++ test/properties/cpp11/query_static.cpp | 62 ++ .../properties/cpp11/require_concept_free.cpp | 54 ++ .../cpp11/require_concept_member.cpp | 54 ++ .../cpp11/require_concept_static.cpp | 60 ++ test/properties/cpp11/require_free.cpp | 66 ++ test/properties/cpp11/require_member.cpp | 66 ++ test/properties/cpp11/require_static.cpp | 70 ++ test/properties/cpp14/Jamfile.v2 | 101 +++ .../cpp14/can_prefer_free_prefer.cpp | 39 ++ .../cpp14/can_prefer_free_require.cpp | 39 ++ .../cpp14/can_prefer_member_prefer.cpp | 39 ++ .../cpp14/can_prefer_member_require.cpp | 39 ++ .../can_prefer_not_applicable_free_prefer.cpp | 38 + ...can_prefer_not_applicable_free_require.cpp | 38 + ...an_prefer_not_applicable_member_prefer.cpp | 38 + ...n_prefer_not_applicable_member_require.cpp | 38 + .../can_prefer_not_applicable_static.cpp | 35 + .../can_prefer_not_applicable_unsupported.cpp | 32 + .../can_prefer_not_preferable_free_prefer.cpp | 39 ++ ...can_prefer_not_preferable_free_require.cpp | 39 ++ ...an_prefer_not_preferable_member_prefer.cpp | 39 ++ ...n_prefer_not_preferable_member_require.cpp | 39 ++ .../can_prefer_not_preferable_static.cpp | 34 + .../can_prefer_not_preferable_unsupported.cpp | 34 + test/properties/cpp14/can_prefer_static.cpp | 36 + .../cpp14/can_prefer_unsupported.cpp | 44 ++ test/properties/cpp14/can_query_free.cpp | 28 + test/properties/cpp14/can_query_member.cpp | 28 + .../cpp14/can_query_not_applicable_free.cpp | 27 + .../cpp14/can_query_not_applicable_member.cpp | 27 + .../cpp14/can_query_not_applicable_static.cpp | 27 + .../can_query_not_applicable_unsupported.cpp | 26 + test/properties/cpp14/can_query_static.cpp | 28 + .../cpp14/can_query_unsupported.cpp | 27 + .../cpp14/can_require_concept_free.cpp | 35 + .../cpp14/can_require_concept_member.cpp | 35 + ...an_require_concept_not_applicable_free.cpp | 34 + ..._require_concept_not_applicable_member.cpp | 34 + ..._require_concept_not_applicable_static.cpp | 31 + ...ire_concept_not_applicable_unsupported.cpp | 28 + .../cpp14/can_require_concept_static.cpp | 32 + .../cpp14/can_require_concept_unsupported.cpp | 40 ++ test/properties/cpp14/can_require_free.cpp | 39 ++ test/properties/cpp14/can_require_member.cpp | 39 ++ .../cpp14/can_require_not_applicable_free.cpp | 38 + .../can_require_not_applicable_member.cpp | 38 + .../can_require_not_applicable_static.cpp | 35 + ...can_require_not_applicable_unsupported.cpp | 32 + test/properties/cpp14/can_require_static.cpp | 36 + .../cpp14/can_require_unsupported.cpp | 44 ++ test/properties/cpp14/prefer_free_prefer.cpp | 55 ++ test/properties/cpp14/prefer_free_require.cpp | 55 ++ .../properties/cpp14/prefer_member_prefer.cpp | 55 ++ .../cpp14/prefer_member_require.cpp | 55 ++ test/properties/cpp14/prefer_static.cpp | 52 ++ test/properties/cpp14/prefer_unsupported.cpp | 50 ++ test/properties/cpp14/query_free.cpp | 40 ++ test/properties/cpp14/query_member.cpp | 40 ++ test/properties/cpp14/query_static.cpp | 40 ++ .../properties/cpp14/require_concept_free.cpp | 43 ++ .../cpp14/require_concept_member.cpp | 43 ++ .../cpp14/require_concept_static.cpp | 42 ++ test/properties/cpp14/require_free.cpp | 55 ++ test/properties/cpp14/require_member.cpp | 55 ++ test/properties/cpp14/require_static.cpp | 52 ++ 193 files changed, 11486 insertions(+), 9 deletions(-) create mode 100644 include/boost/asio/is_applicable_property.hpp create mode 100644 include/boost/asio/prefer.hpp create mode 100644 include/boost/asio/query.hpp create mode 100644 include/boost/asio/require.hpp create mode 100644 include/boost/asio/require_concept.hpp create mode 100644 include/boost/asio/traits/prefer_free.hpp create mode 100644 include/boost/asio/traits/prefer_member.hpp create mode 100644 include/boost/asio/traits/query_free.hpp create mode 100644 include/boost/asio/traits/query_member.hpp create mode 100644 include/boost/asio/traits/require_concept_free.hpp create mode 100644 include/boost/asio/traits/require_concept_member.hpp create mode 100644 include/boost/asio/traits/require_free.hpp create mode 100644 include/boost/asio/traits/require_member.hpp create mode 100644 include/boost/asio/traits/static_query.hpp create mode 100644 include/boost/asio/traits/static_require.hpp create mode 100644 include/boost/asio/traits/static_require_concept.hpp create mode 100644 test/properties/cpp03/Jamfile.v2 create mode 100644 test/properties/cpp03/can_prefer_free_prefer.cpp create mode 100644 test/properties/cpp03/can_prefer_free_require.cpp create mode 100644 test/properties/cpp03/can_prefer_member_prefer.cpp create mode 100644 test/properties/cpp03/can_prefer_member_require.cpp create mode 100644 test/properties/cpp03/can_prefer_not_applicable_free_prefer.cpp create mode 100644 test/properties/cpp03/can_prefer_not_applicable_free_require.cpp create mode 100644 test/properties/cpp03/can_prefer_not_applicable_member_prefer.cpp create mode 100644 test/properties/cpp03/can_prefer_not_applicable_member_require.cpp create mode 100644 test/properties/cpp03/can_prefer_not_applicable_static.cpp create mode 100644 test/properties/cpp03/can_prefer_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp03/can_prefer_not_preferable_free_prefer.cpp create mode 100644 test/properties/cpp03/can_prefer_not_preferable_free_require.cpp create mode 100644 test/properties/cpp03/can_prefer_not_preferable_member_prefer.cpp create mode 100644 test/properties/cpp03/can_prefer_not_preferable_member_require.cpp create mode 100644 test/properties/cpp03/can_prefer_not_preferable_static.cpp create mode 100644 test/properties/cpp03/can_prefer_not_preferable_unsupported.cpp create mode 100644 test/properties/cpp03/can_prefer_static.cpp create mode 100644 test/properties/cpp03/can_prefer_unsupported.cpp create mode 100644 test/properties/cpp03/can_query_free.cpp create mode 100644 test/properties/cpp03/can_query_member.cpp create mode 100644 test/properties/cpp03/can_query_not_applicable_free.cpp create mode 100644 test/properties/cpp03/can_query_not_applicable_member.cpp create mode 100644 test/properties/cpp03/can_query_not_applicable_static.cpp create mode 100644 test/properties/cpp03/can_query_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp03/can_query_static.cpp create mode 100644 test/properties/cpp03/can_query_unsupported.cpp create mode 100644 test/properties/cpp03/can_require_concept_free.cpp create mode 100644 test/properties/cpp03/can_require_concept_member.cpp create mode 100644 test/properties/cpp03/can_require_concept_not_applicable_free.cpp create mode 100644 test/properties/cpp03/can_require_concept_not_applicable_member.cpp create mode 100644 test/properties/cpp03/can_require_concept_not_applicable_static.cpp create mode 100644 test/properties/cpp03/can_require_concept_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp03/can_require_concept_static.cpp create mode 100644 test/properties/cpp03/can_require_concept_unsupported.cpp create mode 100644 test/properties/cpp03/can_require_free.cpp create mode 100644 test/properties/cpp03/can_require_member.cpp create mode 100644 test/properties/cpp03/can_require_not_applicable_free.cpp create mode 100644 test/properties/cpp03/can_require_not_applicable_member.cpp create mode 100644 test/properties/cpp03/can_require_not_applicable_static.cpp create mode 100644 test/properties/cpp03/can_require_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp03/can_require_static.cpp create mode 100644 test/properties/cpp03/can_require_unsupported.cpp create mode 100644 test/properties/cpp03/prefer_free_prefer.cpp create mode 100644 test/properties/cpp03/prefer_free_require.cpp create mode 100644 test/properties/cpp03/prefer_member_prefer.cpp create mode 100644 test/properties/cpp03/prefer_member_require.cpp create mode 100644 test/properties/cpp03/prefer_static.cpp create mode 100644 test/properties/cpp03/prefer_unsupported.cpp create mode 100644 test/properties/cpp03/query_free.cpp create mode 100644 test/properties/cpp03/query_member.cpp create mode 100644 test/properties/cpp03/query_static.cpp create mode 100644 test/properties/cpp03/require_concept_free.cpp create mode 100644 test/properties/cpp03/require_concept_member.cpp create mode 100644 test/properties/cpp03/require_concept_static.cpp create mode 100644 test/properties/cpp03/require_free.cpp create mode 100644 test/properties/cpp03/require_member.cpp create mode 100644 test/properties/cpp03/require_static.cpp create mode 100644 test/properties/cpp11/Jamfile.v2 create mode 100644 test/properties/cpp11/can_prefer_free_prefer.cpp create mode 100644 test/properties/cpp11/can_prefer_free_require.cpp create mode 100644 test/properties/cpp11/can_prefer_member_prefer.cpp create mode 100644 test/properties/cpp11/can_prefer_member_require.cpp create mode 100644 test/properties/cpp11/can_prefer_not_applicable_free_prefer.cpp create mode 100644 test/properties/cpp11/can_prefer_not_applicable_free_require.cpp create mode 100644 test/properties/cpp11/can_prefer_not_applicable_member_prefer.cpp create mode 100644 test/properties/cpp11/can_prefer_not_applicable_member_require.cpp create mode 100644 test/properties/cpp11/can_prefer_not_applicable_static.cpp create mode 100644 test/properties/cpp11/can_prefer_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp11/can_prefer_not_preferable_free_prefer.cpp create mode 100644 test/properties/cpp11/can_prefer_not_preferable_free_require.cpp create mode 100644 test/properties/cpp11/can_prefer_not_preferable_member_prefer.cpp create mode 100644 test/properties/cpp11/can_prefer_not_preferable_member_require.cpp create mode 100644 test/properties/cpp11/can_prefer_not_preferable_static.cpp create mode 100644 test/properties/cpp11/can_prefer_not_preferable_unsupported.cpp create mode 100644 test/properties/cpp11/can_prefer_static.cpp create mode 100644 test/properties/cpp11/can_prefer_unsupported.cpp create mode 100644 test/properties/cpp11/can_query_free.cpp create mode 100644 test/properties/cpp11/can_query_member.cpp create mode 100644 test/properties/cpp11/can_query_not_applicable_free.cpp create mode 100644 test/properties/cpp11/can_query_not_applicable_member.cpp create mode 100644 test/properties/cpp11/can_query_not_applicable_static.cpp create mode 100644 test/properties/cpp11/can_query_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp11/can_query_static.cpp create mode 100644 test/properties/cpp11/can_query_unsupported.cpp create mode 100644 test/properties/cpp11/can_require_concept_free.cpp create mode 100644 test/properties/cpp11/can_require_concept_member.cpp create mode 100644 test/properties/cpp11/can_require_concept_not_applicable_free.cpp create mode 100644 test/properties/cpp11/can_require_concept_not_applicable_member.cpp create mode 100644 test/properties/cpp11/can_require_concept_not_applicable_static.cpp create mode 100644 test/properties/cpp11/can_require_concept_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp11/can_require_concept_static.cpp create mode 100644 test/properties/cpp11/can_require_concept_unsupported.cpp create mode 100644 test/properties/cpp11/can_require_free.cpp create mode 100644 test/properties/cpp11/can_require_member.cpp create mode 100644 test/properties/cpp11/can_require_not_applicable_free.cpp create mode 100644 test/properties/cpp11/can_require_not_applicable_member.cpp create mode 100644 test/properties/cpp11/can_require_not_applicable_static.cpp create mode 100644 test/properties/cpp11/can_require_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp11/can_require_static.cpp create mode 100644 test/properties/cpp11/can_require_unsupported.cpp create mode 100644 test/properties/cpp11/prefer_free_prefer.cpp create mode 100644 test/properties/cpp11/prefer_free_require.cpp create mode 100644 test/properties/cpp11/prefer_member_prefer.cpp create mode 100644 test/properties/cpp11/prefer_member_require.cpp create mode 100644 test/properties/cpp11/prefer_static.cpp create mode 100644 test/properties/cpp11/prefer_unsupported.cpp create mode 100644 test/properties/cpp11/query_free.cpp create mode 100644 test/properties/cpp11/query_member.cpp create mode 100644 test/properties/cpp11/query_static.cpp create mode 100644 test/properties/cpp11/require_concept_free.cpp create mode 100644 test/properties/cpp11/require_concept_member.cpp create mode 100644 test/properties/cpp11/require_concept_static.cpp create mode 100644 test/properties/cpp11/require_free.cpp create mode 100644 test/properties/cpp11/require_member.cpp create mode 100644 test/properties/cpp11/require_static.cpp create mode 100644 test/properties/cpp14/Jamfile.v2 create mode 100644 test/properties/cpp14/can_prefer_free_prefer.cpp create mode 100644 test/properties/cpp14/can_prefer_free_require.cpp create mode 100644 test/properties/cpp14/can_prefer_member_prefer.cpp create mode 100644 test/properties/cpp14/can_prefer_member_require.cpp create mode 100644 test/properties/cpp14/can_prefer_not_applicable_free_prefer.cpp create mode 100644 test/properties/cpp14/can_prefer_not_applicable_free_require.cpp create mode 100644 test/properties/cpp14/can_prefer_not_applicable_member_prefer.cpp create mode 100644 test/properties/cpp14/can_prefer_not_applicable_member_require.cpp create mode 100644 test/properties/cpp14/can_prefer_not_applicable_static.cpp create mode 100644 test/properties/cpp14/can_prefer_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp14/can_prefer_not_preferable_free_prefer.cpp create mode 100644 test/properties/cpp14/can_prefer_not_preferable_free_require.cpp create mode 100644 test/properties/cpp14/can_prefer_not_preferable_member_prefer.cpp create mode 100644 test/properties/cpp14/can_prefer_not_preferable_member_require.cpp create mode 100644 test/properties/cpp14/can_prefer_not_preferable_static.cpp create mode 100644 test/properties/cpp14/can_prefer_not_preferable_unsupported.cpp create mode 100644 test/properties/cpp14/can_prefer_static.cpp create mode 100644 test/properties/cpp14/can_prefer_unsupported.cpp create mode 100644 test/properties/cpp14/can_query_free.cpp create mode 100644 test/properties/cpp14/can_query_member.cpp create mode 100644 test/properties/cpp14/can_query_not_applicable_free.cpp create mode 100644 test/properties/cpp14/can_query_not_applicable_member.cpp create mode 100644 test/properties/cpp14/can_query_not_applicable_static.cpp create mode 100644 test/properties/cpp14/can_query_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp14/can_query_static.cpp create mode 100644 test/properties/cpp14/can_query_unsupported.cpp create mode 100644 test/properties/cpp14/can_require_concept_free.cpp create mode 100644 test/properties/cpp14/can_require_concept_member.cpp create mode 100644 test/properties/cpp14/can_require_concept_not_applicable_free.cpp create mode 100644 test/properties/cpp14/can_require_concept_not_applicable_member.cpp create mode 100644 test/properties/cpp14/can_require_concept_not_applicable_static.cpp create mode 100644 test/properties/cpp14/can_require_concept_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp14/can_require_concept_static.cpp create mode 100644 test/properties/cpp14/can_require_concept_unsupported.cpp create mode 100644 test/properties/cpp14/can_require_free.cpp create mode 100644 test/properties/cpp14/can_require_member.cpp create mode 100644 test/properties/cpp14/can_require_not_applicable_free.cpp create mode 100644 test/properties/cpp14/can_require_not_applicable_member.cpp create mode 100644 test/properties/cpp14/can_require_not_applicable_static.cpp create mode 100644 test/properties/cpp14/can_require_not_applicable_unsupported.cpp create mode 100644 test/properties/cpp14/can_require_static.cpp create mode 100644 test/properties/cpp14/can_require_unsupported.cpp create mode 100644 test/properties/cpp14/prefer_free_prefer.cpp create mode 100644 test/properties/cpp14/prefer_free_require.cpp create mode 100644 test/properties/cpp14/prefer_member_prefer.cpp create mode 100644 test/properties/cpp14/prefer_member_require.cpp create mode 100644 test/properties/cpp14/prefer_static.cpp create mode 100644 test/properties/cpp14/prefer_unsupported.cpp create mode 100644 test/properties/cpp14/query_free.cpp create mode 100644 test/properties/cpp14/query_member.cpp create mode 100644 test/properties/cpp14/query_static.cpp create mode 100644 test/properties/cpp14/require_concept_free.cpp create mode 100644 test/properties/cpp14/require_concept_member.cpp create mode 100644 test/properties/cpp14/require_concept_static.cpp create mode 100644 test/properties/cpp14/require_free.cpp create mode 100644 test/properties/cpp14/require_member.cpp create mode 100644 test/properties/cpp14/require_static.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 01b44555..6dea2c15 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -94,6 +94,7 @@ #include #include #include +#include #include #include #include @@ -109,10 +110,14 @@ #include #include #include +#include +#include #include #include #include #include +#include +#include #include #include #include diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp index 8ec20741..65714860 100644 --- a/include/boost/asio/detail/config.hpp +++ b/include/boost/asio/detail/config.hpp @@ -180,6 +180,13 @@ # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#if !defined(BOOST_ASIO_ELLIPSIS) +# if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# define BOOST_ASIO_ELLIPSIS ... +# else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# define BOOST_ASIO_ELLIPSIS +# endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(BOOST_ASIO_ELLIPSIS) // Support deleted functions on compilers known to allow it. #if !defined(BOOST_ASIO_DELETED) @@ -234,39 +241,68 @@ # define BOOST_ASIO_CONSTEXPR # endif // defined(BOOST_ASIO_HAS_CONSTEXPR) #endif // !defined(BOOST_ASIO_CONSTEXPR) +#if !defined(BOOST_ASIO_STATIC_CONSTEXPR) +# if defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ + static constexpr type assignment +# else // defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ + static const type assignment +# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR) // Support noexcept on compilers known to allow it. -#if !defined(BOOST_ASIO_NOEXCEPT) +#if !defined(BOOST_ASIO_HAS_NOEXCEPT) # if !defined(BOOST_ASIO_DISABLE_NOEXCEPT) # if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) +# if !defined(BOOST_NO_NOEXCEPT) +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# endif // !defined(BOOST_NO_NOEXCEPT) # define BOOST_ASIO_NOEXCEPT BOOST_NOEXCEPT # define BOOST_ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW +# define BOOST_ASIO_NOEXCEPT_IF(c) BOOST_NOEXCEPT_IF(c) # elif defined(__clang__) # if __has_feature(__cxx_noexcept__) -# define BOOST_ASIO_NOEXCEPT noexcept(true) -# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# define BOOST_ASIO_HAS_NOEXCEPT 1 # endif // __has_feature(__cxx_noexcept__) # elif defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) -# define BOOST_ASIO_NOEXCEPT noexcept(true) -# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# define BOOST_ASIO_HAS_NOEXCEPT 1 # endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # elif defined(BOOST_ASIO_MSVC) # if (_MSC_VER >= 1900) -# define BOOST_ASIO_NOEXCEPT noexcept(true) -# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# define BOOST_ASIO_HAS_NOEXCEPT 1 # endif // (_MSC_VER >= 1900) # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT) # if !defined(BOOST_ASIO_NOEXCEPT) -# define BOOST_ASIO_NOEXCEPT # endif // !defined(BOOST_ASIO_NOEXCEPT) # if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) -# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw() # endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +#endif // !defined(BOOST_ASIO_HAS_NOEXCEPT) +#if !defined(BOOST_ASIO_NOEXCEPT) +# if defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# else // defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT +# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) #endif // !defined(BOOST_ASIO_NOEXCEPT) +#if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +# if defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# else // defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw() +# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) +#endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +#if !defined(BOOST_ASIO_NOEXCEPT_IF) +# if defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_IF(c) noexcept(c) +# else // defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_IF(c) +# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) +#endif // !defined(BOOST_ASIO_NOEXCEPT_IF) // Support automatic type deduction on compilers known to support it. #if !defined(BOOST_ASIO_HAS_DECLTYPE) @@ -354,6 +390,67 @@ # endif // !defined(BOOST_ASIO_DISABLE_CONCEPTS) #endif // !defined(BOOST_ASIO_HAS_CONCEPTS) +// Support template variables on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# if __has_feature(__cxx_variable_templates__) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201703) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if (__GNUC__ >= 5) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 5) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +// Support SFINAEd template variables on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_feature(__cxx_variable_templates__) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201703) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +// Enable workarounds for lack of working expression SFINAE. +#if !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_MSVC) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +#endif // !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + // Standard library support for system errors. # if !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) # if defined(__clang__) diff --git a/include/boost/asio/detail/type_traits.hpp b/include/boost/asio/detail/type_traits.hpp index d5a8901c..25dc82c4 100644 --- a/include/boost/asio/detail/type_traits.hpp +++ b/include/boost/asio/detail/type_traits.hpp @@ -85,6 +85,8 @@ using boost::result_of; using boost::true_type; #endif // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) +template struct void_type { typedef void type; }; + } // namespace asio } // namespace boost diff --git a/include/boost/asio/is_applicable_property.hpp b/include/boost/asio/is_applicable_property.hpp new file mode 100644 index 00000000..1d38fa72 --- /dev/null +++ b/include/boost/asio/is_applicable_property.hpp @@ -0,0 +1,63 @@ +// +// is_applicable_property.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IS_APPLICABLE_PROPERTY_HPP +#define BOOST_ASIO_IS_APPLICABLE_PROPERTY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct is_applicable_property_trait : false_type +{ +}; + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property_trait + >::type + >::type> : true_type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +} // namespace detail + +template +struct is_applicable_property : + detail::is_applicable_property_trait +{ +}; + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +BOOST_ASIO_CONSTEXPR const bool is_applicable_property_v + = is_applicable_property::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_IS_APPLICABLE_PROPERTY_HPP diff --git a/include/boost/asio/prefer.hpp b/include/boost/asio/prefer.hpp new file mode 100644 index 00000000..d222b349 --- /dev/null +++ b/include/boost/asio/prefer.hpp @@ -0,0 +1,660 @@ +// +// prefer.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_PREFER_HPP +#define BOOST_ASIO_PREFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(GENERATING_DOCUMENTATION) + +namespace boost { +namespace asio { + +/// A customisation point that attempts to apply a property to an object. +/** + * The name prefer denotes a customisation point object. The + * expression boost::asio::prefer(E, P0, Pn...) for some subexpressions + * E and P0, and where Pn... represents N + * subexpressions (where N is 0 or more, and with types T = + * decay_t and Prop0 = decay_t) is + * expression-equivalent to: + * + * @li If is_applicable_property_v && Prop0::is_preferable is + * not a well-formed constant expression with value true, + * boost::asio::prefer(E, P0, Pn...) is ill-formed. + * + * @li Otherwise, E if N == 0 and the expression + * Prop0::template static_query_v == Prop0::value() is a + * well-formed constant expression with value true. + * + * @li Otherwise, (E).require(P0) if N == 0 and the expression + * (E).require(P0) is a valid expression. + * + * @li Otherwise, require(E, P0) if N == 0 and the expression + * require(E, P0) is a valid expression with overload resolution + * performed in a context that does not include the declaration of the + * require customization point object. + * + * @li Otherwise, (E).prefer(P0) if N == 0 and the expression + * (E).prefer(P0) is a valid expression. + * + * @li Otherwise, prefer(E, P0) if N == 0 and the expression + * prefer(E, P0) is a valid expression with overload resolution + * performed in a context that does not include the declaration of the + * prefer customization point object. + * + * @li Otherwise, E if N == 0. + * + * @li Otherwise, + * boost::asio::prefer(boost::asio::prefer(E, P0), Pn...) + * if N > 0 and the expression + * boost::asio::prefer(boost::asio::prefer(E, P0), Pn...) + * is a valid expression. + * + * @li Otherwise, boost::asio::prefer(E, P0, Pn...) is ill-formed. + */ +inline constexpr unspecified prefer = unspecified; + +/// A type trait that determines whether a @c prefer expression is well-formed. +/** + * Class template @c can_prefer is a trait that is derived from + * @c true_type if the expression boost::asio::prefer(std::declval(), + * std::declval()...) is well formed; otherwise @c false_type. + */ +template +struct can_prefer : + integral_constant +{ +}; + +/// A type trait that determines whether a @c prefer expression will not throw. +/** + * Class template @c is_nothrow_prefer is a trait that is derived from + * @c true_type if the expression boost::asio::prefer(std::declval(), + * std::declval()...) is @c noexcept; otherwise @c false_type. + */ +template +struct is_nothrow_prefer : + integral_constant +{ +}; + +/// A type trait that determines the result type of a @c prefer expression. +/** + * Class template @c prefer_result_type is a trait that determines the result + * type of the expression boost::asio::prefer(std::declval(), + * std::declval()...). + */ +template +struct prefer_result_type +{ + /// The result of the @c prefer expression. + typedef automatically_determined type; +}; + +} // namespace asio +} // namespace boost + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_prefer_fn { + +using boost::asio::decay; +using boost::asio::declval; +using boost::asio::enable_if; +using boost::asio::is_applicable_property; +using boost::asio::traits::prefer_free; +using boost::asio::traits::prefer_member; +using boost::asio::traits::require_free; +using boost::asio::traits::require_member; +using boost::asio::traits::static_require; + +void prefer(); +void require(); + +enum overload_type +{ + identity, + call_require_member, + call_require_free, + call_prefer_member, + call_prefer_free, + two_props, + n_props, + ill_formed +}; + +template +struct call_traits +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_preferable + && + static_require::is_valid + ) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + +#if defined(BOOST_ASIO_HAS_MOVE) + typedef BOOST_ASIO_MOVE_ARG(T) result_type; +#else // defined(BOOST_ASIO_HAS_MOVE) + typedef BOOST_ASIO_MOVE_ARG(typename decay::type) result_type; +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_preferable + && + !static_require::is_valid + && + require_member::is_valid + ) + >::type> : + require_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_member); +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_preferable + && + !static_require::is_valid + && + !require_member::is_valid + && + require_free::is_valid + ) + >::type> : + require_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_free); +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_preferable + && + !static_require::is_valid + && + !require_member::is_valid + && + !require_free::is_valid + && + prefer_member::is_valid + ) + >::type> : + prefer_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_member); +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_preferable + && + !static_require::is_valid + && + !require_member::is_valid + && + !require_free::is_valid + && + !prefer_member::is_valid + && + prefer_free::is_valid + ) + >::type> : + prefer_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_free); +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_preferable + && + !static_require::is_valid + && + !require_member::is_valid + && + !require_free::is_valid + && + !prefer_member::is_valid + && + !prefer_free::is_valid + ) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + +#if defined(BOOST_ASIO_HAS_MOVE) + typedef BOOST_ASIO_MOVE_ARG(T) result_type; +#else // defined(BOOST_ASIO_HAS_MOVE) + typedef BOOST_ASIO_MOVE_ARG(typename decay::type) result_type; +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +template +struct call_traits::overload != ill_formed + && + call_traits< + typename call_traits::result_type, + void(P1) + >::overload != ill_formed + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + ( + call_traits::is_noexcept + && + call_traits< + typename call_traits::result_type, + void(P1) + >::is_noexcept + )); + + typedef typename decay< + typename call_traits< + typename call_traits::result_type, + void(P1) + >::result_type + >::type result_type; +}; + +template +struct call_traits::overload != ill_formed + && + call_traits< + typename call_traits::result_type, + void(P1, PN BOOST_ASIO_ELLIPSIS) + >::overload != ill_formed + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + ( + call_traits::is_noexcept + && + call_traits< + typename call_traits::result_type, + void(P1, PN BOOST_ASIO_ELLIPSIS) + >::is_noexcept + )); + + typedef typename decay< + typename call_traits< + typename call_traits::result_type, + void(P1, PN BOOST_ASIO_ELLIPSIS) + >::result_type + >::type result_type; +}; + +struct impl +{ + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == identity, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property)) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return BOOST_ASIO_MOVE_CAST(T)(t); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_require_member, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property) p) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return BOOST_ASIO_MOVE_CAST(T)(t).require( + BOOST_ASIO_MOVE_CAST(Property)(p)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_require_free, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property) p) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return require( + BOOST_ASIO_MOVE_CAST(T)(t), + BOOST_ASIO_MOVE_CAST(Property)(p)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_prefer_member, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property) p) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return BOOST_ASIO_MOVE_CAST(T)(t).prefer( + BOOST_ASIO_MOVE_CAST(Property)(p)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_prefer_free, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property) p) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return prefer( + BOOST_ASIO_MOVE_CAST(T)(t), + BOOST_ASIO_MOVE_CAST(Property)(p)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == two_props, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(P0) p0, + BOOST_ASIO_MOVE_ARG(P1) p1) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return (*this)( + (*this)( + BOOST_ASIO_MOVE_CAST(T)(t), + BOOST_ASIO_MOVE_CAST(P0)(p0)), + BOOST_ASIO_MOVE_CAST(P1)(p1)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == n_props, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(P0) p0, + BOOST_ASIO_MOVE_ARG(P1) p1, + BOOST_ASIO_MOVE_ARG(PN) BOOST_ASIO_ELLIPSIS pn) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return (*this)( + (*this)( + BOOST_ASIO_MOVE_CAST(T)(t), + BOOST_ASIO_MOVE_CAST(P0)(p0)), + BOOST_ASIO_MOVE_CAST(P1)(p1), + BOOST_ASIO_MOVE_CAST(PN)(pn) BOOST_ASIO_ELLIPSIS); + } +}; + +template +struct static_instance +{ + static const T instance; +}; + +template +const T static_instance::instance = {}; + +} // namespace asio_prefer_fn +namespace boost { +namespace asio { +namespace { + +static BOOST_ASIO_CONSTEXPR const asio_prefer_fn::impl& + prefer = asio_prefer_fn::static_instance<>::instance; + +} // namespace + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct can_prefer : + integral_constant::overload + != asio_prefer_fn::ill_formed> +{ +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct can_prefer : + integral_constant::overload + != asio_prefer_fn::ill_formed> +{ +}; + +template +struct can_prefer : + integral_constant::overload + != asio_prefer_fn::ill_formed> +{ +}; + +template +struct can_prefer : + integral_constant::overload + != asio_prefer_fn::ill_formed> +{ +}; + +template +struct can_prefer : + false_type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool can_prefer_v + = can_prefer::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct is_nothrow_prefer : + integral_constant::is_noexcept> +{ +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct is_nothrow_prefer : + integral_constant::is_noexcept> +{ +}; + +template +struct is_nothrow_prefer : + integral_constant::is_noexcept> +{ +}; + +template +struct is_nothrow_prefer : + integral_constant::is_noexcept> +{ +}; + +template +struct is_nothrow_prefer : + false_type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool is_nothrow_prefer_v + = is_nothrow_prefer::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct prefer_result_type +{ + typedef typename asio_prefer_fn::call_traits< + T, void(Properties...)>::result_type type; +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct prefer_result_type +{ + typedef typename asio_prefer_fn::call_traits< + T, void(P0, P1, P2)>::result_type type; +}; + +template +struct prefer_result_type +{ + typedef typename asio_prefer_fn::call_traits< + T, void(P0, P1)>::result_type type; +}; + +template +struct prefer_result_type +{ + typedef typename asio_prefer_fn::call_traits< + T, void(P0)>::result_type type; +}; + +template +struct prefer_result_type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +} // namespace asio +} // namespace boost + +#endif // defined(GENERATING_DOCUMENTATION) + +#include + +#endif // BOOST_ASIO_PREFER_HPP diff --git a/include/boost/asio/query.hpp b/include/boost/asio/query.hpp new file mode 100644 index 00000000..db3f0daa --- /dev/null +++ b/include/boost/asio/query.hpp @@ -0,0 +1,300 @@ +// +// query.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_QUERY_HPP +#define BOOST_ASIO_QUERY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(GENERATING_DOCUMENTATION) + +namespace boost { +namespace asio { + +/// A customisation point that queries the value of a property. +/** + * The name query denotes a customization point object. The + * expression boost::asio::query(E, P) for some + * subexpressions E and P (with types T = + * decay_t and Prop = decay_t) is + * expression-equivalent to: + * + * @li If is_applicable_property_v is not a well-formed + * constant expression with value true, boost::asio::query(E, + * P) is ill-formed. + * + * @li Otherwise, Prop::template static_query_v if the expression + * Prop::template static_query_v is a well-formed constant + * expression. + * + * @li Otherwise, (E).query(P) if the expression + * (E).query(P) is well-formed. + * + * @li Otherwise, query(E, P) if the expression + * query(E, P) is a valid expression with overload + * resolution performed in a context that does not include the declaration + * of the query customization point object. + * + * @li Otherwise, boost::asio::query(E, P) is ill-formed. + */ +inline constexpr unspecified query = unspecified; + +/// A type trait that determines whether a @c query expression is well-formed. +/** + * Class template @c can_query is a trait that is derived from + * @c true_type if the expression boost::asio::query(std::declval(), + * std::declval()) is well formed; otherwise @c false_type. + */ +template +struct can_query : + integral_constant +{ +}; + +/// A type trait that determines whether a @c query expression will +/// not throw. +/** + * Class template @c is_nothrow_query is a trait that is derived from + * @c true_type if the expression boost::asio::query(std::declval(), + * std::declval()) is @c noexcept; otherwise @c false_type. + */ +template +struct is_nothrow_query : + integral_constant +{ +}; + +/// A type trait that determines the result type of a @c query expression. +/** + * Class template @c query_result_type is a trait that determines the + * result type of the expression boost::asio::query(std::declval(), + * std::declval()). + */ +template +struct query_result_type +{ + /// The result of the @c query expression. + typedef automatically_determined type; +}; + +} // namespace asio +} // namespace boost + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_query_fn { + +using boost::asio::decay; +using boost::asio::declval; +using boost::asio::enable_if; +using boost::asio::is_applicable_property; +using boost::asio::traits::query_free; +using boost::asio::traits::query_member; +using boost::asio::traits::static_query; + +void query(); + +enum overload_type +{ + static_value, + call_member, + call_free, + ill_formed +}; + +template +struct call_traits +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + static_query::is_valid + ) + >::type> : + static_query +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = static_value); +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + !static_query::is_valid + && + query_member::is_valid + ) + >::type> : + query_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + !static_query::is_valid + && + !query_member::is_valid + && + query_free::is_valid + ) + >::type> : + query_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); +}; + +struct impl +{ + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == static_value, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T), + BOOST_ASIO_MOVE_ARG(Property)) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return static_query< + typename decay::type, + typename decay::type + >::value(); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property) p) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return BOOST_ASIO_MOVE_CAST(T)(t).query(BOOST_ASIO_MOVE_CAST(Property)(p)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property) p) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return query(BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(Property)(p)); + } +}; + +template +struct static_instance +{ + static const T instance; +}; + +template +const T static_instance::instance = {}; + +} // namespace asio_query_fn +namespace boost { +namespace asio { +namespace { + +static BOOST_ASIO_CONSTEXPR const asio_query_fn::impl& + query = asio_query_fn::static_instance<>::instance; + +} // namespace + +template +struct can_query : + integral_constant::overload != + asio_query_fn::ill_formed> +{ +}; + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool can_query_v + = can_query::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_nothrow_query : + integral_constant::is_noexcept> +{ +}; + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool is_nothrow_query_v + = is_nothrow_query::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct query_result_type +{ + typedef typename asio_query_fn::call_traits< + T, void(Property)>::result_type type; +}; + +} // namespace asio +} // namespace boost + +#endif // defined(GENERATING_DOCUMENTATION) + +#include + +#endif // BOOST_ASIO_QUERY_HPP diff --git a/include/boost/asio/require.hpp b/include/boost/asio/require.hpp new file mode 100644 index 00000000..06920b87 --- /dev/null +++ b/include/boost/asio/require.hpp @@ -0,0 +1,528 @@ +// +// require.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_REQUIRE_HPP +#define BOOST_ASIO_REQUIRE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(GENERATING_DOCUMENTATION) + +namespace boost { +namespace asio { + +/// A customisation point that applies a concept-preserving property to an +/// object. +/** + * The name require denotes a customisation point object. The + * expression boost::asio::require(E, P0, Pn...) for some + * subexpressions E and P0, and where Pn... + * represents N subexpressions (where N is 0 or more, and with + * types T = decay_t and Prop0 = + * decay_t) is expression-equivalent to: + * + * @li If is_applicable_property_v && Prop0::is_requirable is + * not a well-formed constant expression with value true, + * boost::asio::require(E, P0, Pn...) is ill-formed. + * + * @li Otherwise, E if N == 0 and the expression + * Prop0::template static_query_v == Prop0::value() is a + * well-formed constant expression with value true. + * + * @li Otherwise, (E).require(P0) if N == 0 and the expression + * (E).require(P0) is a valid expression. + * + * @li Otherwise, require(E, P0) if N == 0 and the expression + * require(E, P0) is a valid expression with overload resolution + * performed in a context that does not include the declaration of the + * require customization point object. + * + * @li Otherwise, + * boost::asio::require(boost::asio::require(E, P0), Pn...) + * if N > 0 and the expression + * boost::asio::require(boost::asio::require(E, P0), Pn...) + * is a valid expression. + * + * @li Otherwise, boost::asio::require(E, P0, Pn...) is ill-formed. + */ +inline constexpr unspecified require = unspecified; + +/// A type trait that determines whether a @c require expression is well-formed. +/** + * Class template @c can_require is a trait that is derived from + * @c true_type if the expression boost::asio::require(std::declval(), + * std::declval()...) is well formed; otherwise @c false_type. + */ +template +struct can_require : + integral_constant +{ +}; + +/// A type trait that determines whether a @c require expression will not throw. +/** + * Class template @c is_nothrow_require is a trait that is derived from + * @c true_type if the expression boost::asio::require(std::declval(), + * std::declval()...) is @c noexcept; otherwise @c false_type. + */ +template +struct is_nothrow_require : + integral_constant +{ +}; + +/// A type trait that determines the result type of a @c require expression. +/** + * Class template @c require_result_type is a trait that determines the result + * type of the expression boost::asio::require(std::declval(), + * std::declval()...). + */ +template +struct require_result_type +{ + /// The result of the @c require expression. + typedef automatically_determined type; +}; + +} // namespace asio +} // namespace boost + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_require_fn { + +using boost::asio::decay; +using boost::asio::declval; +using boost::asio::enable_if; +using boost::asio::is_applicable_property; +using boost::asio::traits::require_free; +using boost::asio::traits::require_member; +using boost::asio::traits::static_require; + +void require(); + +enum overload_type +{ + identity, + call_member, + call_free, + two_props, + n_props, + ill_formed +}; + +template +struct call_traits +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_requirable + && + static_require::is_valid + ) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + +#if defined(BOOST_ASIO_HAS_MOVE) + typedef BOOST_ASIO_MOVE_ARG(T) result_type; +#else // defined(BOOST_ASIO_HAS_MOVE) + typedef BOOST_ASIO_MOVE_ARG(typename decay::type) result_type; +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_requirable + && + !static_require::is_valid + && + require_member::is_valid + ) + >::type> : + require_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_requirable + && + !static_require::is_valid + && + !require_member::is_valid + && + require_free::is_valid + ) + >::type> : + require_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); +}; + +template +struct call_traits::overload != ill_formed + && + call_traits< + typename call_traits::result_type, + void(P1) + >::overload != ill_formed + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + ( + call_traits::is_noexcept + && + call_traits< + typename call_traits::result_type, + void(P1) + >::is_noexcept + )); + + typedef typename decay< + typename call_traits< + typename call_traits::result_type, + void(P1) + >::result_type + >::type result_type; +}; + +template +struct call_traits::overload != ill_formed + && + call_traits< + typename call_traits::result_type, + void(P1, PN BOOST_ASIO_ELLIPSIS) + >::overload != ill_formed + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + ( + call_traits::is_noexcept + && + call_traits< + typename call_traits::result_type, + void(P1, PN BOOST_ASIO_ELLIPSIS) + >::is_noexcept + )); + + typedef typename decay< + typename call_traits< + typename call_traits::result_type, + void(P1, PN BOOST_ASIO_ELLIPSIS) + >::result_type + >::type result_type; +}; + +struct impl +{ + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == identity, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property)) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return BOOST_ASIO_MOVE_CAST(T)(t); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property) p) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return BOOST_ASIO_MOVE_CAST(T)(t).require( + BOOST_ASIO_MOVE_CAST(Property)(p)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property) p) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return require( + BOOST_ASIO_MOVE_CAST(T)(t), + BOOST_ASIO_MOVE_CAST(Property)(p)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == two_props, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(P0) p0, + BOOST_ASIO_MOVE_ARG(P1) p1) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return (*this)( + (*this)( + BOOST_ASIO_MOVE_CAST(T)(t), + BOOST_ASIO_MOVE_CAST(P0)(p0)), + BOOST_ASIO_MOVE_CAST(P1)(p1)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == n_props, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(P0) p0, + BOOST_ASIO_MOVE_ARG(P1) p1, + BOOST_ASIO_MOVE_ARG(PN) BOOST_ASIO_ELLIPSIS pn) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return (*this)( + (*this)( + BOOST_ASIO_MOVE_CAST(T)(t), + BOOST_ASIO_MOVE_CAST(P0)(p0)), + BOOST_ASIO_MOVE_CAST(P1)(p1), + BOOST_ASIO_MOVE_CAST(PN)(pn) BOOST_ASIO_ELLIPSIS); + } +}; + +template +struct static_instance +{ + static const T instance; +}; + +template +const T static_instance::instance = {}; + +} // namespace asio_require_fn +namespace boost { +namespace asio { +namespace { + +static BOOST_ASIO_CONSTEXPR const asio_require_fn::impl& + require = asio_require_fn::static_instance<>::instance; + +} // namespace + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct can_require : + integral_constant::overload + != asio_require_fn::ill_formed> +{ +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct can_require : + integral_constant::overload + != asio_require_fn::ill_formed> +{ +}; + +template +struct can_require : + integral_constant::overload + != asio_require_fn::ill_formed> +{ +}; + +template +struct can_require : + integral_constant::overload + != asio_require_fn::ill_formed> +{ +}; + +template +struct can_require : + false_type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool can_require_v + = can_require::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct is_nothrow_require : + integral_constant::is_noexcept> +{ +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct is_nothrow_require : + integral_constant::is_noexcept> +{ +}; + +template +struct is_nothrow_require : + integral_constant::is_noexcept> +{ +}; + +template +struct is_nothrow_require : + integral_constant::is_noexcept> +{ +}; + +template +struct is_nothrow_require : + false_type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool is_nothrow_require_v + = is_nothrow_require::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct require_result_type +{ + typedef typename asio_require_fn::call_traits< + T, void(Properties...)>::result_type type; +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct require_result_type +{ + typedef typename asio_require_fn::call_traits< + T, void(P0, P1, P2)>::result_type type; +}; + +template +struct require_result_type +{ + typedef typename asio_require_fn::call_traits< + T, void(P0, P1)>::result_type type; +}; + +template +struct require_result_type +{ + typedef typename asio_require_fn::call_traits< + T, void(P0)>::result_type type; +}; + +template +struct require_result_type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +} // namespace asio +} // namespace boost + +#endif // defined(GENERATING_DOCUMENTATION) + +#include + +#endif // BOOST_ASIO_REQUIRE_HPP diff --git a/include/boost/asio/require_concept.hpp b/include/boost/asio/require_concept.hpp new file mode 100644 index 00000000..d397e24f --- /dev/null +++ b/include/boost/asio/require_concept.hpp @@ -0,0 +1,314 @@ +// +// require_concept.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_REQUIRE_CONCEPT_HPP +#define BOOST_ASIO_REQUIRE_CONCEPT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(GENERATING_DOCUMENTATION) + +namespace boost { +namespace asio { + +/// A customisation point that applies a concept-enforcing property to an +/// object. +/** + * The name require_concept denotes a customization point object. The + * expression boost::asio::require_concept(E, P) for some + * subexpressions E and P (with types T = + * decay_t and Prop = decay_t) is + * expression-equivalent to: + * + * @li If is_applicable_property_v && + * Prop::is_requirable_concept is not a well-formed constant expression + * with value true, boost::asio::require_concept(E, P) is + * ill-formed. + * + * @li Otherwise, E if the expression Prop::template + * static_query_v == Prop::value() is a well-formed constant + * expression with value true. + * + * @li Otherwise, (E).require_concept(P) if the expression + * (E).require_concept(P) is well-formed. + * + * @li Otherwise, require_concept(E, P) if the expression + * require_concept(E, P) is a valid expression with overload + * resolution performed in a context that does not include the declaration + * of the require_concept customization point object. + * + * @li Otherwise, boost::asio::require_concept(E, P) is ill-formed. + */ +inline constexpr unspecified require_concept = unspecified; + +/// A type trait that determines whether a @c require_concept expression is +/// well-formed. +/** + * Class template @c can_require_concept is a trait that is derived from + * @c true_type if the expression + * boost::asio::require_concept(std::declval(), + * std::declval()) is well formed; otherwise @c false_type. + */ +template +struct can_require_concept : + integral_constant +{ +}; + +/// A type trait that determines whether a @c require_concept expression will +/// not throw. +/** + * Class template @c is_nothrow_require_concept is a trait that is derived from + * @c true_type if the expression + * boost::asio::require_concept(std::declval(), + * std::declval()) is @c noexcept; otherwise @c false_type. + */ +template +struct is_nothrow_require_concept : + integral_constant +{ +}; + +/// A type trait that determines the result type of a @c require_concept +/// expression. +/** + * Class template @c require_concept_result_type is a trait that determines the + * result type of the expression + * boost::asio::require_concept(std::declval(), + * std::declval()). + */ +template +struct require_concept_result_type +{ + /// The result of the @c require_concept expression. + typedef automatically_determined type; +}; + +} // namespace asio +} // namespace boost + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_require_concept_fn { + +using boost::asio::decay; +using boost::asio::declval; +using boost::asio::enable_if; +using boost::asio::is_applicable_property; +using boost::asio::traits::require_concept_free; +using boost::asio::traits::require_concept_member; +using boost::asio::traits::static_require_concept; + +void require_concept(); + +enum overload_type +{ + identity, + call_member, + call_free, + ill_formed +}; + +template +struct call_traits +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_requirable_concept + && + static_require_concept::is_valid + ) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef BOOST_ASIO_MOVE_ARG(T) result_type; +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_requirable_concept + && + !static_require_concept::is_valid + && + require_concept_member::is_valid + ) + >::type> : + require_concept_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); +}; + +template +struct call_traits::type, + typename decay::type + >::value + && + decay::type::is_requirable_concept + && + !static_require_concept::is_valid + && + !require_concept_member::is_valid + && + require_concept_free::is_valid + ) + >::type> : + require_concept_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); +}; + +struct impl +{ + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == identity, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property)) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return BOOST_ASIO_MOVE_CAST(T)(t); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property) p) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return BOOST_ASIO_MOVE_CAST(T)(t).require_concept( + BOOST_ASIO_MOVE_CAST(Property)(p)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(Property) p) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return require_concept( + BOOST_ASIO_MOVE_CAST(T)(t), + BOOST_ASIO_MOVE_CAST(Property)(p)); + } +}; + +template +struct static_instance +{ + static const T instance; +}; + +template +const T static_instance::instance = {}; + +} // namespace asio_require_concept_fn +namespace boost { +namespace asio { +namespace { + +static BOOST_ASIO_CONSTEXPR const asio_require_concept_fn::impl& + require_concept = asio_require_concept_fn::static_instance<>::instance; + +} // namespace + +template +struct can_require_concept : + integral_constant::overload != + asio_require_concept_fn::ill_formed> +{ +}; + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool can_require_concept_v + = can_require_concept::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_nothrow_require_concept : + integral_constant::is_noexcept> +{ +}; + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool is_nothrow_require_concept_v + = is_nothrow_require_concept::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct require_concept_result_type +{ + typedef typename asio_require_concept_fn::call_traits< + T, void(Property)>::result_type type; +}; + +} // namespace asio +} // namespace boost + +#endif // defined(GENERATING_DOCUMENTATION) + +#include + +#endif // BOOST_ASIO_REQUIRE_CONCEPT_HPP diff --git a/include/boost/asio/traits/prefer_free.hpp b/include/boost/asio/traits/prefer_free.hpp new file mode 100644 index 00000000..5f8b73de --- /dev/null +++ b/include/boost/asio/traits/prefer_free.hpp @@ -0,0 +1,110 @@ +// +// traits/prefer_free.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_PREFER_FREE_HPP +#define BOOST_ASIO_TRAITS_PREFER_FREE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct prefer_free_default; + +template +struct prefer_free; + +} // namespace traits +namespace detail { + +struct no_prefer_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template +struct prefer_free_trait : no_prefer_free +{ +}; + +template +struct prefer_free_trait(), declval())) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + prefer(declval(), declval())); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( + prefer(declval(), declval()))); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template +struct prefer_free_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_prefer_free, + traits::prefer_free< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace detail +namespace traits { + +template +struct prefer_free_default : + detail::prefer_free_trait +{ +}; + +template +struct prefer_free : + prefer_free_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_PREFER_FREE_HPP diff --git a/include/boost/asio/traits/prefer_member.hpp b/include/boost/asio/traits/prefer_member.hpp new file mode 100644 index 00000000..4c71c439 --- /dev/null +++ b/include/boost/asio/traits/prefer_member.hpp @@ -0,0 +1,110 @@ +// +// traits/prefer_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_PREFER_MEMBER_HPP +#define BOOST_ASIO_TRAITS_PREFER_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct prefer_member_default; + +template +struct prefer_member; + +} // namespace traits +namespace detail { + +struct no_prefer_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template +struct prefer_member_trait : no_prefer_member +{ +}; + +template +struct prefer_member_trait().prefer(declval())) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + declval().prefer(declval())); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( + declval().prefer(declval()))); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template +struct prefer_member_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_prefer_member, + traits::prefer_member< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template +struct prefer_member_default : + detail::prefer_member_trait +{ +}; + +template +struct prefer_member : + prefer_member_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_PREFER_MEMBER_HPP diff --git a/include/boost/asio/traits/query_free.hpp b/include/boost/asio/traits/query_free.hpp new file mode 100644 index 00000000..335b12e5 --- /dev/null +++ b/include/boost/asio/traits/query_free.hpp @@ -0,0 +1,110 @@ +// +// traits/query_free.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_QUERY_FREE_HPP +#define BOOST_ASIO_TRAITS_QUERY_FREE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct query_free_default; + +template +struct query_free; + +} // namespace traits +namespace detail { + +struct no_query_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_trait : no_query_free +{ +}; + +template +struct query_free_trait(), declval())) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + query(declval(), declval())); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( + query(declval(), declval()))); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_query_free, + traits::query_free< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace detail +namespace traits { + +template +struct query_free_default : + detail::query_free_trait +{ +}; + +template +struct query_free : + query_free_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_QUERY_FREE_HPP diff --git a/include/boost/asio/traits/query_member.hpp b/include/boost/asio/traits/query_member.hpp new file mode 100644 index 00000000..aa175934 --- /dev/null +++ b/include/boost/asio/traits/query_member.hpp @@ -0,0 +1,110 @@ +// +// traits/query_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_QUERY_MEMBER_HPP +#define BOOST_ASIO_TRAITS_QUERY_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct query_member_default; + +template +struct query_member; + +} // namespace traits +namespace detail { + +struct no_query_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member_trait : no_query_member +{ +}; + +template +struct query_member_trait().query(declval())) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + declval().query(declval())); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( + declval().query(declval()))); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_query_member, + traits::query_member< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template +struct query_member_default : + detail::query_member_trait +{ +}; + +template +struct query_member : + query_member_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_QUERY_MEMBER_HPP diff --git a/include/boost/asio/traits/require_concept_free.hpp b/include/boost/asio/traits/require_concept_free.hpp new file mode 100644 index 00000000..4b27af43 --- /dev/null +++ b/include/boost/asio/traits/require_concept_free.hpp @@ -0,0 +1,110 @@ +// +// traits/require_concept_free.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP +#define BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_concept_free_default; + +template +struct require_concept_free; + +} // namespace traits +namespace detail { + +struct no_require_concept_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT) + +template +struct require_concept_free_trait : no_require_concept_free +{ +}; + +template +struct require_concept_free_trait(), declval())) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + require_concept(declval(), declval())); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( + require_concept(declval(), declval()))); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT) + +template +struct require_concept_free_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_require_concept_free, + traits::require_concept_free< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT) + +} // namespace detail +namespace traits { + +template +struct require_concept_free_default : + detail::require_concept_free_trait +{ +}; + +template +struct require_concept_free : + require_concept_free_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP diff --git a/include/boost/asio/traits/require_concept_member.hpp b/include/boost/asio/traits/require_concept_member.hpp new file mode 100644 index 00000000..c8084a84 --- /dev/null +++ b/include/boost/asio/traits/require_concept_member.hpp @@ -0,0 +1,110 @@ +// +// traits/require_concept_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP +#define BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_concept_member_default; + +template +struct require_concept_member; + +} // namespace traits +namespace detail { + +struct no_require_concept_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) + +template +struct require_concept_member_trait : no_require_concept_member +{ +}; + +template +struct require_concept_member_trait().require_concept(declval())) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + declval().require_concept(declval())); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( + declval().require_concept(declval()))); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) + +template +struct require_concept_member_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_require_concept_member, + traits::require_concept_member< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template +struct require_concept_member_default : + detail::require_concept_member_trait +{ +}; + +template +struct require_concept_member : + require_concept_member_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP diff --git a/include/boost/asio/traits/require_free.hpp b/include/boost/asio/traits/require_free.hpp new file mode 100644 index 00000000..10a8ed07 --- /dev/null +++ b/include/boost/asio/traits/require_free.hpp @@ -0,0 +1,110 @@ +// +// traits/require_free.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_REQUIRE_FREE_HPP +#define BOOST_ASIO_TRAITS_REQUIRE_FREE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_free_default; + +template +struct require_free; + +} // namespace traits +namespace detail { + +struct no_require_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template +struct require_free_trait : no_require_free +{ +}; + +template +struct require_free_trait(), declval())) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + require(declval(), declval())); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( + require(declval(), declval()))); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template +struct require_free_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_require_free, + traits::require_free< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +} // namespace detail +namespace traits { + +template +struct require_free_default : + detail::require_free_trait +{ +}; + +template +struct require_free : + require_free_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_REQUIRE_FREE_HPP diff --git a/include/boost/asio/traits/require_member.hpp b/include/boost/asio/traits/require_member.hpp new file mode 100644 index 00000000..63bb7564 --- /dev/null +++ b/include/boost/asio/traits/require_member.hpp @@ -0,0 +1,110 @@ +// +// traits/require_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_REQUIRE_MEMBER_HPP +#define BOOST_ASIO_TRAITS_REQUIRE_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_member_default; + +template +struct require_member; + +} // namespace traits +namespace detail { + +struct no_require_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member_trait : no_require_member +{ +}; + +template +struct require_member_trait().require(declval())) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + declval().require(declval())); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( + declval().require(declval()))); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_require_member, + traits::require_member< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template +struct require_member_default : + detail::require_member_trait +{ +}; + +template +struct require_member : + require_member_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_REQUIRE_MEMBER_HPP diff --git a/include/boost/asio/traits/static_query.hpp b/include/boost/asio/traits/static_query.hpp new file mode 100644 index 00000000..2cc8fbe6 --- /dev/null +++ b/include/boost/asio/traits/static_query.hpp @@ -0,0 +1,110 @@ +// +// traits/static_query.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_STATIC_QUERY_HPP +#define BOOST_ASIO_TRAITS_STATIC_QUERY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_CONSTEXPR) \ + && defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_CONSTEXPR) + // && defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct static_query_default; + +template +struct static_query; + +} // namespace traits +namespace detail { + +struct no_static_query +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +template +struct static_query_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_static_query, + traits::static_query< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + +template +struct static_query_trait::type::template static_query_v) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + decay::type::template static_query_v); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + noexcept(decay::type::template static_query_v)); + + static BOOST_ASIO_CONSTEXPR result_type value() noexcept(is_noexcept) + { + return decay::type::template static_query_v; + } +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + +} // namespace detail +namespace traits { + +template +struct static_query_default : detail::static_query_trait +{ +}; + +template +struct static_query : static_query_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_STATIC_QUERY_HPP diff --git a/include/boost/asio/traits/static_require.hpp b/include/boost/asio/traits/static_require.hpp new file mode 100644 index 00000000..c0bdbbea --- /dev/null +++ b/include/boost/asio/traits/static_require.hpp @@ -0,0 +1,125 @@ +// +// traits/static_require.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_STATIC_REQUIRE_HPP +#define BOOST_ASIO_TRAITS_STATIC_REQUIRE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct static_require_default; + +template +struct static_require; + +} // namespace traits +namespace detail { + +struct no_static_require +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); +}; + +template +struct static_require_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_static_require, + traits::static_require< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +#if defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +template +struct static_require_trait::type::value() == traits::static_query::value() + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); +}; + +#else // defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +false_type static_require_test(...); + +template +true_type static_require_test(T*, Property*, + typename enable_if< + Property::value() == traits::static_query::value() + >::type* = 0); + +template +struct has_static_require +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, value = + decltype((static_require_test)( + static_cast(0), static_cast(0)))::value); +}; + +template +struct static_require_trait::type, + typename decay::type>::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); +}; + +#endif // defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace detail +namespace traits { + +template +struct static_require_default : detail::static_require_trait +{ +}; + +template +struct static_require : static_require_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_STATIC_REQUIRE_HPP diff --git a/include/boost/asio/traits/static_require_concept.hpp b/include/boost/asio/traits/static_require_concept.hpp new file mode 100644 index 00000000..97ee2285 --- /dev/null +++ b/include/boost/asio/traits/static_require_concept.hpp @@ -0,0 +1,125 @@ +// +// traits/static_require_concept.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP +#define BOOST_ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct static_require_concept_default; + +template +struct static_require_concept; + +} // namespace traits +namespace detail { + +struct no_static_require_concept +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); +}; + +template +struct static_require_concept_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_static_require_concept, + traits::static_require_concept< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT) + +#if defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +template +struct static_require_concept_trait::type::value() == traits::static_query::value() + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); +}; + +#else // defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +false_type static_require_concept_test(...); + +template +true_type static_require_concept_test(T*, Property*, + typename enable_if< + Property::value() == traits::static_query::value() + >::type* = 0); + +template +struct has_static_require_concept +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, value = + decltype((static_require_concept_test)( + static_cast(0), static_cast(0)))::value); +}; + +template +struct static_require_concept_trait::type>::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); +}; + +#endif // defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT) + +} // namespace detail +namespace traits { + +template +struct static_require_concept_default : + detail::static_require_concept_trait +{ +}; + +template +struct static_require_concept : static_require_concept_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP diff --git a/test/properties/cpp03/Jamfile.v2 b/test/properties/cpp03/Jamfile.v2 new file mode 100644 index 00000000..f2264864 --- /dev/null +++ b/test/properties/cpp03/Jamfile.v2 @@ -0,0 +1,101 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import feature ; + +lib socket ; # SOLARIS, QNXNTO +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + /boost/date_time//boost_date_time + /boost/system//boost_system + /boost/chrono//boost_chrono + /boost/regex//boost_regex + BOOST_ALL_NO_LIB=1 + multi + linux:_XOPEN_SOURCE=600 + linux:_GNU_SOURCE=1 + solaris:_XOPEN_SOURCE=500 + solaris:__EXTENSIONS__ + solaris:socket + solaris:nsl + windows:_WIN32_WINNT=0x0501 + windows,cw:ws2_32 + windows,cw:mswsock + windows,gcc:ws2_32 + windows,gcc:mswsock + windows,gcc-cygwin:__USE_W32_SOCKETS + hpux,gcc:_XOPEN_SOURCE_EXTENDED + hpux:ipv6 + qnxnto:socket + haiku:network + ; + +test-suite "asio" : + [ run can_prefer_free_prefer.cpp ] + [ run can_prefer_free_require.cpp ] + [ run can_prefer_member_prefer.cpp ] + [ run can_prefer_member_require.cpp ] + [ run can_prefer_not_applicable_free_prefer.cpp ] + [ run can_prefer_not_applicable_free_require.cpp ] + [ run can_prefer_not_applicable_member_prefer.cpp ] + [ run can_prefer_not_applicable_member_require.cpp ] + [ run can_prefer_not_applicable_static.cpp ] + [ run can_prefer_not_applicable_unsupported.cpp ] + [ run can_prefer_not_preferable_free_prefer.cpp ] + [ run can_prefer_not_preferable_free_require.cpp ] + [ run can_prefer_not_preferable_member_prefer.cpp ] + [ run can_prefer_not_preferable_member_require.cpp ] + [ run can_prefer_not_preferable_static.cpp ] + [ run can_prefer_not_preferable_unsupported.cpp ] + [ run can_prefer_static.cpp ] + [ run can_prefer_unsupported.cpp ] + [ run can_query_free.cpp ] + [ run can_query_member.cpp ] + [ run can_query_not_applicable_free.cpp ] + [ run can_query_not_applicable_member.cpp ] + [ run can_query_not_applicable_static.cpp ] + [ run can_query_not_applicable_unsupported.cpp ] + [ run can_query_static.cpp ] + [ run can_query_unsupported.cpp ] + [ run can_require_concept_free.cpp ] + [ run can_require_concept_member.cpp ] + [ run can_require_concept_not_applicable_free.cpp ] + [ run can_require_concept_not_applicable_member.cpp ] + [ run can_require_concept_not_applicable_static.cpp ] + [ run can_require_concept_not_applicable_unsupported.cpp ] + [ run can_require_concept_static.cpp ] + [ run can_require_concept_unsupported.cpp ] + [ run can_require_free.cpp ] + [ run can_require_member.cpp ] + [ run can_require_not_applicable_free.cpp ] + [ run can_require_not_applicable_member.cpp ] + [ run can_require_not_applicable_static.cpp ] + [ run can_require_not_applicable_unsupported.cpp ] + [ run can_require_static.cpp ] + [ run can_require_unsupported.cpp ] + [ run prefer_free_prefer.cpp ] + [ run prefer_free_require.cpp ] + [ run prefer_member_prefer.cpp ] + [ run prefer_member_require.cpp ] + [ run prefer_static.cpp ] + [ run prefer_unsupported.cpp ] + [ run query_free.cpp ] + [ run query_member.cpp ] + [ run query_static.cpp ] + [ run require_concept_free.cpp ] + [ run require_concept_member.cpp ] + [ run require_concept_static.cpp ] + [ run require_free.cpp ] + [ run require_member.cpp ] + [ run require_static.cpp ] + ; diff --git a/test/properties/cpp03/can_prefer_free_prefer.cpp b/test/properties/cpp03/can_prefer_free_prefer.cpp new file mode 100644 index 00000000..b2f3de93 --- /dev/null +++ b/test/properties/cpp03/can_prefer_free_prefer.cpp @@ -0,0 +1,61 @@ +// +// cpp03/can_prefer_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + friend object prefer(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct prefer_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_prefer, prop<2> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((boost::asio::can_prefer, prop<2> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_free_require.cpp b/test/properties/cpp03/can_prefer_free_require.cpp new file mode 100644 index 00000000..0afc5b7c --- /dev/null +++ b/test/properties/cpp03/can_prefer_free_require.cpp @@ -0,0 +1,61 @@ +// +// cpp03/can_prefer_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + friend object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_prefer, prop<2> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((boost::asio::can_prefer, prop<2> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_member_prefer.cpp b/test/properties/cpp03/can_prefer_member_prefer.cpp new file mode 100644 index 00000000..86ea5844 --- /dev/null +++ b/test/properties/cpp03/can_prefer_member_prefer.cpp @@ -0,0 +1,61 @@ +// +// cpp03/can_prefer_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + object prefer(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct prefer_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_prefer, prop<2> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((boost::asio::can_prefer, prop<2> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_member_require.cpp b/test/properties/cpp03/can_prefer_member_require.cpp new file mode 100644 index 00000000..ebc4230d --- /dev/null +++ b/test/properties/cpp03/can_prefer_member_require.cpp @@ -0,0 +1,61 @@ +// +// cpp03/can_prefer_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_prefer, prop<2> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((boost::asio::can_prefer, prop<2> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_applicable_free_prefer.cpp b/test/properties/cpp03/can_prefer_not_applicable_free_prefer.cpp new file mode 100644 index 00000000..9a090f68 --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_applicable_free_prefer.cpp @@ -0,0 +1,54 @@ +// +// cpp03/can_prefer_not_applicable_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + friend object prefer(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct prefer_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_applicable_free_require.cpp b/test/properties/cpp03/can_prefer_not_applicable_free_require.cpp new file mode 100644 index 00000000..d996a685 --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_applicable_free_require.cpp @@ -0,0 +1,54 @@ +// +// cpp03/can_prefer_not_applicable_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + friend object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_applicable_member_prefer.cpp b/test/properties/cpp03/can_prefer_not_applicable_member_prefer.cpp new file mode 100644 index 00000000..9ec96df2 --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_applicable_member_prefer.cpp @@ -0,0 +1,54 @@ +// +// cpp03/can_prefer_not_applicable_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + object prefer(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct prefer_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_applicable_member_require.cpp b/test/properties/cpp03/can_prefer_not_applicable_member_require.cpp new file mode 100644 index 00000000..ab83a293 --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_applicable_member_require.cpp @@ -0,0 +1,54 @@ +// +// cpp03/can_prefer_not_applicable_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_applicable_static.cpp b/test/properties/cpp03/can_prefer_not_applicable_static.cpp new file mode 100644 index 00000000..039bf6bb --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_applicable_static.cpp @@ -0,0 +1,47 @@ +// +// cpp03/can_prefer_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct static_require, prop > +{ + static const bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<1> >::value)); + assert((!boost::asio::can_prefer, prop<1>, prop<1> >::value)); + assert((!boost::asio::can_prefer, prop<1>, prop<1>, prop<1> >::value)); + assert((!boost::asio::can_prefer, prop<1> >::value)); + assert((!boost::asio::can_prefer, prop<1>, prop<1> >::value)); + assert((!boost::asio::can_prefer, prop<1>, prop<1>, prop<1> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_applicable_unsupported.cpp b/test/properties/cpp03/can_prefer_not_applicable_unsupported.cpp new file mode 100644 index 00000000..8e8b4697 --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_applicable_unsupported.cpp @@ -0,0 +1,33 @@ +// +// cpp03/can_prefer_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ +}; + +int main() +{ + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_preferable_free_prefer.cpp b/test/properties/cpp03/can_prefer_not_preferable_free_prefer.cpp new file mode 100644 index 00000000..87a1df41 --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_preferable_free_prefer.cpp @@ -0,0 +1,61 @@ +// +// cpp03/can_prefer_not_preferable_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = false; +}; + +template +struct object +{ + template + friend object prefer(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct prefer_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_preferable_free_require.cpp b/test/properties/cpp03/can_prefer_not_preferable_free_require.cpp new file mode 100644 index 00000000..722ff36e --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_preferable_free_require.cpp @@ -0,0 +1,61 @@ +// +// cpp03/can_prefer_not_preferable_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = false; +}; + +template +struct object +{ + template + friend object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_preferable_member_prefer.cpp b/test/properties/cpp03/can_prefer_not_preferable_member_prefer.cpp new file mode 100644 index 00000000..a3fd6378 --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_preferable_member_prefer.cpp @@ -0,0 +1,61 @@ +// +// cpp03/can_prefer_not_preferable_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = false; +}; + +template +struct object +{ + template + object prefer(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct prefer_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_preferable_member_require.cpp b/test/properties/cpp03/can_prefer_not_preferable_member_require.cpp new file mode 100644 index 00000000..660baead --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_preferable_member_require.cpp @@ -0,0 +1,61 @@ +// +// cpp03/can_prefer_not_preferable_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = false; +}; + +template +struct object +{ + template + object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_preferable_static.cpp b/test/properties/cpp03/can_prefer_not_preferable_static.cpp new file mode 100644 index 00000000..fa886e4b --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_preferable_static.cpp @@ -0,0 +1,54 @@ +// +// cpp03/can_prefer_not_preferable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = false; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct static_require, prop > +{ + static const bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<1> >::value)); + assert((!boost::asio::can_prefer, prop<1>, prop<1> >::value)); + assert((!boost::asio::can_prefer, prop<1>, prop<1>, prop<1> >::value)); + assert((!boost::asio::can_prefer, prop<1> >::value)); + assert((!boost::asio::can_prefer, prop<1>, prop<1> >::value)); + assert((!boost::asio::can_prefer, prop<1>, prop<1>, prop<1> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_not_preferable_unsupported.cpp b/test/properties/cpp03/can_prefer_not_preferable_unsupported.cpp new file mode 100644 index 00000000..a1dd3cdb --- /dev/null +++ b/test/properties/cpp03/can_prefer_not_preferable_unsupported.cpp @@ -0,0 +1,45 @@ +// +// cpp03/can_prefer_not_preferable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = false; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_prefer, prop<2> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_static.cpp b/test/properties/cpp03/can_prefer_static.cpp new file mode 100644 index 00000000..da0b5f8e --- /dev/null +++ b/test/properties/cpp03/can_prefer_static.cpp @@ -0,0 +1,54 @@ +// +// cpp03/can_prefer_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct static_require, prop > +{ + static const bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_prefer, prop<1> >::value)); + assert((boost::asio::can_prefer, prop<1>, prop<1> >::value)); + assert((boost::asio::can_prefer, prop<1>, prop<1>, prop<1> >::value)); + assert((boost::asio::can_prefer, prop<1> >::value)); + assert((boost::asio::can_prefer, prop<1>, prop<1> >::value)); + assert((boost::asio::can_prefer, prop<1>, prop<1>, prop<1> >::value)); +} diff --git a/test/properties/cpp03/can_prefer_unsupported.cpp b/test/properties/cpp03/can_prefer_unsupported.cpp new file mode 100644 index 00000000..3006539a --- /dev/null +++ b/test/properties/cpp03/can_prefer_unsupported.cpp @@ -0,0 +1,45 @@ +// +// cpp03/can_prefer_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_prefer, prop<2> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); + assert((boost::asio::can_prefer, prop<2> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3> >::value)); + assert((boost::asio::can_prefer, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_query_free.cpp b/test/properties/cpp03/can_query_free.cpp new file mode 100644 index 00000000..d641d8f7 --- /dev/null +++ b/test/properties/cpp03/can_query_free.cpp @@ -0,0 +1,50 @@ +// +// cpp03/can_query_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + friend int query(const object&, prop) { return 123; } +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static const bool value = true; +}; + +namespace traits { + +template<> +struct query_free +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef int result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_query::value)); + assert((boost::asio::can_query::value)); +} diff --git a/test/properties/cpp03/can_query_member.cpp b/test/properties/cpp03/can_query_member.cpp new file mode 100644 index 00000000..3dd67cc9 --- /dev/null +++ b/test/properties/cpp03/can_query_member.cpp @@ -0,0 +1,50 @@ +// +// cpp03/can_query_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + int query(prop) const { return 123; } +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static const bool value = true; +}; + +namespace traits { + +template<> +struct query_member +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef int result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_query::value)); + assert((boost::asio::can_query::value)); +} diff --git a/test/properties/cpp03/can_query_not_applicable_free.cpp b/test/properties/cpp03/can_query_not_applicable_free.cpp new file mode 100644 index 00000000..7a9f68c8 --- /dev/null +++ b/test/properties/cpp03/can_query_not_applicable_free.cpp @@ -0,0 +1,43 @@ +// +// cpp03/can_query_not_applicable_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + friend int query(const object&, prop) { return 123; } +}; + +namespace boost { +namespace asio { +namespace traits { + +template<> +struct query_free +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef int result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_query::value)); + assert((!boost::asio::can_query::value)); +} diff --git a/test/properties/cpp03/can_query_not_applicable_member.cpp b/test/properties/cpp03/can_query_not_applicable_member.cpp new file mode 100644 index 00000000..ab70b5f0 --- /dev/null +++ b/test/properties/cpp03/can_query_not_applicable_member.cpp @@ -0,0 +1,43 @@ +// +// cpp03/can_query_not_applicable_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + int query(prop) const { return 123; } +}; + +namespace boost { +namespace asio { +namespace traits { + +template<> +struct query_member +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef int result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_query::value)); + assert((!boost::asio::can_query::value)); +} diff --git a/test/properties/cpp03/can_query_not_applicable_static.cpp b/test/properties/cpp03/can_query_not_applicable_static.cpp new file mode 100644 index 00000000..2d6f0a3f --- /dev/null +++ b/test/properties/cpp03/can_query_not_applicable_static.cpp @@ -0,0 +1,43 @@ +// +// cpp03/can_query_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +namespace boost { +namespace asio { +namespace traits { + +template<> +struct static_query +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef int result_type; + static int value() { return 123; } +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_query::value)); + assert((!boost::asio::can_query::value)); +} diff --git a/test/properties/cpp03/can_query_not_applicable_unsupported.cpp b/test/properties/cpp03/can_query_not_applicable_unsupported.cpp new file mode 100644 index 00000000..61158b43 --- /dev/null +++ b/test/properties/cpp03/can_query_not_applicable_unsupported.cpp @@ -0,0 +1,26 @@ +// +// cpp03/can_query_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +int main() +{ + assert((!boost::asio::can_query::value)); + assert((!boost::asio::can_query::value)); +} diff --git a/test/properties/cpp03/can_query_static.cpp b/test/properties/cpp03/can_query_static.cpp new file mode 100644 index 00000000..a48384ef --- /dev/null +++ b/test/properties/cpp03/can_query_static.cpp @@ -0,0 +1,50 @@ +// +// cpp03/can_query_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static const bool value = true; +}; + +namespace traits { + +template<> +struct static_query +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef int result_type; + static int value() { return 123; } +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_query::value)); + assert((boost::asio::can_query::value)); +} diff --git a/test/properties/cpp03/can_query_unsupported.cpp b/test/properties/cpp03/can_query_unsupported.cpp new file mode 100644 index 00000000..1d3c9257 --- /dev/null +++ b/test/properties/cpp03/can_query_unsupported.cpp @@ -0,0 +1,38 @@ +// +// cpp03/can_query_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +namespace boost { +namespace asio { + +template <> +struct is_applicable_property +{ + static const bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_query::value)); + assert((!boost::asio::can_query::value)); +} diff --git a/test/properties/cpp03/can_require_concept_free.cpp b/test/properties/cpp03/can_require_concept_free.cpp new file mode 100644 index 00000000..b356a371 --- /dev/null +++ b/test/properties/cpp03/can_require_concept_free.cpp @@ -0,0 +1,57 @@ +// +// cpp03/can_require_concept_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable_concept = true; +}; + +template +struct object +{ + template + friend object require_concept(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_concept_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_require_concept, prop<2> >::value)); + assert((boost::asio::can_require_concept, prop<2> >::value)); +} diff --git a/test/properties/cpp03/can_require_concept_member.cpp b/test/properties/cpp03/can_require_concept_member.cpp new file mode 100644 index 00000000..8f54ce2e --- /dev/null +++ b/test/properties/cpp03/can_require_concept_member.cpp @@ -0,0 +1,57 @@ +// +// cpp03/can_require_concept_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable_concept = true; +}; + +template +struct object +{ + template + object require_concept(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_concept_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_require_concept, prop<2> >::value)); + assert((boost::asio::can_require_concept, prop<2> >::value)); +} diff --git a/test/properties/cpp03/can_require_concept_not_applicable_free.cpp b/test/properties/cpp03/can_require_concept_not_applicable_free.cpp new file mode 100644 index 00000000..fdd76b9e --- /dev/null +++ b/test/properties/cpp03/can_require_concept_not_applicable_free.cpp @@ -0,0 +1,50 @@ +// +// cpp03/can_require_concept_not_applicable_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable_concept = true; +}; + +template +struct object +{ + template + friend object require_concept(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_concept_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_require_concept, prop<2> >::value)); + assert((!boost::asio::can_require_concept, prop<2> >::value)); +} diff --git a/test/properties/cpp03/can_require_concept_not_applicable_member.cpp b/test/properties/cpp03/can_require_concept_not_applicable_member.cpp new file mode 100644 index 00000000..caf3c6e2 --- /dev/null +++ b/test/properties/cpp03/can_require_concept_not_applicable_member.cpp @@ -0,0 +1,50 @@ +// +// cpp03/can_require_concept_not_applicable_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable_concept = true; +}; + +template +struct object +{ + template + object require_concept(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_concept_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_require_concept, prop<2> >::value)); + assert((!boost::asio::can_require_concept, prop<2> >::value)); +} diff --git a/test/properties/cpp03/can_require_concept_not_applicable_static.cpp b/test/properties/cpp03/can_require_concept_not_applicable_static.cpp new file mode 100644 index 00000000..5340a633 --- /dev/null +++ b/test/properties/cpp03/can_require_concept_not_applicable_static.cpp @@ -0,0 +1,43 @@ +// +// cpp03/can_require_concept_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable_concept = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct static_require_concept, prop > +{ + static const bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_require_concept, prop<2> >::value)); + assert((!boost::asio::can_require_concept, prop<2> >::value)); +} diff --git a/test/properties/cpp03/can_require_concept_not_applicable_unsupported.cpp b/test/properties/cpp03/can_require_concept_not_applicable_unsupported.cpp new file mode 100644 index 00000000..f318d38c --- /dev/null +++ b/test/properties/cpp03/can_require_concept_not_applicable_unsupported.cpp @@ -0,0 +1,28 @@ +// +// cpp03/can_require_concept_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +int main() +{ + assert((!boost::asio::can_require_concept, prop<2> >::value)); + assert((!boost::asio::can_require_concept, prop<2> >::value)); +} diff --git a/test/properties/cpp03/can_require_concept_static.cpp b/test/properties/cpp03/can_require_concept_static.cpp new file mode 100644 index 00000000..f34187bd --- /dev/null +++ b/test/properties/cpp03/can_require_concept_static.cpp @@ -0,0 +1,50 @@ +// +// cpp03/can_require_concept_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable_concept = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct static_require_concept, prop > +{ + static const bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_require_concept, prop<1> >::value)); + assert((boost::asio::can_require_concept, prop<1> >::value)); +} diff --git a/test/properties/cpp03/can_require_concept_unsupported.cpp b/test/properties/cpp03/can_require_concept_unsupported.cpp new file mode 100644 index 00000000..1b176189 --- /dev/null +++ b/test/properties/cpp03/can_require_concept_unsupported.cpp @@ -0,0 +1,40 @@ +// +// cpp03/can_require_concept_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_require_concept, prop<2> >::value)); + assert((!boost::asio::can_require_concept, prop<2> >::value)); +} diff --git a/test/properties/cpp03/can_require_free.cpp b/test/properties/cpp03/can_require_free.cpp new file mode 100644 index 00000000..a438ccf8 --- /dev/null +++ b/test/properties/cpp03/can_require_free.cpp @@ -0,0 +1,61 @@ +// +// cpp03/can_require_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable = true; +}; + +template +struct object +{ + template + friend object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_require, prop<2> >::value)); + assert((boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); + assert((boost::asio::can_require, prop<2> >::value)); + assert((boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_require_member.cpp b/test/properties/cpp03/can_require_member.cpp new file mode 100644 index 00000000..64ebe40c --- /dev/null +++ b/test/properties/cpp03/can_require_member.cpp @@ -0,0 +1,61 @@ +// +// cpp03/can_require_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable = true; +}; + +template +struct object +{ + template + object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_require, prop<2> >::value)); + assert((boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); + assert((boost::asio::can_require, prop<2> >::value)); + assert((boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_require_not_applicable_free.cpp b/test/properties/cpp03/can_require_not_applicable_free.cpp new file mode 100644 index 00000000..0ad767c9 --- /dev/null +++ b/test/properties/cpp03/can_require_not_applicable_free.cpp @@ -0,0 +1,54 @@ +// +// cpp03/can_require_not_applicable_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable = true; +}; + +template +struct object +{ + template + friend object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_require, prop<2> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_require, prop<2> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_require_not_applicable_member.cpp b/test/properties/cpp03/can_require_not_applicable_member.cpp new file mode 100644 index 00000000..6d697e42 --- /dev/null +++ b/test/properties/cpp03/can_require_not_applicable_member.cpp @@ -0,0 +1,54 @@ +// +// cpp03/can_require_not_applicable_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable = true; +}; + +template +struct object +{ + template + object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_require, prop<2> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_require, prop<2> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_require_not_applicable_static.cpp b/test/properties/cpp03/can_require_not_applicable_static.cpp new file mode 100644 index 00000000..13db94d8 --- /dev/null +++ b/test/properties/cpp03/can_require_not_applicable_static.cpp @@ -0,0 +1,47 @@ +// +// cpp03/can_require_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct static_require, prop > +{ + static const bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_require, prop<1> >::value)); + assert((!boost::asio::can_require, prop<1>, prop<1> >::value)); + assert((!boost::asio::can_require, prop<1>, prop<1>, prop<1> >::value)); + assert((!boost::asio::can_require, prop<1> >::value)); + assert((!boost::asio::can_require, prop<1>, prop<1> >::value)); + assert((!boost::asio::can_require, prop<1>, prop<1>, prop<1> >::value)); +} diff --git a/test/properties/cpp03/can_require_not_applicable_unsupported.cpp b/test/properties/cpp03/can_require_not_applicable_unsupported.cpp new file mode 100644 index 00000000..d5de3fc3 --- /dev/null +++ b/test/properties/cpp03/can_require_not_applicable_unsupported.cpp @@ -0,0 +1,32 @@ +// +// cpp03/can_require_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +int main() +{ + assert((!boost::asio::can_require, prop<2> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_require, prop<2> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/can_require_static.cpp b/test/properties/cpp03/can_require_static.cpp new file mode 100644 index 00000000..fb7d1781 --- /dev/null +++ b/test/properties/cpp03/can_require_static.cpp @@ -0,0 +1,54 @@ +// +// cpp03/can_require_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct static_require, prop > +{ + static const bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + assert((boost::asio::can_require, prop<1> >::value)); + assert((boost::asio::can_require, prop<1>, prop<1> >::value)); + assert((boost::asio::can_require, prop<1>, prop<1>, prop<1> >::value)); + assert((boost::asio::can_require, prop<1> >::value)); + assert((boost::asio::can_require, prop<1>, prop<1> >::value)); + assert((boost::asio::can_require, prop<1>, prop<1>, prop<1> >::value)); +} diff --git a/test/properties/cpp03/can_require_unsupported.cpp b/test/properties/cpp03/can_require_unsupported.cpp new file mode 100644 index 00000000..38f6a977 --- /dev/null +++ b/test/properties/cpp03/can_require_unsupported.cpp @@ -0,0 +1,44 @@ +// +// cpp03/can_require_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + assert((!boost::asio::can_require, prop<2> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); + assert((!boost::asio::can_require, prop<2> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3> >::value)); + assert((!boost::asio::can_require, prop<2>, prop<3>, prop<4> >::value)); +} diff --git a/test/properties/cpp03/prefer_free_prefer.cpp b/test/properties/cpp03/prefer_free_prefer.cpp new file mode 100644 index 00000000..0e189792 --- /dev/null +++ b/test/properties/cpp03/prefer_free_prefer.cpp @@ -0,0 +1,70 @@ +// +// cpp03/prefer_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + friend object prefer(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct prefer_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; +} diff --git a/test/properties/cpp03/prefer_free_require.cpp b/test/properties/cpp03/prefer_free_require.cpp new file mode 100644 index 00000000..0c0a4d48 --- /dev/null +++ b/test/properties/cpp03/prefer_free_require.cpp @@ -0,0 +1,70 @@ +// +// cpp03/prefer_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + friend object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; +} diff --git a/test/properties/cpp03/prefer_member_prefer.cpp b/test/properties/cpp03/prefer_member_prefer.cpp new file mode 100644 index 00000000..4892bcd6 --- /dev/null +++ b/test/properties/cpp03/prefer_member_prefer.cpp @@ -0,0 +1,70 @@ +// +// cpp03/prefer_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + object prefer(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct prefer_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; +} diff --git a/test/properties/cpp03/prefer_member_require.cpp b/test/properties/cpp03/prefer_member_require.cpp new file mode 100644 index 00000000..7d623ce8 --- /dev/null +++ b/test/properties/cpp03/prefer_member_require.cpp @@ -0,0 +1,70 @@ +// +// cpp03/prefer_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ + template + object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; +} diff --git a/test/properties/cpp03/prefer_static.cpp b/test/properties/cpp03/prefer_static.cpp new file mode 100644 index 00000000..a3cb6ef2 --- /dev/null +++ b/test/properties/cpp03/prefer_static.cpp @@ -0,0 +1,63 @@ +// +// cpp03/prefer_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct static_require, prop > +{ + static const bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<1> o2 = boost::asio::prefer(o1, prop<1>()); + object<1> o3 = boost::asio::prefer(o1, prop<1>(), prop<1>()); + object<1> o4 = boost::asio::prefer(o1, prop<1>(), prop<1>(), prop<1>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<1> o6 = boost::asio::prefer(o5, prop<1>()); + object<1> o7 = boost::asio::prefer(o5, prop<1>(), prop<1>()); + object<1> o8 = boost::asio::prefer(o5, prop<1>(), prop<1>(), prop<1>()); + (void)o6; + (void)o7; + (void)o8; +} diff --git a/test/properties/cpp03/prefer_unsupported.cpp b/test/properties/cpp03/prefer_unsupported.cpp new file mode 100644 index 00000000..2c72e7a9 --- /dev/null +++ b/test/properties/cpp03/prefer_unsupported.cpp @@ -0,0 +1,48 @@ +// +// cpp03/prefer_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_preferable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + const object<1>& o2 = boost::asio::prefer(o1, prop<1>()); + assert(&o1 == &o2); + (void)o2; + + const object<1> o3 = {}; + const object<1>& o4 = boost::asio::prefer(o3, prop<1>()); + assert(&o3 == &o4); + (void)o4; +} diff --git a/test/properties/cpp03/query_free.cpp b/test/properties/cpp03/query_free.cpp new file mode 100644 index 00000000..03eb8fe5 --- /dev/null +++ b/test/properties/cpp03/query_free.cpp @@ -0,0 +1,57 @@ +// +// cpp03/query_free.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + friend int query(const object&, prop) { return 123; } +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static const bool value = true; +}; + +namespace traits { + +template<> +struct query_free +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef int result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object o1 = {}; + int result1 = boost::asio::query(o1, prop()); + assert(result1 == 123); + (void)result1; + + const object o2 = {}; + int result2 = boost::asio::query(o2, prop()); + assert(result2 == 123); + (void)result2; +} diff --git a/test/properties/cpp03/query_member.cpp b/test/properties/cpp03/query_member.cpp new file mode 100644 index 00000000..3d9e1d18 --- /dev/null +++ b/test/properties/cpp03/query_member.cpp @@ -0,0 +1,57 @@ +// +// cpp03/query_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + int query(prop) const { return 123; } +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static const bool value = true; +}; + +namespace traits { + +template<> +struct query_member +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef int result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object o1 = {}; + int result1 = boost::asio::query(o1, prop()); + assert(result1 == 123); + (void)result1; + + const object o2 = {}; + int result2 = boost::asio::query(o2, prop()); + assert(result2 == 123); + (void)result2; +} diff --git a/test/properties/cpp03/query_static.cpp b/test/properties/cpp03/query_static.cpp new file mode 100644 index 00000000..d431098f --- /dev/null +++ b/test/properties/cpp03/query_static.cpp @@ -0,0 +1,57 @@ +// +// cpp03/query_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static const bool value = true; +}; + +namespace traits { + +template<> +struct static_query +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef int result_type; + static int value() { return 123; } +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object o1 = {}; + int result1 = boost::asio::query(o1, prop()); + assert(result1 == 123); + (void)result1; + + const object o2 = {}; + int result2 = boost::asio::query(o2, prop()); + assert(result2 == 123); + (void)result2; +} diff --git a/test/properties/cpp03/require_concept_free.cpp b/test/properties/cpp03/require_concept_free.cpp new file mode 100644 index 00000000..3d75e71e --- /dev/null +++ b/test/properties/cpp03/require_concept_free.cpp @@ -0,0 +1,62 @@ +// +// cpp03/require_concept_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable_concept = true; +}; + +template +struct object +{ + template + friend object require_concept(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_concept_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require_concept(o1, prop<2>()); + (void)o2; + + const object<1> o3 = {}; + object<2> o4 = boost::asio::require_concept(o3, prop<2>()); + (void)o4; +} diff --git a/test/properties/cpp03/require_concept_member.cpp b/test/properties/cpp03/require_concept_member.cpp new file mode 100644 index 00000000..e9bc424b --- /dev/null +++ b/test/properties/cpp03/require_concept_member.cpp @@ -0,0 +1,62 @@ +// +// cpp03/require_concept_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable_concept = true; +}; + +template +struct object +{ + template + object require_concept(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_concept_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require_concept(o1, prop<2>()); + (void)o2; + + const object<1> o3 = {}; + object<2> o4 = boost::asio::require_concept(o3, prop<2>()); + (void)o4; +} diff --git a/test/properties/cpp03/require_concept_static.cpp b/test/properties/cpp03/require_concept_static.cpp new file mode 100644 index 00000000..b80f6724 --- /dev/null +++ b/test/properties/cpp03/require_concept_static.cpp @@ -0,0 +1,57 @@ +// +// cpp03/require_concept_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable_concept = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct static_require_concept, prop > +{ + static const bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + const object<1>& o2 = boost::asio::require_concept(o1, prop<1>()); + assert(&o1 == &o2); + (void)o2; + + const object<1> o3 = {}; + const object<1>& o4 = boost::asio::require_concept(o3, prop<1>()); + assert(&o3 == &o4); + (void)o4; +} diff --git a/test/properties/cpp03/require_free.cpp b/test/properties/cpp03/require_free.cpp new file mode 100644 index 00000000..f97130a5 --- /dev/null +++ b/test/properties/cpp03/require_free.cpp @@ -0,0 +1,70 @@ +// +// cpp03/require_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable = true; +}; + +template +struct object +{ + template + friend object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_free, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require(o1, prop<2>()); + object<3> o3 = boost::asio::require(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::require(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::require(o5, prop<2>()); + object<3> o7 = boost::asio::require(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::require(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; +} diff --git a/test/properties/cpp03/require_member.cpp b/test/properties/cpp03/require_member.cpp new file mode 100644 index 00000000..fb27d27f --- /dev/null +++ b/test/properties/cpp03/require_member.cpp @@ -0,0 +1,70 @@ +// +// cpp03/require_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable = true; +}; + +template +struct object +{ + template + object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct require_member, prop > +{ + static const bool is_valid = true; + static const bool is_noexcept = true; + typedef object result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require(o1, prop<2>()); + object<3> o3 = boost::asio::require(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::require(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::require(o5, prop<2>()); + object<3> o7 = boost::asio::require(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::require(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; +} diff --git a/test/properties/cpp03/require_static.cpp b/test/properties/cpp03/require_static.cpp new file mode 100644 index 00000000..54bd896b --- /dev/null +++ b/test/properties/cpp03/require_static.cpp @@ -0,0 +1,63 @@ +// +// cpp03/require_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static const bool is_requirable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static const bool value = true; +}; + +namespace traits { + +template +struct static_require, prop > +{ + static const bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<1> o2 = boost::asio::require(o1, prop<1>()); + object<1> o3 = boost::asio::require(o1, prop<1>(), prop<1>()); + object<1> o4 = boost::asio::require(o1, prop<1>(), prop<1>(), prop<1>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<1> o6 = boost::asio::require(o5, prop<1>()); + object<1> o7 = boost::asio::require(o5, prop<1>(), prop<1>()); + object<1> o8 = boost::asio::require(o5, prop<1>(), prop<1>(), prop<1>()); + (void)o6; + (void)o7; + (void)o8; +} diff --git a/test/properties/cpp11/Jamfile.v2 b/test/properties/cpp11/Jamfile.v2 new file mode 100644 index 00000000..f2264864 --- /dev/null +++ b/test/properties/cpp11/Jamfile.v2 @@ -0,0 +1,101 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import feature ; + +lib socket ; # SOLARIS, QNXNTO +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + /boost/date_time//boost_date_time + /boost/system//boost_system + /boost/chrono//boost_chrono + /boost/regex//boost_regex + BOOST_ALL_NO_LIB=1 + multi + linux:_XOPEN_SOURCE=600 + linux:_GNU_SOURCE=1 + solaris:_XOPEN_SOURCE=500 + solaris:__EXTENSIONS__ + solaris:socket + solaris:nsl + windows:_WIN32_WINNT=0x0501 + windows,cw:ws2_32 + windows,cw:mswsock + windows,gcc:ws2_32 + windows,gcc:mswsock + windows,gcc-cygwin:__USE_W32_SOCKETS + hpux,gcc:_XOPEN_SOURCE_EXTENDED + hpux:ipv6 + qnxnto:socket + haiku:network + ; + +test-suite "asio" : + [ run can_prefer_free_prefer.cpp ] + [ run can_prefer_free_require.cpp ] + [ run can_prefer_member_prefer.cpp ] + [ run can_prefer_member_require.cpp ] + [ run can_prefer_not_applicable_free_prefer.cpp ] + [ run can_prefer_not_applicable_free_require.cpp ] + [ run can_prefer_not_applicable_member_prefer.cpp ] + [ run can_prefer_not_applicable_member_require.cpp ] + [ run can_prefer_not_applicable_static.cpp ] + [ run can_prefer_not_applicable_unsupported.cpp ] + [ run can_prefer_not_preferable_free_prefer.cpp ] + [ run can_prefer_not_preferable_free_require.cpp ] + [ run can_prefer_not_preferable_member_prefer.cpp ] + [ run can_prefer_not_preferable_member_require.cpp ] + [ run can_prefer_not_preferable_static.cpp ] + [ run can_prefer_not_preferable_unsupported.cpp ] + [ run can_prefer_static.cpp ] + [ run can_prefer_unsupported.cpp ] + [ run can_query_free.cpp ] + [ run can_query_member.cpp ] + [ run can_query_not_applicable_free.cpp ] + [ run can_query_not_applicable_member.cpp ] + [ run can_query_not_applicable_static.cpp ] + [ run can_query_not_applicable_unsupported.cpp ] + [ run can_query_static.cpp ] + [ run can_query_unsupported.cpp ] + [ run can_require_concept_free.cpp ] + [ run can_require_concept_member.cpp ] + [ run can_require_concept_not_applicable_free.cpp ] + [ run can_require_concept_not_applicable_member.cpp ] + [ run can_require_concept_not_applicable_static.cpp ] + [ run can_require_concept_not_applicable_unsupported.cpp ] + [ run can_require_concept_static.cpp ] + [ run can_require_concept_unsupported.cpp ] + [ run can_require_free.cpp ] + [ run can_require_member.cpp ] + [ run can_require_not_applicable_free.cpp ] + [ run can_require_not_applicable_member.cpp ] + [ run can_require_not_applicable_static.cpp ] + [ run can_require_not_applicable_unsupported.cpp ] + [ run can_require_static.cpp ] + [ run can_require_unsupported.cpp ] + [ run prefer_free_prefer.cpp ] + [ run prefer_free_require.cpp ] + [ run prefer_member_prefer.cpp ] + [ run prefer_member_require.cpp ] + [ run prefer_static.cpp ] + [ run prefer_unsupported.cpp ] + [ run query_free.cpp ] + [ run query_member.cpp ] + [ run query_static.cpp ] + [ run require_concept_free.cpp ] + [ run require_concept_member.cpp ] + [ run require_concept_static.cpp ] + [ run require_free.cpp ] + [ run require_member.cpp ] + [ run require_static.cpp ] + ; diff --git a/test/properties/cpp11/can_prefer_free_prefer.cpp b/test/properties/cpp11/can_prefer_free_prefer.cpp new file mode 100644 index 00000000..25b5faa5 --- /dev/null +++ b/test/properties/cpp11/can_prefer_free_prefer.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_prefer_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object prefer(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_free_require.cpp b/test/properties/cpp11/can_prefer_free_require.cpp new file mode 100644 index 00000000..beceeaa0 --- /dev/null +++ b/test/properties/cpp11/can_prefer_free_require.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_prefer_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_member_prefer.cpp b/test/properties/cpp11/can_prefer_member_prefer.cpp new file mode 100644 index 00000000..577da655 --- /dev/null +++ b/test/properties/cpp11/can_prefer_member_prefer.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_prefer_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object prefer(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_member_require.cpp b/test/properties/cpp11/can_prefer_member_require.cpp new file mode 100644 index 00000000..94b70b09 --- /dev/null +++ b/test/properties/cpp11/can_prefer_member_require.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_prefer_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_applicable_free_prefer.cpp b/test/properties/cpp11/can_prefer_not_applicable_free_prefer.cpp new file mode 100644 index 00000000..85a70b1f --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_applicable_free_prefer.cpp @@ -0,0 +1,38 @@ +// +// cpp11/can_prefer_not_applicable_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object prefer(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_applicable_free_require.cpp b/test/properties/cpp11/can_prefer_not_applicable_free_require.cpp new file mode 100644 index 00000000..91e39100 --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_applicable_free_require.cpp @@ -0,0 +1,38 @@ +// +// cpp11/can_prefer_not_applicable_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_applicable_member_prefer.cpp b/test/properties/cpp11/can_prefer_not_applicable_member_prefer.cpp new file mode 100644 index 00000000..2f7b4c80 --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_applicable_member_prefer.cpp @@ -0,0 +1,38 @@ +// +// cpp11/can_prefer_not_applicable_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object prefer(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_applicable_member_require.cpp b/test/properties/cpp11/can_prefer_not_applicable_member_require.cpp new file mode 100644 index 00000000..a002e5d0 --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_applicable_member_require.cpp @@ -0,0 +1,38 @@ +// +// cpp11/can_prefer_not_applicable_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_applicable_static.cpp b/test/properties/cpp11/can_prefer_not_applicable_static.cpp new file mode 100644 index 00000000..a79303d7 --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_applicable_static.cpp @@ -0,0 +1,47 @@ +// +// cpp11/can_prefer_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct static_require, prop > +{ + static constexpr bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<1>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<1>, prop<1>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<1>, prop<1>, prop<1>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<1>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<1>, prop<1>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<1>, prop<1>, prop<1>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_applicable_unsupported.cpp b/test/properties/cpp11/can_prefer_not_applicable_unsupported.cpp new file mode 100644 index 00000000..01737c1d --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_applicable_unsupported.cpp @@ -0,0 +1,33 @@ +// +// cpp11/can_prefer_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_preferable_free_prefer.cpp b/test/properties/cpp11/can_prefer_not_preferable_free_prefer.cpp new file mode 100644 index 00000000..e763b246 --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_preferable_free_prefer.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_prefer_not_preferable_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = false; +}; + +template +struct object +{ + template + friend constexpr object prefer(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_preferable_free_require.cpp b/test/properties/cpp11/can_prefer_not_preferable_free_require.cpp new file mode 100644 index 00000000..e019cf6c --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_preferable_free_require.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_prefer_not_preferable_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = false; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_preferable_member_prefer.cpp b/test/properties/cpp11/can_prefer_not_preferable_member_prefer.cpp new file mode 100644 index 00000000..14e3c248 --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_preferable_member_prefer.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_prefer_not_preferable_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = false; +}; + +template +struct object +{ + template + constexpr object prefer(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_preferable_member_require.cpp b/test/properties/cpp11/can_prefer_not_preferable_member_require.cpp new file mode 100644 index 00000000..a0c1af1a --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_preferable_member_require.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_prefer_not_preferable_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = false; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_preferable_static.cpp b/test/properties/cpp11/can_prefer_not_preferable_static.cpp new file mode 100644 index 00000000..4291e8e3 --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_preferable_static.cpp @@ -0,0 +1,45 @@ +// +// cpp11/can_prefer_not_preferable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = false; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<1>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<1>, prop<1>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<1>, prop<1>, prop<1>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<1>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<1>, prop<1>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<1>, prop<1>, prop<1>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_not_preferable_unsupported.cpp b/test/properties/cpp11/can_prefer_not_preferable_unsupported.cpp new file mode 100644 index 00000000..45e624ab --- /dev/null +++ b/test/properties/cpp11/can_prefer_not_preferable_unsupported.cpp @@ -0,0 +1,45 @@ +// +// cpp11/can_prefer_not_preferable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = false; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_static.cpp b/test/properties/cpp11/can_prefer_static.cpp new file mode 100644 index 00000000..a17290f7 --- /dev/null +++ b/test/properties/cpp11/can_prefer_static.cpp @@ -0,0 +1,54 @@ +// +// cpp11/can_prefer_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +namespace traits { + +template +struct static_require, prop > +{ + static constexpr bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_prefer, prop<1>>::value, ""); + static_assert(boost::asio::can_prefer, prop<1>, prop<1>>::value, ""); + static_assert(boost::asio::can_prefer, prop<1>, prop<1>, prop<1>>::value, ""); + static_assert(boost::asio::can_prefer, prop<1>>::value, ""); + static_assert(boost::asio::can_prefer, prop<1>, prop<1>>::value, ""); + static_assert(boost::asio::can_prefer, prop<1>, prop<1>, prop<1>>::value, ""); +} diff --git a/test/properties/cpp11/can_prefer_unsupported.cpp b/test/properties/cpp11/can_prefer_unsupported.cpp new file mode 100644 index 00000000..7fb97323 --- /dev/null +++ b/test/properties/cpp11/can_prefer_unsupported.cpp @@ -0,0 +1,45 @@ +// +// cpp11/can_prefer_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_prefer, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_query_free.cpp b/test/properties/cpp11/can_query_free.cpp new file mode 100644 index 00000000..5e9411f6 --- /dev/null +++ b/test/properties/cpp11/can_query_free.cpp @@ -0,0 +1,39 @@ +// +// cpp11/can_query_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + friend constexpr int query(const object&, prop) { return 123; } +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_query::value, ""); + static_assert(boost::asio::can_query::value, ""); +} diff --git a/test/properties/cpp11/can_query_member.cpp b/test/properties/cpp11/can_query_member.cpp new file mode 100644 index 00000000..9f530361 --- /dev/null +++ b/test/properties/cpp11/can_query_member.cpp @@ -0,0 +1,39 @@ +// +// cpp11/can_query_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + constexpr int query(prop) const { return 123; } +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_query::value, ""); + static_assert(boost::asio::can_query::value, ""); +} diff --git a/test/properties/cpp11/can_query_not_applicable_free.cpp b/test/properties/cpp11/can_query_not_applicable_free.cpp new file mode 100644 index 00000000..2641bc7e --- /dev/null +++ b/test/properties/cpp11/can_query_not_applicable_free.cpp @@ -0,0 +1,27 @@ +// +// cpp11/can_query_not_applicable_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + friend constexpr int query(const object&, prop) { return 123; } +}; + +int main() +{ + static_assert(!boost::asio::can_query::value, ""); + static_assert(!boost::asio::can_query::value, ""); +} diff --git a/test/properties/cpp11/can_query_not_applicable_member.cpp b/test/properties/cpp11/can_query_not_applicable_member.cpp new file mode 100644 index 00000000..d68af6dd --- /dev/null +++ b/test/properties/cpp11/can_query_not_applicable_member.cpp @@ -0,0 +1,27 @@ +// +// cpp11/can_query_not_applicable_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + constexpr int query(prop) const { return 123; } +}; + +int main() +{ + static_assert(!boost::asio::can_query::value, ""); + static_assert(!boost::asio::can_query::value, ""); +} diff --git a/test/properties/cpp11/can_query_not_applicable_static.cpp b/test/properties/cpp11/can_query_not_applicable_static.cpp new file mode 100644 index 00000000..a45e0672 --- /dev/null +++ b/test/properties/cpp11/can_query_not_applicable_static.cpp @@ -0,0 +1,43 @@ +// +// cpp11/can_query_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +namespace boost { +namespace asio { +namespace traits { + +template<> +struct static_query +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef int result_type; + static constexpr int value() { return 123; } +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_query::value, ""); + static_assert(!boost::asio::can_query::value, ""); +} diff --git a/test/properties/cpp11/can_query_not_applicable_unsupported.cpp b/test/properties/cpp11/can_query_not_applicable_unsupported.cpp new file mode 100644 index 00000000..cc81dd4b --- /dev/null +++ b/test/properties/cpp11/can_query_not_applicable_unsupported.cpp @@ -0,0 +1,26 @@ +// +// cpp11/can_query_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_query::value, ""); + static_assert(!boost::asio::can_query::value, ""); +} diff --git a/test/properties/cpp11/can_query_static.cpp b/test/properties/cpp11/can_query_static.cpp new file mode 100644 index 00000000..9502b5a7 --- /dev/null +++ b/test/properties/cpp11/can_query_static.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_query_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static constexpr bool value = true; +}; + +namespace traits { + +template<> +struct static_query +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef int result_type; + static constexpr int value() { return 123; } +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_query::value, ""); + static_assert(boost::asio::can_query::value, ""); +} diff --git a/test/properties/cpp11/can_query_unsupported.cpp b/test/properties/cpp11/can_query_unsupported.cpp new file mode 100644 index 00000000..29332cc0 --- /dev/null +++ b/test/properties/cpp11/can_query_unsupported.cpp @@ -0,0 +1,38 @@ +// +// cpp11/can_query_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_query::value, ""); + static_assert(!boost::asio::can_query::value, ""); +} diff --git a/test/properties/cpp11/can_require_concept_free.cpp b/test/properties/cpp11/can_require_concept_free.cpp new file mode 100644 index 00000000..8b79219d --- /dev/null +++ b/test/properties/cpp11/can_require_concept_free.cpp @@ -0,0 +1,46 @@ +// +// cpp11/can_require_concept_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + friend constexpr object require_concept(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_require_concept, prop<2>>::value, ""); + static_assert(boost::asio::can_require_concept, prop<2>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_concept_member.cpp b/test/properties/cpp11/can_require_concept_member.cpp new file mode 100644 index 00000000..2838ae2a --- /dev/null +++ b/test/properties/cpp11/can_require_concept_member.cpp @@ -0,0 +1,46 @@ +// +// cpp11/can_require_concept_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + constexpr object require_concept(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_require_concept, prop<2>>::value, ""); + static_assert(boost::asio::can_require_concept, prop<2>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_concept_not_applicable_free.cpp b/test/properties/cpp11/can_require_concept_not_applicable_free.cpp new file mode 100644 index 00000000..672d55c1 --- /dev/null +++ b/test/properties/cpp11/can_require_concept_not_applicable_free.cpp @@ -0,0 +1,34 @@ +// +// cpp11/can_require_concept_not_applicable_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + friend constexpr object require_concept(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_concept_not_applicable_member.cpp b/test/properties/cpp11/can_require_concept_not_applicable_member.cpp new file mode 100644 index 00000000..1c80cd9d --- /dev/null +++ b/test/properties/cpp11/can_require_concept_not_applicable_member.cpp @@ -0,0 +1,34 @@ +// +// cpp11/can_require_concept_not_applicable_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + constexpr object require_concept(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_concept_not_applicable_static.cpp b/test/properties/cpp11/can_require_concept_not_applicable_static.cpp new file mode 100644 index 00000000..9d07aabc --- /dev/null +++ b/test/properties/cpp11/can_require_concept_not_applicable_static.cpp @@ -0,0 +1,43 @@ +// +// cpp11/can_require_concept_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct static_require_concept, prop > +{ + static constexpr bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_concept_not_applicable_unsupported.cpp b/test/properties/cpp11/can_require_concept_not_applicable_unsupported.cpp new file mode 100644 index 00000000..ff730995 --- /dev/null +++ b/test/properties/cpp11/can_require_concept_not_applicable_unsupported.cpp @@ -0,0 +1,28 @@ +// +// cpp11/can_require_concept_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_concept_static.cpp b/test/properties/cpp11/can_require_concept_static.cpp new file mode 100644 index 00000000..42843c57 --- /dev/null +++ b/test/properties/cpp11/can_require_concept_static.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_require_concept_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +namespace traits { + +template +struct static_require_concept, prop > +{ + static constexpr bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_require_concept, prop<1>>::value, ""); + static_assert(boost::asio::can_require_concept, prop<1>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_concept_unsupported.cpp b/test/properties/cpp11/can_require_concept_unsupported.cpp new file mode 100644 index 00000000..edbca6dd --- /dev/null +++ b/test/properties/cpp11/can_require_concept_unsupported.cpp @@ -0,0 +1,40 @@ +// +// cpp11/can_require_concept_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_free.cpp b/test/properties/cpp11/can_require_free.cpp new file mode 100644 index 00000000..2c15a469 --- /dev/null +++ b/test/properties/cpp11/can_require_free.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_require_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_require, prop<2>>::value, ""); + static_assert(boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(boost::asio::can_require, prop<2>>::value, ""); + static_assert(boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_member.cpp b/test/properties/cpp11/can_require_member.cpp new file mode 100644 index 00000000..efa531a3 --- /dev/null +++ b/test/properties/cpp11/can_require_member.cpp @@ -0,0 +1,50 @@ +// +// cpp11/can_require_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_require, prop<2>>::value, ""); + static_assert(boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(boost::asio::can_require, prop<2>>::value, ""); + static_assert(boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_not_applicable_free.cpp b/test/properties/cpp11/can_require_not_applicable_free.cpp new file mode 100644 index 00000000..9dee75bf --- /dev/null +++ b/test/properties/cpp11/can_require_not_applicable_free.cpp @@ -0,0 +1,38 @@ +// +// cpp11/can_require_not_applicable_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_require, prop<2>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_not_applicable_member.cpp b/test/properties/cpp11/can_require_not_applicable_member.cpp new file mode 100644 index 00000000..e05e561f --- /dev/null +++ b/test/properties/cpp11/can_require_not_applicable_member.cpp @@ -0,0 +1,38 @@ +// +// cpp11/can_require_not_applicable_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_require, prop<2>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_not_applicable_static.cpp b/test/properties/cpp11/can_require_not_applicable_static.cpp new file mode 100644 index 00000000..3c4dc8df --- /dev/null +++ b/test/properties/cpp11/can_require_not_applicable_static.cpp @@ -0,0 +1,47 @@ +// +// cpp11/can_require_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { +namespace traits { + +template +struct static_require, prop > +{ + static constexpr bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_require, prop<1>>::value, ""); + static_assert(!boost::asio::can_require, prop<1>, prop<1>>::value, ""); + static_assert(!boost::asio::can_require, prop<1>, prop<1>, prop<1>>::value, ""); + static_assert(!boost::asio::can_require, prop<1>>::value, ""); + static_assert(!boost::asio::can_require, prop<1>, prop<1>>::value, ""); + static_assert(!boost::asio::can_require, prop<1>, prop<1>, prop<1>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_not_applicable_unsupported.cpp b/test/properties/cpp11/can_require_not_applicable_unsupported.cpp new file mode 100644 index 00000000..36fc9f11 --- /dev/null +++ b/test/properties/cpp11/can_require_not_applicable_unsupported.cpp @@ -0,0 +1,32 @@ +// +// cpp11/can_require_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_require, prop<2>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_static.cpp b/test/properties/cpp11/can_require_static.cpp new file mode 100644 index 00000000..646eeb15 --- /dev/null +++ b/test/properties/cpp11/can_require_static.cpp @@ -0,0 +1,54 @@ +// +// cpp11/can_require_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +namespace traits { + +template +struct static_require, prop > +{ + static constexpr bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(boost::asio::can_require, prop<1>>::value, ""); + static_assert(boost::asio::can_require, prop<1>, prop<1>>::value, ""); + static_assert(boost::asio::can_require, prop<1>, prop<1>, prop<1>>::value, ""); + static_assert(boost::asio::can_require, prop<1>>::value, ""); + static_assert(boost::asio::can_require, prop<1>, prop<1>>::value, ""); + static_assert(boost::asio::can_require, prop<1>, prop<1>, prop<1>>::value, ""); +} diff --git a/test/properties/cpp11/can_require_unsupported.cpp b/test/properties/cpp11/can_require_unsupported.cpp new file mode 100644 index 00000000..e0b4613d --- /dev/null +++ b/test/properties/cpp11/can_require_unsupported.cpp @@ -0,0 +1,44 @@ +// +// cpp11/can_require_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_require, prop<2>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>>::value, ""); + static_assert(!boost::asio::can_require, prop<2>, prop<3>, prop<4>>::value, ""); +} diff --git a/test/properties/cpp11/prefer_free_prefer.cpp b/test/properties/cpp11/prefer_free_prefer.cpp new file mode 100644 index 00000000..1378a7ce --- /dev/null +++ b/test/properties/cpp11/prefer_free_prefer.cpp @@ -0,0 +1,66 @@ +// +// cpp11/prefer_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object prefer(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::prefer(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp11/prefer_free_require.cpp b/test/properties/cpp11/prefer_free_require.cpp new file mode 100644 index 00000000..a6d2e0f2 --- /dev/null +++ b/test/properties/cpp11/prefer_free_require.cpp @@ -0,0 +1,66 @@ +// +// cpp11/prefer_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::prefer(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp11/prefer_member_prefer.cpp b/test/properties/cpp11/prefer_member_prefer.cpp new file mode 100644 index 00000000..11c566e4 --- /dev/null +++ b/test/properties/cpp11/prefer_member_prefer.cpp @@ -0,0 +1,66 @@ +// +// cpp11/prefer_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object prefer(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::prefer(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp11/prefer_member_require.cpp b/test/properties/cpp11/prefer_member_require.cpp new file mode 100644 index 00000000..f028406c --- /dev/null +++ b/test/properties/cpp11/prefer_member_require.cpp @@ -0,0 +1,66 @@ +// +// cpp11/prefer_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::prefer(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp11/prefer_static.cpp b/test/properties/cpp11/prefer_static.cpp new file mode 100644 index 00000000..6a685486 --- /dev/null +++ b/test/properties/cpp11/prefer_static.cpp @@ -0,0 +1,70 @@ +// +// cpp11/prefer_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +namespace traits { + +template +struct static_require, prop > +{ + static constexpr bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<1> o2 = boost::asio::prefer(o1, prop<1>()); + object<1> o3 = boost::asio::prefer(o1, prop<1>(), prop<1>()); + object<1> o4 = boost::asio::prefer(o1, prop<1>(), prop<1>(), prop<1>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<1> o6 = boost::asio::prefer(o5, prop<1>()); + object<1> o7 = boost::asio::prefer(o5, prop<1>(), prop<1>()); + object<1> o8 = boost::asio::prefer(o5, prop<1>(), prop<1>(), prop<1>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<1> o9 = boost::asio::prefer(object<1>(), prop<1>()); + constexpr object<1> o10 = boost::asio::prefer(object<1>(), prop<1>(), prop<1>()); + constexpr object<1> o11 = boost::asio::prefer(object<1>(), prop<1>(), prop<1>(), prop<1>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp11/prefer_unsupported.cpp b/test/properties/cpp11/prefer_unsupported.cpp new file mode 100644 index 00000000..b44b38e6 --- /dev/null +++ b/test/properties/cpp11/prefer_unsupported.cpp @@ -0,0 +1,61 @@ +// +// cpp11/prefer_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<1> o2 = boost::asio::prefer(o1, prop<2>()); + object<1> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<1> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<1> o6 = boost::asio::prefer(o5, prop<2>()); + object<1> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<1> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<1> o9 = boost::asio::prefer(object<1>(), prop<2>()); + constexpr object<1> o10 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>()); + constexpr object<1> o11 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp11/query_free.cpp b/test/properties/cpp11/query_free.cpp new file mode 100644 index 00000000..2f831c4e --- /dev/null +++ b/test/properties/cpp11/query_free.cpp @@ -0,0 +1,51 @@ +// +// cpp11/query_free.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + friend constexpr int query(const object&, prop) { return 123; } +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object o1 = {}; + int result1 = boost::asio::query(o1, prop()); + assert(result1 == 123); + (void)result1; + + const object o2 = {}; + int result2 = boost::asio::query(o2, prop()); + assert(result2 == 123); + (void)result2; + + constexpr object o3 = {}; + constexpr int result3 = boost::asio::query(o3, prop()); + assert(result3 == 123); + (void)result3; +} diff --git a/test/properties/cpp11/query_member.cpp b/test/properties/cpp11/query_member.cpp new file mode 100644 index 00000000..bb91efe6 --- /dev/null +++ b/test/properties/cpp11/query_member.cpp @@ -0,0 +1,51 @@ +// +// cpp11/query_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + constexpr int query(prop) const { return 123; } +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object o1 = {}; + int result1 = boost::asio::query(o1, prop()); + assert(result1 == 123); + (void)result1; + + const object o2 = {}; + int result2 = boost::asio::query(o2, prop()); + assert(result2 == 123); + (void)result2; + + constexpr object o3 = {}; + constexpr int result3 = boost::asio::query(o3, prop()); + assert(result3 == 123); + (void)result3; +} diff --git a/test/properties/cpp11/query_static.cpp b/test/properties/cpp11/query_static.cpp new file mode 100644 index 00000000..8b8f2122 --- /dev/null +++ b/test/properties/cpp11/query_static.cpp @@ -0,0 +1,62 @@ +// +// cpp11/query_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +namespace boost { +namespace asio { + +template<> +struct is_applicable_property +{ + static constexpr bool value = true; +}; + +namespace traits { + +template<> +struct static_query +{ + static constexpr bool is_valid = true; + static constexpr bool is_noexcept = true; + typedef int result_type; + static constexpr int value() { return 123; } +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object o1 = {}; + int result1 = boost::asio::query(o1, prop()); + assert(result1 == 123); + (void)result1; + + const object o2 = {}; + int result2 = boost::asio::query(o2, prop()); + assert(result2 == 123); + (void)result2; + + constexpr object o3 = {}; + constexpr int result3 = boost::asio::query(o3, prop()); + assert(result3 == 123); + (void)result3; +} diff --git a/test/properties/cpp11/require_concept_free.cpp b/test/properties/cpp11/require_concept_free.cpp new file mode 100644 index 00000000..76d8a2ef --- /dev/null +++ b/test/properties/cpp11/require_concept_free.cpp @@ -0,0 +1,54 @@ +// +// cpp11/require_concept_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + friend constexpr object require_concept(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require_concept(o1, prop<2>()); + (void)o2; + + const object<1> o3 = {}; + object<2> o4 = boost::asio::require_concept(o3, prop<2>()); + (void)o4; + + constexpr object<2> o5 = boost::asio::require_concept(object<1>(), prop<2>()); + (void)o5; +} diff --git a/test/properties/cpp11/require_concept_member.cpp b/test/properties/cpp11/require_concept_member.cpp new file mode 100644 index 00000000..86404e93 --- /dev/null +++ b/test/properties/cpp11/require_concept_member.cpp @@ -0,0 +1,54 @@ +// +// cpp11/require_concept_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + constexpr object require_concept(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require_concept(o1, prop<2>()); + (void)o2; + + const object<1> o3 = {}; + object<2> o4 = boost::asio::require_concept(o3, prop<2>()); + (void)o4; + + constexpr object<2> o5 = boost::asio::require_concept(object<1>(), prop<2>()); + (void)o5; +} diff --git a/test/properties/cpp11/require_concept_static.cpp b/test/properties/cpp11/require_concept_static.cpp new file mode 100644 index 00000000..cfd29524 --- /dev/null +++ b/test/properties/cpp11/require_concept_static.cpp @@ -0,0 +1,60 @@ +// +// cpp11/require_concept_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +namespace traits { + +template +struct static_require_concept, prop > +{ + static constexpr bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + const object<1>& o2 = boost::asio::require_concept(o1, prop<1>()); + assert(&o1 == &o2); + (void)o2; + + const object<1> o3 = {}; + const object<1>& o4 = boost::asio::require_concept(o3, prop<1>()); + assert(&o3 == &o4); + (void)o4; + + constexpr object<1> o5 = boost::asio::require_concept(object<1>(), prop<1>()); + (void)o5; +} diff --git a/test/properties/cpp11/require_free.cpp b/test/properties/cpp11/require_free.cpp new file mode 100644 index 00000000..6b99350f --- /dev/null +++ b/test/properties/cpp11/require_free.cpp @@ -0,0 +1,66 @@ +// +// cpp11/require_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require(o1, prop<2>()); + object<3> o3 = boost::asio::require(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::require(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::require(o5, prop<2>()); + object<3> o7 = boost::asio::require(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::require(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::require(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::require(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::require(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp11/require_member.cpp b/test/properties/cpp11/require_member.cpp new file mode 100644 index 00000000..87886133 --- /dev/null +++ b/test/properties/cpp11/require_member.cpp @@ -0,0 +1,66 @@ +// +// cpp11/require_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require(o1, prop<2>()); + object<3> o3 = boost::asio::require(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::require(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::require(o5, prop<2>()); + object<3> o7 = boost::asio::require(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::require(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::require(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::require(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::require(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp11/require_static.cpp b/test/properties/cpp11/require_static.cpp new file mode 100644 index 00000000..a74b13ec --- /dev/null +++ b/test/properties/cpp11/require_static.cpp @@ -0,0 +1,70 @@ +// +// cpp11/require_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +namespace traits { + +template +struct static_require, prop > +{ + static constexpr bool is_valid = true; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +int main() +{ + object<1> o1 = {}; + object<1> o2 = boost::asio::require(o1, prop<1>()); + object<1> o3 = boost::asio::require(o1, prop<1>(), prop<1>()); + object<1> o4 = boost::asio::require(o1, prop<1>(), prop<1>(), prop<1>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<1> o6 = boost::asio::require(o5, prop<1>()); + object<1> o7 = boost::asio::require(o5, prop<1>(), prop<1>()); + object<1> o8 = boost::asio::require(o5, prop<1>(), prop<1>(), prop<1>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<1> o9 = boost::asio::require(object<1>(), prop<1>()); + constexpr object<1> o10 = boost::asio::require(object<1>(), prop<1>(), prop<1>()); + constexpr object<1> o11 = boost::asio::require(object<1>(), prop<1>(), prop<1>(), prop<1>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp14/Jamfile.v2 b/test/properties/cpp14/Jamfile.v2 new file mode 100644 index 00000000..f2264864 --- /dev/null +++ b/test/properties/cpp14/Jamfile.v2 @@ -0,0 +1,101 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import feature ; + +lib socket ; # SOLARIS, QNXNTO +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + /boost/date_time//boost_date_time + /boost/system//boost_system + /boost/chrono//boost_chrono + /boost/regex//boost_regex + BOOST_ALL_NO_LIB=1 + multi + linux:_XOPEN_SOURCE=600 + linux:_GNU_SOURCE=1 + solaris:_XOPEN_SOURCE=500 + solaris:__EXTENSIONS__ + solaris:socket + solaris:nsl + windows:_WIN32_WINNT=0x0501 + windows,cw:ws2_32 + windows,cw:mswsock + windows,gcc:ws2_32 + windows,gcc:mswsock + windows,gcc-cygwin:__USE_W32_SOCKETS + hpux,gcc:_XOPEN_SOURCE_EXTENDED + hpux:ipv6 + qnxnto:socket + haiku:network + ; + +test-suite "asio" : + [ run can_prefer_free_prefer.cpp ] + [ run can_prefer_free_require.cpp ] + [ run can_prefer_member_prefer.cpp ] + [ run can_prefer_member_require.cpp ] + [ run can_prefer_not_applicable_free_prefer.cpp ] + [ run can_prefer_not_applicable_free_require.cpp ] + [ run can_prefer_not_applicable_member_prefer.cpp ] + [ run can_prefer_not_applicable_member_require.cpp ] + [ run can_prefer_not_applicable_static.cpp ] + [ run can_prefer_not_applicable_unsupported.cpp ] + [ run can_prefer_not_preferable_free_prefer.cpp ] + [ run can_prefer_not_preferable_free_require.cpp ] + [ run can_prefer_not_preferable_member_prefer.cpp ] + [ run can_prefer_not_preferable_member_require.cpp ] + [ run can_prefer_not_preferable_static.cpp ] + [ run can_prefer_not_preferable_unsupported.cpp ] + [ run can_prefer_static.cpp ] + [ run can_prefer_unsupported.cpp ] + [ run can_query_free.cpp ] + [ run can_query_member.cpp ] + [ run can_query_not_applicable_free.cpp ] + [ run can_query_not_applicable_member.cpp ] + [ run can_query_not_applicable_static.cpp ] + [ run can_query_not_applicable_unsupported.cpp ] + [ run can_query_static.cpp ] + [ run can_query_unsupported.cpp ] + [ run can_require_concept_free.cpp ] + [ run can_require_concept_member.cpp ] + [ run can_require_concept_not_applicable_free.cpp ] + [ run can_require_concept_not_applicable_member.cpp ] + [ run can_require_concept_not_applicable_static.cpp ] + [ run can_require_concept_not_applicable_unsupported.cpp ] + [ run can_require_concept_static.cpp ] + [ run can_require_concept_unsupported.cpp ] + [ run can_require_free.cpp ] + [ run can_require_member.cpp ] + [ run can_require_not_applicable_free.cpp ] + [ run can_require_not_applicable_member.cpp ] + [ run can_require_not_applicable_static.cpp ] + [ run can_require_not_applicable_unsupported.cpp ] + [ run can_require_static.cpp ] + [ run can_require_unsupported.cpp ] + [ run prefer_free_prefer.cpp ] + [ run prefer_free_require.cpp ] + [ run prefer_member_prefer.cpp ] + [ run prefer_member_require.cpp ] + [ run prefer_static.cpp ] + [ run prefer_unsupported.cpp ] + [ run query_free.cpp ] + [ run query_member.cpp ] + [ run query_static.cpp ] + [ run require_concept_free.cpp ] + [ run require_concept_member.cpp ] + [ run require_concept_static.cpp ] + [ run require_free.cpp ] + [ run require_member.cpp ] + [ run require_static.cpp ] + ; diff --git a/test/properties/cpp14/can_prefer_free_prefer.cpp b/test/properties/cpp14/can_prefer_free_prefer.cpp new file mode 100644 index 00000000..c1283fc9 --- /dev/null +++ b/test/properties/cpp14/can_prefer_free_prefer.cpp @@ -0,0 +1,39 @@ +// +// cpp14/can_prefer_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object prefer(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_free_require.cpp b/test/properties/cpp14/can_prefer_free_require.cpp new file mode 100644 index 00000000..55b742ff --- /dev/null +++ b/test/properties/cpp14/can_prefer_free_require.cpp @@ -0,0 +1,39 @@ +// +// cpp14/can_prefer_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_member_prefer.cpp b/test/properties/cpp14/can_prefer_member_prefer.cpp new file mode 100644 index 00000000..e4e085a1 --- /dev/null +++ b/test/properties/cpp14/can_prefer_member_prefer.cpp @@ -0,0 +1,39 @@ +// +// cpp14/can_prefer_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object prefer(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_member_require.cpp b/test/properties/cpp14/can_prefer_member_require.cpp new file mode 100644 index 00000000..98125970 --- /dev/null +++ b/test/properties/cpp14/can_prefer_member_require.cpp @@ -0,0 +1,39 @@ +// +// cpp14/can_prefer_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_applicable_free_prefer.cpp b/test/properties/cpp14/can_prefer_not_applicable_free_prefer.cpp new file mode 100644 index 00000000..cde1a188 --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_applicable_free_prefer.cpp @@ -0,0 +1,38 @@ +// +// cpp14/can_prefer_not_applicable_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object prefer(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_applicable_free_require.cpp b/test/properties/cpp14/can_prefer_not_applicable_free_require.cpp new file mode 100644 index 00000000..9f1c5496 --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_applicable_free_require.cpp @@ -0,0 +1,38 @@ +// +// cpp14/can_prefer_not_applicable_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_applicable_member_prefer.cpp b/test/properties/cpp14/can_prefer_not_applicable_member_prefer.cpp new file mode 100644 index 00000000..2fd97fc7 --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_applicable_member_prefer.cpp @@ -0,0 +1,38 @@ +// +// cpp14/can_prefer_not_applicable_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object prefer(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_applicable_member_require.cpp b/test/properties/cpp14/can_prefer_not_applicable_member_require.cpp new file mode 100644 index 00000000..bebe2d3b --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_applicable_member_require.cpp @@ -0,0 +1,38 @@ +// +// cpp14/can_prefer_not_applicable_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_applicable_static.cpp b/test/properties/cpp14/can_prefer_not_applicable_static.cpp new file mode 100644 index 00000000..ebaa1346 --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_applicable_static.cpp @@ -0,0 +1,35 @@ +// +// cpp14/can_prefer_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_preferable = true; + template static constexpr bool static_query_v = true; + static constexpr bool value() { return true; } +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<1>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<1>, prop<1>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<1>, prop<1>, prop<1>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<1>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<1>, prop<1>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<1>, prop<1>, prop<1>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_applicable_unsupported.cpp b/test/properties/cpp14/can_prefer_not_applicable_unsupported.cpp new file mode 100644 index 00000000..fec98434 --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_applicable_unsupported.cpp @@ -0,0 +1,32 @@ +// +// cpp14/can_prefer_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_preferable_free_prefer.cpp b/test/properties/cpp14/can_prefer_not_preferable_free_prefer.cpp new file mode 100644 index 00000000..3a1d156b --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_preferable_free_prefer.cpp @@ -0,0 +1,39 @@ +// +// cpp14/can_prefer_not_preferable_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = false; +}; + +template +struct object +{ + template + friend constexpr object prefer(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_preferable_free_require.cpp b/test/properties/cpp14/can_prefer_not_preferable_free_require.cpp new file mode 100644 index 00000000..02a7a25f --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_preferable_free_require.cpp @@ -0,0 +1,39 @@ +// +// cpp14/can_prefer_not_preferable_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = false; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_preferable_member_prefer.cpp b/test/properties/cpp14/can_prefer_not_preferable_member_prefer.cpp new file mode 100644 index 00000000..f87dacbb --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_preferable_member_prefer.cpp @@ -0,0 +1,39 @@ +// +// cpp14/can_prefer_not_preferable_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = false; +}; + +template +struct object +{ + template + constexpr object prefer(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_preferable_member_require.cpp b/test/properties/cpp14/can_prefer_not_preferable_member_require.cpp new file mode 100644 index 00000000..5793d6cc --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_preferable_member_require.cpp @@ -0,0 +1,39 @@ +// +// cpp14/can_prefer_not_preferable_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = false; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_preferable_static.cpp b/test/properties/cpp14/can_prefer_not_preferable_static.cpp new file mode 100644 index 00000000..18c59b3e --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_preferable_static.cpp @@ -0,0 +1,34 @@ +// +// cpp14/can_prefer_not_preferable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = false; +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<1>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<1>, prop<1>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<1>, prop<1>, prop<1>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<1>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<1>, prop<1>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<1>, prop<1>, prop<1>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_not_preferable_unsupported.cpp b/test/properties/cpp14/can_prefer_not_preferable_unsupported.cpp new file mode 100644 index 00000000..5d1f28a5 --- /dev/null +++ b/test/properties/cpp14/can_prefer_not_preferable_unsupported.cpp @@ -0,0 +1,34 @@ +// +// cpp14/can_prefer_not_preferable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = false; +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_static.cpp b/test/properties/cpp14/can_prefer_static.cpp new file mode 100644 index 00000000..b4ff8cec --- /dev/null +++ b/test/properties/cpp14/can_prefer_static.cpp @@ -0,0 +1,36 @@ +// +// cpp14/can_prefer_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; + template static constexpr bool static_query_v = true; + static constexpr bool value() { return true; } +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(boost::asio::can_prefer_v, prop<1>>, ""); + static_assert(boost::asio::can_prefer_v, prop<1>, prop<1>>, ""); + static_assert(boost::asio::can_prefer_v, prop<1>, prop<1>, prop<1>>, ""); + static_assert(boost::asio::can_prefer_v, prop<1>>, ""); + static_assert(boost::asio::can_prefer_v, prop<1>, prop<1>>, ""); + static_assert(boost::asio::can_prefer_v, prop<1>, prop<1>, prop<1>>, ""); +} diff --git a/test/properties/cpp14/can_prefer_unsupported.cpp b/test/properties/cpp14/can_prefer_unsupported.cpp new file mode 100644 index 00000000..0d603f00 --- /dev/null +++ b/test/properties/cpp14/can_prefer_unsupported.cpp @@ -0,0 +1,44 @@ +// +// cpp14/can_prefer_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_prefer_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_query_free.cpp b/test/properties/cpp14/can_query_free.cpp new file mode 100644 index 00000000..ddd5a153 --- /dev/null +++ b/test/properties/cpp14/can_query_free.cpp @@ -0,0 +1,28 @@ +// +// cpp14/can_query_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ + template static constexpr bool is_applicable_property_v = true; +}; + +struct object +{ + friend constexpr int query(const object&, prop) { return 123; } +}; + +int main() +{ + static_assert(boost::asio::can_query_v, ""); + static_assert(boost::asio::can_query_v, ""); +} diff --git a/test/properties/cpp14/can_query_member.cpp b/test/properties/cpp14/can_query_member.cpp new file mode 100644 index 00000000..05fe40e5 --- /dev/null +++ b/test/properties/cpp14/can_query_member.cpp @@ -0,0 +1,28 @@ +// +// cpp14/can_query_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ + template static constexpr bool is_applicable_property_v = true; +}; + +struct object +{ + constexpr int query(prop) const { return 123; } +}; + +int main() +{ + static_assert(boost::asio::can_query_v, ""); + static_assert(boost::asio::can_query_v, ""); +} diff --git a/test/properties/cpp14/can_query_not_applicable_free.cpp b/test/properties/cpp14/can_query_not_applicable_free.cpp new file mode 100644 index 00000000..ad2416e7 --- /dev/null +++ b/test/properties/cpp14/can_query_not_applicable_free.cpp @@ -0,0 +1,27 @@ +// +// cpp14/can_query_not_applicable_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + friend constexpr int query(const object&, prop) { return 123; } +}; + +int main() +{ + static_assert(!boost::asio::can_query_v, ""); + static_assert(!boost::asio::can_query_v, ""); +} diff --git a/test/properties/cpp14/can_query_not_applicable_member.cpp b/test/properties/cpp14/can_query_not_applicable_member.cpp new file mode 100644 index 00000000..f4386cc2 --- /dev/null +++ b/test/properties/cpp14/can_query_not_applicable_member.cpp @@ -0,0 +1,27 @@ +// +// cpp14/can_query_not_applicable_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ + constexpr int query(prop) const { return 123; } +}; + +int main() +{ + static_assert(!boost::asio::can_query_v, ""); + static_assert(!boost::asio::can_query_v, ""); +} diff --git a/test/properties/cpp14/can_query_not_applicable_static.cpp b/test/properties/cpp14/can_query_not_applicable_static.cpp new file mode 100644 index 00000000..ea300381 --- /dev/null +++ b/test/properties/cpp14/can_query_not_applicable_static.cpp @@ -0,0 +1,27 @@ +// +// cpp14/can_query_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ + template static constexpr int static_query_v = 123; +}; + +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_query_v, ""); + static_assert(!boost::asio::can_query_v, ""); +} diff --git a/test/properties/cpp14/can_query_not_applicable_unsupported.cpp b/test/properties/cpp14/can_query_not_applicable_unsupported.cpp new file mode 100644 index 00000000..0fcb8757 --- /dev/null +++ b/test/properties/cpp14/can_query_not_applicable_unsupported.cpp @@ -0,0 +1,26 @@ +// +// cpp14/can_query_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ +}; + +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_query_v, ""); + static_assert(!boost::asio::can_query_v, ""); +} diff --git a/test/properties/cpp14/can_query_static.cpp b/test/properties/cpp14/can_query_static.cpp new file mode 100644 index 00000000..83d5d302 --- /dev/null +++ b/test/properties/cpp14/can_query_static.cpp @@ -0,0 +1,28 @@ +// +// cpp14/can_query_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + template static constexpr int static_query_v = 123; +}; + +struct object +{ +}; + +int main() +{ + static_assert(boost::asio::can_query_v, ""); + static_assert(boost::asio::can_query_v, ""); +} diff --git a/test/properties/cpp14/can_query_unsupported.cpp b/test/properties/cpp14/can_query_unsupported.cpp new file mode 100644 index 00000000..4faee2e9 --- /dev/null +++ b/test/properties/cpp14/can_query_unsupported.cpp @@ -0,0 +1,27 @@ +// +// cpp14/can_query_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ + template static constexpr bool is_applicable_property_v = true; +}; + +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_query_v, ""); + static_assert(!boost::asio::can_query_v, ""); +} diff --git a/test/properties/cpp14/can_require_concept_free.cpp b/test/properties/cpp14/can_require_concept_free.cpp new file mode 100644 index 00000000..f5c7ad28 --- /dev/null +++ b/test/properties/cpp14/can_require_concept_free.cpp @@ -0,0 +1,35 @@ +// +// cpp14/can_require_concept_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + friend constexpr object require_concept(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(boost::asio::can_require_concept_v, prop<2>>, ""); + static_assert(boost::asio::can_require_concept_v, prop<2>>, ""); +} diff --git a/test/properties/cpp14/can_require_concept_member.cpp b/test/properties/cpp14/can_require_concept_member.cpp new file mode 100644 index 00000000..e009754c --- /dev/null +++ b/test/properties/cpp14/can_require_concept_member.cpp @@ -0,0 +1,35 @@ +// +// cpp14/can_require_concept_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + constexpr object require_concept(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(boost::asio::can_require_concept_v, prop<2>>, ""); + static_assert(boost::asio::can_require_concept_v, prop<2>>, ""); +} diff --git a/test/properties/cpp14/can_require_concept_not_applicable_free.cpp b/test/properties/cpp14/can_require_concept_not_applicable_free.cpp new file mode 100644 index 00000000..b0eec76d --- /dev/null +++ b/test/properties/cpp14/can_require_concept_not_applicable_free.cpp @@ -0,0 +1,34 @@ +// +// cpp14/can_require_concept_not_applicable_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + friend constexpr object require_concept(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_require_concept_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_concept_v, prop<2>>, ""); +} diff --git a/test/properties/cpp14/can_require_concept_not_applicable_member.cpp b/test/properties/cpp14/can_require_concept_not_applicable_member.cpp new file mode 100644 index 00000000..78ea50d4 --- /dev/null +++ b/test/properties/cpp14/can_require_concept_not_applicable_member.cpp @@ -0,0 +1,34 @@ +// +// cpp14/can_require_concept_not_applicable_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + constexpr object require_concept(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_require_concept_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_concept_v, prop<2>>, ""); +} diff --git a/test/properties/cpp14/can_require_concept_not_applicable_static.cpp b/test/properties/cpp14/can_require_concept_not_applicable_static.cpp new file mode 100644 index 00000000..8ebbe174 --- /dev/null +++ b/test/properties/cpp14/can_require_concept_not_applicable_static.cpp @@ -0,0 +1,31 @@ +// +// cpp14/can_require_concept_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable_concept = true; + template static constexpr bool static_query_v = true; + static constexpr bool value() { return true; } +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_require_concept_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_concept_v, prop<2>>, ""); +} diff --git a/test/properties/cpp14/can_require_concept_not_applicable_unsupported.cpp b/test/properties/cpp14/can_require_concept_not_applicable_unsupported.cpp new file mode 100644 index 00000000..ebba75a9 --- /dev/null +++ b/test/properties/cpp14/can_require_concept_not_applicable_unsupported.cpp @@ -0,0 +1,28 @@ +// +// cpp14/can_require_concept_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_require_concept_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_concept_v, prop<2>>, ""); +} diff --git a/test/properties/cpp14/can_require_concept_static.cpp b/test/properties/cpp14/can_require_concept_static.cpp new file mode 100644 index 00000000..994ecdb7 --- /dev/null +++ b/test/properties/cpp14/can_require_concept_static.cpp @@ -0,0 +1,32 @@ +// +// cpp14/can_require_concept_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable_concept = true; + template static constexpr bool static_query_v = true; + static constexpr bool value() { return true; } +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(boost::asio::can_require_concept_v, prop<1>>, ""); + static_assert(boost::asio::can_require_concept_v, prop<1>>, ""); +} diff --git a/test/properties/cpp14/can_require_concept_unsupported.cpp b/test/properties/cpp14/can_require_concept_unsupported.cpp new file mode 100644 index 00000000..edda4ed2 --- /dev/null +++ b/test/properties/cpp14/can_require_concept_unsupported.cpp @@ -0,0 +1,40 @@ +// +// cpp14/can_require_concept_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); + static_assert(!boost::asio::can_require_concept, prop<2>>::value, ""); +} diff --git a/test/properties/cpp14/can_require_free.cpp b/test/properties/cpp14/can_require_free.cpp new file mode 100644 index 00000000..5420e7fd --- /dev/null +++ b/test/properties/cpp14/can_require_free.cpp @@ -0,0 +1,39 @@ +// +// cpp14/can_require_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(boost::asio::can_require_v, prop<2>>, ""); + static_assert(boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(boost::asio::can_require_v, prop<2>>, ""); + static_assert(boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_require_member.cpp b/test/properties/cpp14/can_require_member.cpp new file mode 100644 index 00000000..cd4ce542 --- /dev/null +++ b/test/properties/cpp14/can_require_member.cpp @@ -0,0 +1,39 @@ +// +// cpp14/can_require_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(boost::asio::can_require_v, prop<2>>, ""); + static_assert(boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(boost::asio::can_require_v, prop<2>>, ""); + static_assert(boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_require_not_applicable_free.cpp b/test/properties/cpp14/can_require_not_applicable_free.cpp new file mode 100644 index 00000000..9e590ea9 --- /dev/null +++ b/test/properties/cpp14/can_require_not_applicable_free.cpp @@ -0,0 +1,38 @@ +// +// cpp14/can_require_not_applicable_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_require_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_require_not_applicable_member.cpp b/test/properties/cpp14/can_require_not_applicable_member.cpp new file mode 100644 index 00000000..b7a295c1 --- /dev/null +++ b/test/properties/cpp14/can_require_not_applicable_member.cpp @@ -0,0 +1,38 @@ +// +// cpp14/can_require_not_applicable_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +int main() +{ + static_assert(!boost::asio::can_require_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_require_not_applicable_static.cpp b/test/properties/cpp14/can_require_not_applicable_static.cpp new file mode 100644 index 00000000..38037f13 --- /dev/null +++ b/test/properties/cpp14/can_require_not_applicable_static.cpp @@ -0,0 +1,35 @@ +// +// cpp14/can_require_not_applicable_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + static constexpr bool is_requirable = true; + template static constexpr bool static_query_v = true; + static constexpr bool value() { return true; } +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_require_v, prop<1>>, ""); + static_assert(!boost::asio::can_require_v, prop<1>, prop<1>>, ""); + static_assert(!boost::asio::can_require_v, prop<1>, prop<1>, prop<1>>, ""); + static_assert(!boost::asio::can_require_v, prop<1>>, ""); + static_assert(!boost::asio::can_require_v, prop<1>, prop<1>>, ""); + static_assert(!boost::asio::can_require_v, prop<1>, prop<1>, prop<1>>, ""); +} diff --git a/test/properties/cpp14/can_require_not_applicable_unsupported.cpp b/test/properties/cpp14/can_require_not_applicable_unsupported.cpp new file mode 100644 index 00000000..ab48b1db --- /dev/null +++ b/test/properties/cpp14/can_require_not_applicable_unsupported.cpp @@ -0,0 +1,32 @@ +// +// cpp14/can_require_not_applicable_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(!boost::asio::can_require_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/can_require_static.cpp b/test/properties/cpp14/can_require_static.cpp new file mode 100644 index 00000000..bbb00bad --- /dev/null +++ b/test/properties/cpp14/can_require_static.cpp @@ -0,0 +1,36 @@ +// +// cpp14/can_require_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable = true; + template static constexpr bool static_query_v = true; + static constexpr bool value() { return true; } +}; + +template +struct object +{ +}; + +int main() +{ + static_assert(boost::asio::can_require_v, prop<1>>, ""); + static_assert(boost::asio::can_require_v, prop<1>, prop<1>>, ""); + static_assert(boost::asio::can_require_v, prop<1>, prop<1>, prop<1>>, ""); + static_assert(boost::asio::can_require_v, prop<1>>, ""); + static_assert(boost::asio::can_require_v, prop<1>, prop<1>>, ""); + static_assert(boost::asio::can_require_v, prop<1>, prop<1>, prop<1>>, ""); +} diff --git a/test/properties/cpp14/can_require_unsupported.cpp b/test/properties/cpp14/can_require_unsupported.cpp new file mode 100644 index 00000000..e000d700 --- /dev/null +++ b/test/properties/cpp14/can_require_unsupported.cpp @@ -0,0 +1,44 @@ +// +// cpp14/can_require_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ +}; + +template +struct object +{ +}; + +namespace boost { +namespace asio { + +template +struct is_applicable_property, prop > +{ + static constexpr bool value = true; +}; + +} // namespace asio +} // namespace boost + +int main() +{ + static_assert(!boost::asio::can_require_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>>, ""); + static_assert(!boost::asio::can_require_v, prop<2>, prop<3>, prop<4>>, ""); +} diff --git a/test/properties/cpp14/prefer_free_prefer.cpp b/test/properties/cpp14/prefer_free_prefer.cpp new file mode 100644 index 00000000..e83520c7 --- /dev/null +++ b/test/properties/cpp14/prefer_free_prefer.cpp @@ -0,0 +1,55 @@ +// +// cpp14/prefer_free_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object prefer(const object&, prop) + { + return object(); + } +}; + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::prefer(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp14/prefer_free_require.cpp b/test/properties/cpp14/prefer_free_require.cpp new file mode 100644 index 00000000..19001c52 --- /dev/null +++ b/test/properties/cpp14/prefer_free_require.cpp @@ -0,0 +1,55 @@ +// +// cpp14/prefer_free_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::prefer(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp14/prefer_member_prefer.cpp b/test/properties/cpp14/prefer_member_prefer.cpp new file mode 100644 index 00000000..4eba547b --- /dev/null +++ b/test/properties/cpp14/prefer_member_prefer.cpp @@ -0,0 +1,55 @@ +// +// cpp14/prefer_member_prefer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object prefer(prop) const + { + return object(); + } +}; + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::prefer(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp14/prefer_member_require.cpp b/test/properties/cpp14/prefer_member_require.cpp new file mode 100644 index 00000000..52f71713 --- /dev/null +++ b/test/properties/cpp14/prefer_member_require.cpp @@ -0,0 +1,55 @@ +// +// cpp14/prefer_member_require.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::prefer(o1, prop<2>()); + object<3> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::prefer(o5, prop<2>()); + object<3> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::prefer(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp14/prefer_static.cpp b/test/properties/cpp14/prefer_static.cpp new file mode 100644 index 00000000..2e4b56cf --- /dev/null +++ b/test/properties/cpp14/prefer_static.cpp @@ -0,0 +1,52 @@ +// +// cpp14/prefer_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; + template static constexpr bool static_query_v = true; + static constexpr bool value() { return true; } +}; + +template +struct object +{ +}; + +int main() +{ + object<1> o1 = {}; + object<1> o2 = boost::asio::prefer(o1, prop<1>()); + object<1> o3 = boost::asio::prefer(o1, prop<1>(), prop<1>()); + object<1> o4 = boost::asio::prefer(o1, prop<1>(), prop<1>(), prop<1>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<1> o6 = boost::asio::prefer(o5, prop<1>()); + object<1> o7 = boost::asio::prefer(o5, prop<1>(), prop<1>()); + object<1> o8 = boost::asio::prefer(o5, prop<1>(), prop<1>(), prop<1>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<1> o9 = boost::asio::prefer(object<1>(), prop<1>()); + constexpr object<1> o10 = boost::asio::prefer(object<1>(), prop<1>(), prop<1>()); + constexpr object<1> o11 = boost::asio::prefer(object<1>(), prop<1>(), prop<1>(), prop<1>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp14/prefer_unsupported.cpp b/test/properties/cpp14/prefer_unsupported.cpp new file mode 100644 index 00000000..425144ab --- /dev/null +++ b/test/properties/cpp14/prefer_unsupported.cpp @@ -0,0 +1,50 @@ +// +// cpp14/prefer_unsupported.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_preferable = true; +}; + +template +struct object +{ +}; + +int main() +{ + object<1> o1 = {}; + object<1> o2 = boost::asio::prefer(o1, prop<2>()); + object<1> o3 = boost::asio::prefer(o1, prop<2>(), prop<3>()); + object<1> o4 = boost::asio::prefer(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<1> o6 = boost::asio::prefer(o5, prop<2>()); + object<1> o7 = boost::asio::prefer(o5, prop<2>(), prop<3>()); + object<1> o8 = boost::asio::prefer(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<1> o9 = boost::asio::prefer(object<1>(), prop<2>()); + constexpr object<1> o10 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>()); + constexpr object<1> o11 = boost::asio::prefer(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp14/query_free.cpp b/test/properties/cpp14/query_free.cpp new file mode 100644 index 00000000..131f9125 --- /dev/null +++ b/test/properties/cpp14/query_free.cpp @@ -0,0 +1,40 @@ +// +// cpp14/query_free.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ + template static constexpr bool is_applicable_property_v = true; +}; + +struct object +{ + friend constexpr int query(const object&, prop) { return 123; } +}; + +int main() +{ + object o1 = {}; + int result1 = boost::asio::query(o1, prop()); + assert(result1 == 123); + (void)result1; + + const object o2 = {}; + int result2 = boost::asio::query(o2, prop()); + assert(result2 == 123); + (void)result2; + + constexpr object o3 = {}; + constexpr int result3 = boost::asio::query(o3, prop()); + assert(result3 == 123); + (void)result3; +} diff --git a/test/properties/cpp14/query_member.cpp b/test/properties/cpp14/query_member.cpp new file mode 100644 index 00000000..f0faa02f --- /dev/null +++ b/test/properties/cpp14/query_member.cpp @@ -0,0 +1,40 @@ +// +// cpp14/query_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ + template static constexpr bool is_applicable_property_v = true; +}; + +struct object +{ + constexpr int query(prop) const { return 123; } +}; + +int main() +{ + object o1 = {}; + int result1 = boost::asio::query(o1, prop()); + assert(result1 == 123); + (void)result1; + + const object o2 = {}; + int result2 = boost::asio::query(o2, prop()); + assert(result2 == 123); + (void)result2; + + constexpr object o3 = {}; + constexpr int result3 = boost::asio::query(o3, prop()); + assert(result3 == 123); + (void)result3; +} diff --git a/test/properties/cpp14/query_static.cpp b/test/properties/cpp14/query_static.cpp new file mode 100644 index 00000000..0254d3c3 --- /dev/null +++ b/test/properties/cpp14/query_static.cpp @@ -0,0 +1,40 @@ +// +// cpp14/query_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + template static constexpr int static_query_v = 123; +}; + +struct object +{ +}; + +int main() +{ + object o1 = {}; + int result1 = boost::asio::query(o1, prop()); + assert(result1 == 123); + (void)result1; + + const object o2 = {}; + int result2 = boost::asio::query(o2, prop()); + assert(result2 == 123); + (void)result2; + + constexpr object o3 = {}; + constexpr int result3 = boost::asio::query(o3, prop()); + assert(result3 == 123); + (void)result3; +} diff --git a/test/properties/cpp14/require_concept_free.cpp b/test/properties/cpp14/require_concept_free.cpp new file mode 100644 index 00000000..4e7752c7 --- /dev/null +++ b/test/properties/cpp14/require_concept_free.cpp @@ -0,0 +1,43 @@ +// +// cpp14/require_concept_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + friend constexpr object require_concept(const object&, prop) + { + return object(); + } +}; + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require_concept(o1, prop<2>()); + (void)o2; + + const object<1> o3 = {}; + object<2> o4 = boost::asio::require_concept(o3, prop<2>()); + (void)o4; + + constexpr object<2> o5 = boost::asio::require_concept(object<1>(), prop<2>()); + (void)o5; +} diff --git a/test/properties/cpp14/require_concept_member.cpp b/test/properties/cpp14/require_concept_member.cpp new file mode 100644 index 00000000..155c1b87 --- /dev/null +++ b/test/properties/cpp14/require_concept_member.cpp @@ -0,0 +1,43 @@ +// +// cpp14/require_concept_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable_concept = true; +}; + +template +struct object +{ + template + constexpr object require_concept(prop) const + { + return object(); + } +}; + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require_concept(o1, prop<2>()); + (void)o2; + + const object<1> o3 = {}; + object<2> o4 = boost::asio::require_concept(o3, prop<2>()); + (void)o4; + + constexpr object<2> o5 = boost::asio::require_concept(object<1>(), prop<2>()); + (void)o5; +} diff --git a/test/properties/cpp14/require_concept_static.cpp b/test/properties/cpp14/require_concept_static.cpp new file mode 100644 index 00000000..68eba17f --- /dev/null +++ b/test/properties/cpp14/require_concept_static.cpp @@ -0,0 +1,42 @@ +// +// cpp14/require_concept_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable_concept = true; + template static constexpr bool static_query_v = true; + static constexpr bool value() { return true; } +}; + +template +struct object +{ +}; + +int main() +{ + object<1> o1 = {}; + const object<1>& o2 = boost::asio::require_concept(o1, prop<1>()); + assert(&o1 == &o2); + (void)o2; + + const object<1> o3 = {}; + const object<1>& o4 = boost::asio::require_concept(o3, prop<1>()); + assert(&o3 == &o4); + (void)o4; + + constexpr object<1> o5 = boost::asio::require_concept(object<1>(), prop<1>()); + (void)o5; +} diff --git a/test/properties/cpp14/require_free.cpp b/test/properties/cpp14/require_free.cpp new file mode 100644 index 00000000..8c459267 --- /dev/null +++ b/test/properties/cpp14/require_free.cpp @@ -0,0 +1,55 @@ +// +// cpp14/require_free.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + friend constexpr object require(const object&, prop) + { + return object(); + } +}; + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require(o1, prop<2>()); + object<3> o3 = boost::asio::require(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::require(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::require(o5, prop<2>()); + object<3> o7 = boost::asio::require(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::require(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::require(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::require(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::require(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp14/require_member.cpp b/test/properties/cpp14/require_member.cpp new file mode 100644 index 00000000..c433ee94 --- /dev/null +++ b/test/properties/cpp14/require_member.cpp @@ -0,0 +1,55 @@ +// +// cpp14/require_member.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable = true; +}; + +template +struct object +{ + template + constexpr object require(prop) const + { + return object(); + } +}; + +int main() +{ + object<1> o1 = {}; + object<2> o2 = boost::asio::require(o1, prop<2>()); + object<3> o3 = boost::asio::require(o1, prop<2>(), prop<3>()); + object<4> o4 = boost::asio::require(o1, prop<2>(), prop<3>(), prop<4>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<2> o6 = boost::asio::require(o5, prop<2>()); + object<3> o7 = boost::asio::require(o5, prop<2>(), prop<3>()); + object<4> o8 = boost::asio::require(o5, prop<2>(), prop<3>(), prop<4>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<2> o9 = boost::asio::require(object<1>(), prop<2>()); + constexpr object<3> o10 = boost::asio::require(object<1>(), prop<2>(), prop<3>()); + constexpr object<4> o11 = boost::asio::require(object<1>(), prop<2>(), prop<3>(), prop<4>()); + (void)o9; + (void)o10; + (void)o11; +} diff --git a/test/properties/cpp14/require_static.cpp b/test/properties/cpp14/require_static.cpp new file mode 100644 index 00000000..126cb3a6 --- /dev/null +++ b/test/properties/cpp14/require_static.cpp @@ -0,0 +1,52 @@ +// +// cpp14/require_static.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +template +struct prop +{ + template static constexpr bool is_applicable_property_v = true; + static constexpr bool is_requirable = true; + template static constexpr bool static_query_v = true; + static constexpr bool value() { return true; } +}; + +template +struct object +{ +}; + +int main() +{ + object<1> o1 = {}; + object<1> o2 = boost::asio::require(o1, prop<1>()); + object<1> o3 = boost::asio::require(o1, prop<1>(), prop<1>()); + object<1> o4 = boost::asio::require(o1, prop<1>(), prop<1>(), prop<1>()); + (void)o2; + (void)o3; + (void)o4; + + const object<1> o5 = {}; + object<1> o6 = boost::asio::require(o5, prop<1>()); + object<1> o7 = boost::asio::require(o5, prop<1>(), prop<1>()); + object<1> o8 = boost::asio::require(o5, prop<1>(), prop<1>(), prop<1>()); + (void)o6; + (void)o7; + (void)o8; + + constexpr object<1> o9 = boost::asio::require(object<1>(), prop<1>()); + constexpr object<1> o10 = boost::asio::require(object<1>(), prop<1>(), prop<1>()); + constexpr object<1> o11 = boost::asio::require(object<1>(), prop<1>(), prop<1>(), prop<1>()); + (void)o9; + (void)o10; + (void)o11; +} From e3be5fe44499279a58f0b95d9bb0f80f2c21dd30 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:44:22 +1000 Subject: [PATCH 46/90] Add execution::invocable_archetype. --- include/boost/asio.hpp | 1 + .../boost/asio/detail/variadic_templates.hpp | 18 +++++ .../asio/execution/invocable_archetype.hpp | 68 +++++++++++++++++++ test/execution/Jamfile.v2 | 45 ++++++++++++ test/execution/invocable_archetype.cpp | 25 +++++++ 5 files changed, 157 insertions(+) create mode 100644 include/boost/asio/execution/invocable_archetype.hpp create mode 100644 test/execution/Jamfile.v2 create mode 100644 test/execution/invocable_archetype.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 6dea2c15..6575b045 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/detail/variadic_templates.hpp b/include/boost/asio/detail/variadic_templates.hpp index f1a8bc6c..790ece07 100644 --- a/include/boost/asio/detail/variadic_templates.hpp +++ b/include/boost/asio/detail/variadic_templates.hpp @@ -90,6 +90,24 @@ BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4, \ BOOST_ASIO_MOVE_ARG(T5) x5 +# define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n) \ + BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_##n + +# define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_1 \ + BOOST_ASIO_MOVE_ARG(T1) +# define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_2 \ + BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2) +# define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_3 \ + BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ + BOOST_ASIO_MOVE_ARG(T3) +# define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_4 \ + BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ + BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4) +# define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_5 \ + BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ + BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4), \ + BOOST_ASIO_MOVE_ARG(T5) + # define BOOST_ASIO_VARIADIC_MOVE_ARGS(n) \ BOOST_ASIO_VARIADIC_MOVE_ARGS_##n diff --git a/include/boost/asio/execution/invocable_archetype.hpp b/include/boost/asio/execution/invocable_archetype.hpp new file mode 100644 index 00000000..75715965 --- /dev/null +++ b/include/boost/asio/execution/invocable_archetype.hpp @@ -0,0 +1,68 @@ +// +// execution/invocable_archetype.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP +#define BOOST_ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace execution { + +/// An archetypal function object used for determining adherence to the +/// execution::executor concept. +struct invocable_archetype +{ +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + + /// Function call operator. + template + void operator()(BOOST_ASIO_MOVE_ARG(Args)...) + { + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + + void operator()() + { + } + +#define BOOST_ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF(n) \ + template \ + void operator()(BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n)) \ + { \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF) +#undef BOOST_ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP + diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 new file mode 100644 index 00000000..dc0f6a1c --- /dev/null +++ b/test/execution/Jamfile.v2 @@ -0,0 +1,45 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import feature ; + +lib socket ; # SOLARIS, QNXNTO +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + /boost/date_time//boost_date_time + /boost/system//boost_system + /boost/chrono//boost_chrono + /boost/regex//boost_regex + BOOST_ALL_NO_LIB=1 + multi + linux:_XOPEN_SOURCE=600 + linux:_GNU_SOURCE=1 + solaris:_XOPEN_SOURCE=500 + solaris:__EXTENSIONS__ + solaris:socket + solaris:nsl + windows:_WIN32_WINNT=0x0501 + windows,cw:ws2_32 + windows,cw:mswsock + windows,gcc:ws2_32 + windows,gcc:mswsock + windows,gcc-cygwin:__USE_W32_SOCKETS + hpux,gcc:_XOPEN_SOURCE_EXTENDED + hpux:ipv6 + qnxnto:socket + haiku:network + ; + +test-suite "asio" : + [ run invocable_archetype.cpp ] + ; diff --git a/test/execution/invocable_archetype.cpp b/test/execution/invocable_archetype.cpp new file mode 100644 index 00000000..629bea52 --- /dev/null +++ b/test/execution/invocable_archetype.cpp @@ -0,0 +1,25 @@ +// +// invocable_archetype.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "invocable_archetype", + BOOST_ASIO_TEST_CASE(null_test) +) From f6cfbc3982c72dd8afd5e99fb57cd7816569d2ff Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:49:58 +1000 Subject: [PATCH 47/90] Add execution::execute() customisation point object. --- include/boost/asio.hpp | 1 + include/boost/asio/execution/execute.hpp | 196 ++++++++++++ include/boost/asio/traits/execute_free.hpp | 110 +++++++ include/boost/asio/traits/execute_member.hpp | 110 +++++++ test/execution/Jamfile.v2 | 1 + test/execution/execute.cpp | 301 +++++++++++++++++++ 6 files changed, 719 insertions(+) create mode 100644 include/boost/asio/execution/execute.hpp create mode 100644 include/boost/asio/traits/execute_free.hpp create mode 100644 include/boost/asio/traits/execute_member.hpp create mode 100644 test/execution/execute.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 6575b045..4197bb40 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution/execute.hpp b/include/boost/asio/execution/execute.hpp new file mode 100644 index 00000000..04b5c074 --- /dev/null +++ b/include/boost/asio/execution/execute.hpp @@ -0,0 +1,196 @@ +// +// execution/execute.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_EXECUTE_HPP +#define BOOST_ASIO_EXECUTION_EXECUTE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +#if defined(GENERATING_DOCUMENTATION) + +namespace boost { +namespace asio { +namespace execution { + +/// A customisation point that executes a function on an executor. +/** + * The name execution::execute denotes a customization point object. + * + * For some subexpressions e and f, let E be a type + * such that decltype((e)) is E and let F be a type + * such that decltype((f)) is F. The expression + * execution::execute(e, f) is ill-formed if F does not model + * invocable, or if E does not model either executor + * or sender. Otherwise, it is expression-equivalent to: + * + * @li e.execute(f), if that expression is valid. If the function + * selected does not execute the function object f on the executor + * e, the program is ill-formed with no diagnostic required. + * + * @li Otherwise, execute(e, f), if that expression is valid, with + * overload resolution performed in a context that includes the declaration + * void execute(); and that does not include a declaration of + * execution::execute. If the function selected by overload + * resolution does not execute the function object f on the executor + * e, the program is ill-formed with no diagnostic required. + */ +inline constexpr unspecified execute = unspecified; + +/// A type trait that determines whether a @c execute expression is well-formed. +/** + * Class template @c can_execute is a trait that is derived from + * @c true_type if the expression execution::execute(std::declval(), + * std::declval()) is well formed; otherwise @c false_type. + */ +template +struct can_execute : + integral_constant +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#else // defined(GENERATING_DOCUMENTATION) + +namespace asio_execution_execute_fn { + +using boost::asio::decay; +using boost::asio::declval; +using boost::asio::enable_if; +using boost::asio::traits::execute_free; +using boost::asio::traits::execute_member; + +void execute(); + +enum overload_type +{ + call_member, + call_free, + ill_formed +}; + +template +struct call_traits +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); +}; + +template +struct call_traits::is_valid + ) + >::type> : + execute_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); +}; + +template +struct call_traits::is_valid + && + execute_free::is_valid + ) + >::type> : + execute_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); +}; + +struct impl +{ + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_member, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(F) f) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return BOOST_ASIO_MOVE_CAST(T)(t).execute(BOOST_ASIO_MOVE_CAST(F)(f)); + } + + template + BOOST_ASIO_CONSTEXPR typename enable_if< + call_traits::overload == call_free, + typename call_traits::result_type + >::type + operator()( + BOOST_ASIO_MOVE_ARG(T) t, + BOOST_ASIO_MOVE_ARG(F) f) const + BOOST_ASIO_NOEXCEPT_IF(( + call_traits::is_noexcept)) + { + return execute(BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(F)(f)); + } +}; + +template +struct static_instance +{ + static const T instance; +}; + +template +const T static_instance::instance = {}; + +} // namespace asio_execution_execute_fn +namespace boost { +namespace asio { +namespace execution { +namespace { + +static BOOST_ASIO_CONSTEXPR const asio_execution_execute_fn::impl& + execute = asio_execution_execute_fn::static_instance<>::instance; + +} // namespace + +template +struct can_execute : + integral_constant::overload != + asio_execution_execute_fn::ill_formed> +{ +}; + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +constexpr bool can_execute_v = can_execute::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // defined(GENERATING_DOCUMENTATION) + +#include + +#endif // BOOST_ASIO_EXECUTION_EXECUTE_HPP diff --git a/include/boost/asio/traits/execute_free.hpp b/include/boost/asio/traits/execute_free.hpp new file mode 100644 index 00000000..68344598 --- /dev/null +++ b/include/boost/asio/traits/execute_free.hpp @@ -0,0 +1,110 @@ +// +// traits/execute_free.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_EXECUTE_FREE_HPP +#define BOOST_ASIO_TRAITS_EXECUTE_FREE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct execute_free_default; + +template +struct execute_free; + +} // namespace traits +namespace detail { + +struct no_execute_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) + +template +struct execute_free_trait : no_execute_free +{ +}; + +template +struct execute_free_trait(), declval())) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + execute(declval(), declval())); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( + execute(declval(), declval()))); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) + +template +struct execute_free_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_execute_free, + traits::execute_free< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) + +} // namespace detail +namespace traits { + +template +struct execute_free_default : + detail::execute_free_trait +{ +}; + +template +struct execute_free : + execute_free_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_EXECUTE_FREE_HPP diff --git a/include/boost/asio/traits/execute_member.hpp b/include/boost/asio/traits/execute_member.hpp new file mode 100644 index 00000000..87b43ce4 --- /dev/null +++ b/include/boost/asio/traits/execute_member.hpp @@ -0,0 +1,110 @@ +// +// traits/execute_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_EXECUTE_MEMBER_HPP +#define BOOST_ASIO_TRAITS_EXECUTE_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct execute_member_default; + +template +struct execute_member; + +} // namespace traits +namespace detail { + +struct no_execute_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member_trait : no_execute_member +{ +}; + +template +struct execute_member_trait().execute(declval())) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype( + declval().execute(declval())); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( + declval().execute(declval()))); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_execute_member, + traits::execute_member< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template +struct execute_member_default : + detail::execute_member_trait +{ +}; + +template +struct execute_member : + execute_member_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_EXECUTE_MEMBER_HPP diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 index dc0f6a1c..52e2b27d 100644 --- a/test/execution/Jamfile.v2 +++ b/test/execution/Jamfile.v2 @@ -41,5 +41,6 @@ project ; test-suite "asio" : + [ run execute.cpp ] [ run invocable_archetype.cpp ] ; diff --git a/test/execution/execute.cpp b/test/execution/execute.cpp new file mode 100644 index 00000000..d411f7f2 --- /dev/null +++ b/test/execution/execute.cpp @@ -0,0 +1,301 @@ +// +// execute.cpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include "../unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +namespace exec = boost::asio::execution; + +struct no_execute +{ +}; + +struct const_member_execute +{ + template + void execute(BOOST_ASIO_MOVE_ARG(F) f) const + { + typename boost::asio::decay::type tmp(BOOST_ASIO_MOVE_CAST(F)(f)); + tmp(); + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +template +struct execute_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +struct free_execute_const_executor +{ + template + friend void execute(const free_execute_const_executor&, + BOOST_ASIO_MOVE_ARG(F) f) + { + typename boost::asio::decay::type tmp(BOOST_ASIO_MOVE_CAST(F)(f)); + tmp(); + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +template +struct execute_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) + +#if defined(BOOST_ASIO_HAS_MOVE) + +// Support for rvalue references is required in order to use the execute +// customisation point with non-const member functions and free functions +// taking non-const arguments. + +struct non_const_member_execute +{ + template + void execute(BOOST_ASIO_MOVE_ARG(F) f) + { + typename boost::asio::decay::type tmp(BOOST_ASIO_MOVE_CAST(F)(f)); + tmp(); + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +template +struct execute_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct execute_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct execute_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +struct free_execute_non_const_executor +{ + template + friend void execute(free_execute_non_const_executor&, + BOOST_ASIO_MOVE_ARG(F) f) + { + typename boost::asio::decay::type tmp(BOOST_ASIO_MOVE_CAST(F)(f)); + tmp(); + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +template +struct execute_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct execute_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +template +struct execute_free +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) + +#endif // defined(BOOST_ASIO_HAS_MOVE) + +void test_can_execute() +{ + BOOST_ASIO_CONSTEXPR bool b1 = exec::can_execute< + no_execute&, exec::invocable_archetype>::value; + BOOST_ASIO_CHECK(b1 == false); + + BOOST_ASIO_CONSTEXPR bool b2 = exec::can_execute< + const no_execute&, exec::invocable_archetype>::value; + BOOST_ASIO_CHECK(b2 == false); + + BOOST_ASIO_CONSTEXPR bool b3 = exec::can_execute< + const_member_execute&, exec::invocable_archetype>::value; + BOOST_ASIO_CHECK(b3 == true); + + BOOST_ASIO_CONSTEXPR bool b4 = exec::can_execute< + const const_member_execute&, exec::invocable_archetype>::value; + BOOST_ASIO_CHECK(b4 == true); + + BOOST_ASIO_CONSTEXPR bool b5 = exec::can_execute< + free_execute_const_executor&, exec::invocable_archetype>::value; + BOOST_ASIO_CHECK(b5 == true); + + BOOST_ASIO_CONSTEXPR bool b6 = exec::can_execute< + const free_execute_const_executor&, exec::invocable_archetype>::value; + BOOST_ASIO_CHECK(b6 == true); + +#if defined(BOOST_ASIO_HAS_MOVE) + BOOST_ASIO_CONSTEXPR bool b7 = exec::can_execute< + non_const_member_execute&, exec::invocable_archetype>::value; + BOOST_ASIO_CHECK(b7 == true); + + BOOST_ASIO_CONSTEXPR bool b8 = exec::can_execute< + const non_const_member_execute&, exec::invocable_archetype>::value; + BOOST_ASIO_CHECK(b8 == false); + + BOOST_ASIO_CONSTEXPR bool b9 = exec::can_execute< + free_execute_non_const_executor&, exec::invocable_archetype>::value; + BOOST_ASIO_CHECK(b9 == true); + + BOOST_ASIO_CONSTEXPR bool b10 = exec::can_execute< + const free_execute_non_const_executor&, exec::invocable_archetype>::value; + BOOST_ASIO_CHECK(b10 == false); +#endif // defined(BOOST_ASIO_HAS_MOVE) +} + +void increment(int* count) +{ + ++(*count); +} + +void test_execute() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + + int count = 0; + const_member_execute ex1 = {}; + exec::execute(ex1, bindns::bind(&increment, &count)); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + const const_member_execute ex2 = {}; + exec::execute(ex2, bindns::bind(&increment, &count)); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + exec::execute(const_member_execute(), bindns::bind(&increment, &count)); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + free_execute_const_executor ex3 = {}; + exec::execute(ex3, bindns::bind(&increment, &count)); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + const free_execute_const_executor ex4 = {}; + exec::execute(ex4, bindns::bind(&increment, &count)); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + exec::execute(free_execute_const_executor(), + bindns::bind(&increment, &count)); + BOOST_ASIO_CHECK(count == 1); + +#if defined(BOOST_ASIO_HAS_MOVE) + count = 0; + non_const_member_execute ex5 = {}; + exec::execute(ex5, bindns::bind(&increment, &count)); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + free_execute_non_const_executor ex6 = {}; + exec::execute(ex6, bindns::bind(&increment, &count)); + BOOST_ASIO_CHECK(count == 1); +#endif // defined(BOOST_ASIO_HAS_MOVE) +} + +BOOST_ASIO_TEST_SUITE +( + "blocking", + BOOST_ASIO_TEST_CASE(test_can_execute) + BOOST_ASIO_TEST_CASE(test_execute) +) From 834c5bdc8a573a44d140c8d699ba0355c7ffccfd Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:50:34 +1000 Subject: [PATCH 48/90] Add execution::executor concept and execution::is_executor trait. --- include/boost/asio.hpp | 1 + include/boost/asio/detail/type_traits.hpp | 14 +++ include/boost/asio/execution/executor.hpp | 92 ++++++++++++++++ .../boost/asio/traits/equality_comparable.hpp | 102 ++++++++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 include/boost/asio/execution/executor.hpp create mode 100644 include/boost/asio/traits/equality_comparable.hpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 4197bb40..3f0e153d 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/detail/type_traits.hpp b/include/boost/asio/detail/type_traits.hpp index 25dc82c4..7d3dab85 100644 --- a/include/boost/asio/detail/type_traits.hpp +++ b/include/boost/asio/detail/type_traits.hpp @@ -23,11 +23,15 @@ # include # include # include +# include +# include # include # include # include # include # include +# include +# include # include # include # include @@ -52,7 +56,11 @@ using std::is_base_of; using std::is_class; using std::is_const; using std::is_convertible; +using std::is_copy_constructible; +using std::is_destructible; using std::is_function; +using std::is_nothrow_copy_constructible; +using std::is_nothrow_destructible; using std::is_same; using std::remove_pointer; using std::remove_reference; @@ -77,7 +85,13 @@ using boost::is_base_of; using boost::is_class; using boost::is_const; using boost::is_convertible; +using boost::is_copy_constructible; +using boost::is_destructible; using boost::is_function; +template +struct is_nothrow_copy_constructible : boost::has_nothrow_copy {}; +template +struct is_nothrow_destructible : boost::has_nothrow_destructor {}; using boost::is_same; using boost::remove_pointer; using boost::remove_reference; diff --git a/include/boost/asio/execution/executor.hpp b/include/boost/asio/execution/executor.hpp new file mode 100644 index 00000000..f9842a21 --- /dev/null +++ b/include/boost/asio/execution/executor.hpp @@ -0,0 +1,92 @@ +// +// execution/executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_EXECUTOR_HPP +#define BOOST_ASIO_EXECUTION_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) \ + && defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) \ + && defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) +# define BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) + // && defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + // && defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +#include + +namespace boost { +namespace asio { +namespace execution { + +/// The is_executor trait detects whether a type T satisfies the +/// execution::executor concept. +/** + * Class template @c is_executor is a UnaryTypeTrait that is derived from @c + * true_type if the type @c T meets the concept definition for an executor, + * otherwise @c false_type. + */ +template +struct is_executor : +#if defined(GENERATING_DOCUMENTATION) + integral_constant +#else // defined(GENERATING_DOCUMENTATION) + integral_constant::value +#if defined(BOOST_ASIO_HAS_NOEXCEPT) + && is_nothrow_copy_constructible::value + && is_nothrow_destructible::value +#else // defined(BOOST_ASIO_HAS_NOEXCEPT) + && is_copy_constructible::value + && is_destructible::value +#endif // defined(BOOST_ASIO_HAS_NOEXCEPT) + && traits::equality_comparable::type>::is_valid + && traits::equality_comparable::type>::is_noexcept + > +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +BOOST_ASIO_CONSTEXPR const bool is_executor_v = is_executor::value; + +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_CONCEPTS) + +template +BOOST_ASIO_CONCEPT executor = is_executor::value; + +#define BOOST_ASIO_EXECUTION_EXECUTOR ::boost::asio::execution::executor + +#else // defined(BOOST_ASIO_HAS_CONCEPTS) + +#define BOOST_ASIO_EXECUTION_EXECUTOR typename + +#endif // defined(BOOST_ASIO_HAS_CONCEPTS) + +} // namespace execution +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_EXECUTOR_HPP diff --git a/include/boost/asio/traits/equality_comparable.hpp b/include/boost/asio/traits/equality_comparable.hpp new file mode 100644 index 00000000..c49a21f0 --- /dev/null +++ b/include/boost/asio/traits/equality_comparable.hpp @@ -0,0 +1,102 @@ +// +// traits/equality_comparable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_EQUALITY_COMPARABLE_HPP +#define BOOST_ASIO_TRAITS_EQUALITY_COMPARABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +namespace boost { +namespace asio { +namespace traits { + +template +struct equality_comparable_default; + +template +struct equality_comparable; + +} // namespace traits +namespace detail { + +struct no_equality_comparable +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template +struct equality_comparable_trait : no_equality_comparable +{ +}; + +template +struct equality_comparable_trait(declval() == declval()), + static_cast(declval() != declval()) + ) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + noexcept(declval() == declval()) + && noexcept(declval() != declval())); +}; + +#else // defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +template +struct equality_comparable_trait : + conditional< + is_same::type>::value, + no_equality_comparable, + traits::equality_comparable::type> + >::type +{ +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) + +} // namespace detail +namespace traits { + +template +struct equality_comparable_default : detail::equality_comparable_trait +{ +}; + +template +struct equality_comparable : equality_comparable_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_TRAITS_EQUALITY_COMPARABLE_HPP From 36686f07a1e3932045ee5f4a2ad1ff23d255d875 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:51:57 +1000 Subject: [PATCH 49/90] Add execution::blocking property. --- include/boost/asio.hpp | 1 + include/boost/asio/detail/config.hpp | 42 + include/boost/asio/execution/blocking.hpp | 962 ++++++++ .../traits/query_static_constexpr_member.hpp | 110 + test/execution/Jamfile.v2 | 1 + test/execution/blocking.cpp | 2000 +++++++++++++++++ 6 files changed, 3116 insertions(+) create mode 100644 include/boost/asio/execution/blocking.hpp create mode 100644 include/boost/asio/traits/query_static_constexpr_member.hpp create mode 100644 test/execution/blocking.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 3f0e153d..7fbb0b08 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp index 65714860..e113ff2d 100644 --- a/include/boost/asio/detail/config.hpp +++ b/include/boost/asio/detail/config.hpp @@ -250,6 +250,25 @@ static const type assignment # endif // defined(BOOST_ASIO_HAS_CONSTEXPR) #endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR) +#if !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) +# if defined(BOOST_ASIO_HAS_CONSTEXPR) +# if defined(__GNUC__) +# if (__GNUC__ >= 8) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# else // (__GNUC__ >= 8) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // (__GNUC__ >= 8) +# else // defined(__GNUC__) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# endif // defined(__GNUC__) +# else // defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) // Support noexcept on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_NOEXCEPT) @@ -440,6 +459,29 @@ # endif // !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +// Support SFINAE use of constant expressions on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201703) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +#endif // !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) + // Enable workarounds for lack of working expression SFINAE. #if !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # if !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) diff --git a/include/boost/asio/execution/blocking.hpp b/include/boost/asio/execution/blocking.hpp new file mode 100644 index 00000000..2b59e1b4 --- /dev/null +++ b/include/boost/asio/execution/blocking.hpp @@ -0,0 +1,962 @@ +// +// execution/blocking.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_BLOCKING_HPP +#define BOOST_ASIO_EXECUTION_BLOCKING_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe what guarantees an executor makes about the blocking +/// behaviour of their execution functions. +struct blocking_t +{ + /// The blocking_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The top-level blocking_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level blocking_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// A sub-property that indicates that invocation of an executor's execution + /// function may block pending completion of one or more invocations of the + /// submitted function object. + struct possibly_t + { + /// The blocking_t::possibly_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The blocking_t::possibly_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_t::possibly_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// Default constructor. + constexpr possibly_t(); + + /// Get the value associated with a property object. + /** + * @returns possibly_t(); + */ + static constexpr blocking_t value(); + }; + + /// A sub-property that indicates that invocation of an executor's execution + /// function shall block until completion of all invocations of the submitted + /// function object. + struct always_t + { + /// The blocking_t::always_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The blocking_t::always_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_t::always_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// Default constructor. + constexpr always_t(); + + /// Get the value associated with a property object. + /** + * @returns always_t(); + */ + static constexpr blocking_t value(); + }; + + /// A sub-property that indicates that invocation of an executor's execution + /// function shall not block pending completion of the invocations of the + /// submitted function object. + struct never_t + { + /// The blocking_t::never_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The blocking_t::never_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_t::never_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_t polymorphic_query_result_type; + + /// Default constructor. + constexpr never_t(); + + /// Get the value associated with a property object. + /** + * @returns never_t(); + */ + static constexpr blocking_t value(); + }; + + /// A special value used for accessing the blocking_t::possibly_t property. + static constexpr possibly_t possibly; + + /// A special value used for accessing the blocking_t::always_t property. + static constexpr always_t always; + + /// A special value used for accessing the blocking_t::never_t property. + static constexpr never_t never; + + /// Default constructor. + constexpr blocking_t(); + + /// Construct from a sub-property value. + constexpr blocking_t(possibly_t); + + /// Construct from a sub-property value. + constexpr blocking_t(always_t); + + /// Construct from a sub-property value. + constexpr blocking_t(never_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const blocking_t& a, const blocking_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const blocking_t& a, const blocking_t& b) noexcept; +}; + +/// A special value used for accessing the blocking_t property. +constexpr blocking_t blocking; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace blocking { + +template struct possibly_t; +template struct always_t; +template struct never_t; + +} // namespace blocking + +template +struct blocking_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef blocking_t polymorphic_query_result_type; + + typedef detail::blocking::possibly_t possibly_t; + typedef detail::blocking::always_t always_t; + typedef detail::blocking::never_t never_t; + + BOOST_ASIO_CONSTEXPR blocking_t() + : value_(-1) + { + } + + BOOST_ASIO_CONSTEXPR blocking_t(possibly_t) + : value_(0) + { + } + + BOOST_ASIO_CONSTEXPR blocking_t(always_t) + : value_(1) + { + } + + BOOST_ASIO_CONSTEXPR blocking_t(never_t) + : value_(2) + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = blocking_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const blocking_t& a, const blocking_t& b) + { + return a.value_ == b.value_; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const blocking_t& a, const blocking_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_blocking_t + { + BOOST_ASIO_CONSTEXPR convertible_from_blocking_t(blocking_t) {} + }; + + template + friend BOOST_ASIO_CONSTEXPR blocking_t query( + const Executor& ex, convertible_from_blocking_t, + typename enable_if< + can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::possibly_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, possibly_t()); + } + + template + friend BOOST_ASIO_CONSTEXPR blocking_t query( + const Executor& ex, convertible_from_blocking_t, + typename enable_if< + !can_query::value + && can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::always_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, always_t()); + } + + template + friend BOOST_ASIO_CONSTEXPR blocking_t query( + const Executor& ex, convertible_from_blocking_t, + typename enable_if< + !can_query::value + && !can_query::value + && can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::never_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, never_t()); + } + + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(possibly_t, possibly); + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(always_t, always); + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(never_t, never); + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) + static const blocking_t instance; +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T blocking_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +template +const blocking_t blocking_t::instance; +#endif + +template +const typename blocking_t::possibly_t blocking_t::possibly; + +template +const typename blocking_t::always_t blocking_t::always; + +template +const typename blocking_t::never_t blocking_t::never; + +namespace blocking { + +template +struct possibly_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef blocking_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR possibly_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template + static BOOST_ASIO_CONSTEXPR possibly_t static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query >::value + && !can_query >::value + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return possibly_t(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = possibly_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR blocking_t value() + { + return possibly_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const possibly_t&, const possibly_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const possibly_t&, const possibly_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const possibly_t&, const always_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const possibly_t&, const always_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const possibly_t&, const never_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const possibly_t&, const never_t&) + { + return true; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T possibly_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct always_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef blocking_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR always_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = always_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR blocking_t value() + { + return always_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const always_t&, const always_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const always_t&, const always_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const always_t&, const possibly_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const always_t&, const possibly_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const always_t&, const never_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const always_t&, const never_t&) + { + return true; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T always_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct never_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef blocking_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR never_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = never_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR blocking_t value() + { + return never_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const never_t&, const never_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const never_t&, const never_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const never_t&, const possibly_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const never_t&, const possibly_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const never_t&, const always_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const never_t&, const always_t&) + { + return true; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T never_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace blocking +} // namespace detail + +typedef detail::blocking_t<> blocking_t; + +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr blocking_t blocking; +#else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const blocking_t& blocking = blocking_t::instance; } +#endif + +} // namespace execution + +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::blocking_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::blocking_t result_type; +}; + +template +struct query_free_default::value + && !can_query::value + && can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::blocking_t result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + && !can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::blocking_t::possibly_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::blocking_t::possibly_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::blocking_t::always_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::blocking_t::never_t>::value)); +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_BLOCKING_HPP diff --git a/include/boost/asio/traits/query_static_constexpr_member.hpp b/include/boost/asio/traits/query_static_constexpr_member.hpp new file mode 100644 index 00000000..582e7f9a --- /dev/null +++ b/include/boost/asio/traits/query_static_constexpr_member.hpp @@ -0,0 +1,110 @@ +// +// traits/query_static_constexpr_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP +#define BOOST_ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_NOEXCEPT) \ + && defined(BOOST_ASIO_HAS_CONSTEXPR) \ + && defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# define BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT 1 +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_NOEXCEPT) + // && defined(BOOST_ASIO_HAS_CONSTEXPR) + // && defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +#include + +namespace boost { +namespace asio { +namespace traits { + +template +struct query_static_constexpr_member_default; + +template +struct query_static_constexpr_member; + +} // namespace traits +namespace detail { + +struct no_query_static_constexpr_member +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); +}; + +template +struct query_static_constexpr_member_trait : + conditional< + is_same::type>::value + && is_same::type>::value, + no_query_static_constexpr_member, + traits::query_static_constexpr_member< + typename decay::type, + typename decay::type> + >::type +{ +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member_trait(T::query(Property{})), true) + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + + using result_type = decltype(T::query(Property{})); + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + noexcept(T::query(Property{}))); + + static BOOST_ASIO_CONSTEXPR result_type value() noexcept(is_noexcept) + { + return T::query(Property{}); + } +}; + +#endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +} // namespace detail +namespace traits { + +template +struct query_static_constexpr_member_default : + detail::query_static_constexpr_member_trait +{ +}; + +template +struct query_static_constexpr_member : + query_static_constexpr_member_default +{ +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 index 52e2b27d..f248be34 100644 --- a/test/execution/Jamfile.v2 +++ b/test/execution/Jamfile.v2 @@ -41,6 +41,7 @@ project ; test-suite "asio" : + [ run blocking.cpp ] [ run execute.cpp ] [ run invocable_archetype.cpp ] ; diff --git a/test/execution/blocking.cpp b/test/execution/blocking.cpp new file mode 100644 index 00000000..d9bbbd4f --- /dev/null +++ b/test/execution/blocking.cpp @@ -0,0 +1,2000 @@ +// +// blocking.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include +#include +#include "../unit_test.hpp" + +namespace exec = boost::asio::execution; + +typedef exec::blocking_t s; +typedef exec::blocking_t::possibly_t n1; +typedef exec::blocking_t::always_t n2; +typedef exec::blocking_t::never_t n3; + +struct ex_nq_nr +{ + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template <> +struct is_executor : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct ex_cq_nr +{ + static BOOST_ASIO_CONSTEXPR ResultType query(ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + ex_cq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef Result result_type; // Must return raw result type. + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return Result(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_nr +{ + ResultType query(ParamType) const BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_nr +{ + friend ResultType query(const ex_fq_nr&, ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + CurrentType query(OtherType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + ex_mq_mr require( + OtherType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend CurrentType query(const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +void test_can_query() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_query() +{ + exec::blocking_t result1 = boost::asio::query(Executor(), Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); + + Executor ex1 = {}; + exec::blocking_t result2 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result2 == ExpectedResult()); + + const Executor ex2 = {}; + exec::blocking_t result3 = boost::asio::query(ex2, Param()); + BOOST_ASIO_CHECK(result3 == ExpectedResult()); +} + +template +void test_constexpr_query() +{ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) + constexpr Executor ex1 = {}; + constexpr exec::blocking_t result1 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); +#endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +} + +template +void test_can_require() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_require() +{ + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(Executor(), Param()), + Param()) == ExpectedResult()); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex1, Param()), + Param()) == ExpectedResult()); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex2, Param()), + Param()) == ExpectedResult()); +} + +template +void test_can_prefer() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_prefer() +{ + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(Executor(), Param()), + s())) == s(ExpectedResult())); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex1, Param()), + s())) == s(ExpectedResult())); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex2, Param()), + s())) == s(ExpectedResult())); +} + +void test_vars() +{ + BOOST_ASIO_CHECK(s() == exec::blocking); + BOOST_ASIO_CHECK(n1() == exec::blocking.possibly); + BOOST_ASIO_CHECK(n2() == exec::blocking.always); + BOOST_ASIO_CHECK(n3() == exec::blocking.never); +} + +BOOST_ASIO_TEST_SUITE +( + "blocking", + + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + + BOOST_ASIO_TEST_CASE3(test_query) + BOOST_ASIO_TEST_CASE3(test_query) + + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + + BOOST_ASIO_TEST_CASE3(test_require) + + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + + BOOST_ASIO_TEST_CASE3(test_prefer) + BOOST_ASIO_TEST_CASE3(test_prefer) + BOOST_ASIO_TEST_CASE3(test_prefer) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE(test_vars) +) From 50e3e1798d48674dd36c3a528766888461a2e5b0 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:52:33 +1000 Subject: [PATCH 50/90] Add execution::outstanding_work property. --- include/boost/asio.hpp | 1 + .../boost/asio/execution/outstanding_work.hpp | 699 +++++++++ test/execution/Jamfile.v2 | 1 + test/execution/outstanding_work.cpp | 1272 +++++++++++++++++ 4 files changed, 1973 insertions(+) create mode 100644 include/boost/asio/execution/outstanding_work.hpp create mode 100644 test/execution/outstanding_work.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 7fbb0b08..b760cc4b 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution/outstanding_work.hpp b/include/boost/asio/execution/outstanding_work.hpp new file mode 100644 index 00000000..19ba4c40 --- /dev/null +++ b/include/boost/asio/execution/outstanding_work.hpp @@ -0,0 +1,699 @@ +// +// execution/outstanding_work.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_OUTSTANDING_WORK_HPP +#define BOOST_ASIO_EXECUTION_OUTSTANDING_WORK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe whether task submission is likely in the future. +struct outstanding_work_t +{ + /// The outstanding_work_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The top-level outstanding_work_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level outstanding_work_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef outstanding_work_t polymorphic_query_result_type; + + /// A sub-property that indicates that the executor does not represent likely + /// future submission of a function object. + struct untracked_t + { + /// The outstanding_work_t::untracked_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The outstanding_work_t::untracked_t property can be required. + static constexpr bool is_requirable = true; + + /// The outstanding_work_t::untracked_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef outstanding_work_t polymorphic_query_result_type; + + /// Default constructor. + constexpr untracked_t(); + + /// Get the value associated with a property object. + /** + * @returns untracked_t(); + */ + static constexpr outstanding_work_t value(); + }; + + /// A sub-property that indicates that the executor represents likely + /// future submission of a function object. + struct tracked_t + { + /// The outstanding_work_t::tracked_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The outstanding_work_t::tracked_t property can be required. + static constexpr bool is_requirable = true; + + /// The outstanding_work_t::tracked_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef outstanding_work_t polymorphic_query_result_type; + + /// Default constructor. + constexpr tracked_t(); + + /// Get the value associated with a property object. + /** + * @returns tracked_t(); + */ + static constexpr outstanding_work_t value(); + }; + + /// A special value used for accessing the outstanding_work_t::untracked_t + /// property. + static constexpr untracked_t untracked; + + /// A special value used for accessing the outstanding_work_t::tracked_t + /// property. + static constexpr tracked_t tracked; + + /// Default constructor. + constexpr outstanding_work_t(); + + /// Construct from a sub-property value. + constexpr outstanding_work_t(untracked_t); + + /// Construct from a sub-property value. + constexpr outstanding_work_t(tracked_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const outstanding_work_t& a, const outstanding_work_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const outstanding_work_t& a, const outstanding_work_t& b) noexcept; +}; + +/// A special value used for accessing the outstanding_work_t property. +constexpr outstanding_work_t outstanding_work; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace outstanding_work { + +template struct untracked_t; +template struct tracked_t; + +} // namespace outstanding_work + +template +struct outstanding_work_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef outstanding_work_t polymorphic_query_result_type; + + typedef detail::outstanding_work::untracked_t untracked_t; + typedef detail::outstanding_work::tracked_t tracked_t; + + BOOST_ASIO_CONSTEXPR outstanding_work_t() + : value_(-1) + { + } + + BOOST_ASIO_CONSTEXPR outstanding_work_t(untracked_t) + : value_(0) + { + } + + BOOST_ASIO_CONSTEXPR outstanding_work_t(tracked_t) + : value_(1) + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member< + T, outstanding_work_t>::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member< + T, outstanding_work_t + >::is_noexcept)) + { + return traits::query_static_constexpr_member< + T, outstanding_work_t>::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member< + T, outstanding_work_t>::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member< + T, outstanding_work_t>::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = outstanding_work_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const outstanding_work_t& a, const outstanding_work_t& b) + { + return a.value_ == b.value_; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const outstanding_work_t& a, const outstanding_work_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_outstanding_work_t + { + BOOST_ASIO_CONSTEXPR convertible_from_outstanding_work_t(outstanding_work_t) + { + } + }; + + template + friend BOOST_ASIO_CONSTEXPR outstanding_work_t query( + const Executor& ex, convertible_from_outstanding_work_t, + typename enable_if< + can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::untracked_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, untracked_t()); + } + + template + friend BOOST_ASIO_CONSTEXPR outstanding_work_t query( + const Executor& ex, convertible_from_outstanding_work_t, + typename enable_if< + !can_query::value + && can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::tracked_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, tracked_t()); + } + + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(untracked_t, untracked); + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(tracked_t, tracked); + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) + static const outstanding_work_t instance; +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T outstanding_work_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +template +const outstanding_work_t outstanding_work_t::instance; +#endif + +template +const typename outstanding_work_t::untracked_t +outstanding_work_t::untracked; + +template +const typename outstanding_work_t::tracked_t +outstanding_work_t::tracked; + +namespace outstanding_work { + +template +struct untracked_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef outstanding_work_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR untracked_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template + static BOOST_ASIO_CONSTEXPR untracked_t static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query >::value + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return untracked_t(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = untracked_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR outstanding_work_t value() + { + return untracked_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const untracked_t&, const untracked_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const untracked_t&, const untracked_t&) + { + return false; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T untracked_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct tracked_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef outstanding_work_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR tracked_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = tracked_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR outstanding_work_t value() + { + return tracked_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const tracked_t&, const tracked_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const tracked_t&, const tracked_t&) + { + return false; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T tracked_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace outstanding_work +} // namespace detail + +typedef detail::outstanding_work_t<> outstanding_work_t; + +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr outstanding_work_t outstanding_work; +#else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const outstanding_work_t& + outstanding_work = outstanding_work_t::instance; } +#endif + +} // namespace execution + +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::outstanding_work_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::outstanding_work_t result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::outstanding_work_t::untracked_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::outstanding_work_t::untracked_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::outstanding_work_t::tracked_t>::value)); +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_OUTSTANDING_WORK_HPP diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 index f248be34..8a743b72 100644 --- a/test/execution/Jamfile.v2 +++ b/test/execution/Jamfile.v2 @@ -44,4 +44,5 @@ test-suite "asio" : [ run blocking.cpp ] [ run execute.cpp ] [ run invocable_archetype.cpp ] + [ run outstanding_work.cpp ] ; diff --git a/test/execution/outstanding_work.cpp b/test/execution/outstanding_work.cpp new file mode 100644 index 00000000..076297af --- /dev/null +++ b/test/execution/outstanding_work.cpp @@ -0,0 +1,1272 @@ +// +// outstanding_work.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include +#include +#include "../unit_test.hpp" + +namespace exec = boost::asio::execution; + +typedef exec::outstanding_work_t s; +typedef exec::outstanding_work_t::untracked_t n1; +typedef exec::outstanding_work_t::tracked_t n2; + +struct ex_nq_nr +{ + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template <> +struct is_executor : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct ex_cq_nr +{ + static BOOST_ASIO_CONSTEXPR ResultType query(ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + ex_cq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef Result result_type; // Must return raw result type. + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return Result(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_nr +{ + ResultType query(ParamType) const BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_nr +{ + friend ResultType query(const ex_fq_nr&, ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + CurrentType query(OtherType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + ex_mq_mr require( + OtherType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend CurrentType query(const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +void test_can_query() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_query() +{ + exec::outstanding_work_t result1 = boost::asio::query(Executor(), Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); + + Executor ex1 = {}; + exec::outstanding_work_t result2 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result2 == ExpectedResult()); + + const Executor ex2 = {}; + exec::outstanding_work_t result3 = boost::asio::query(ex2, Param()); + BOOST_ASIO_CHECK(result3 == ExpectedResult()); +} + +template +void test_constexpr_query() +{ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) + constexpr Executor ex1 = {}; + constexpr exec::outstanding_work_t result1 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); +#endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +} + +template +void test_can_require() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_require() +{ + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(Executor(), Param()), + Param()) == ExpectedResult()); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex1, Param()), + Param()) == ExpectedResult()); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex2, Param()), + Param()) == ExpectedResult()); +} + +template +void test_can_prefer() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_prefer() +{ + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(Executor(), Param()), + s())) == s(ExpectedResult())); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex1, Param()), + s())) == s(ExpectedResult())); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex2, Param()), + s())) == s(ExpectedResult())); +} + +void test_vars() +{ + BOOST_ASIO_CHECK(s() == exec::outstanding_work); + BOOST_ASIO_CHECK(n1() == exec::outstanding_work.untracked); + BOOST_ASIO_CHECK(n2() == exec::outstanding_work.tracked); +} + +BOOST_ASIO_TEST_SUITE +( + "outstanding_work", + + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + + BOOST_ASIO_TEST_CASE3(test_query) + BOOST_ASIO_TEST_CASE3(test_query) + + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + + BOOST_ASIO_TEST_CASE3(test_require) + + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + + BOOST_ASIO_TEST_CASE3(test_prefer) + BOOST_ASIO_TEST_CASE3(test_prefer) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE(test_vars) +) From 3d5209fa19c496fa5cf41d40c0d2c042ddbc66da Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:53:15 +1000 Subject: [PATCH 51/90] Add execution::mapping property. --- include/boost/asio.hpp | 1 + include/boost/asio/execution/mapping.hpp | 888 ++++++++++ test/execution/Jamfile.v2 | 1 + test/execution/mapping.cpp | 2000 ++++++++++++++++++++++ 4 files changed, 2890 insertions(+) create mode 100644 include/boost/asio/execution/mapping.hpp create mode 100644 test/execution/mapping.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index b760cc4b..2e996797 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution/mapping.hpp b/include/boost/asio/execution/mapping.hpp new file mode 100644 index 00000000..b28ccd6a --- /dev/null +++ b/include/boost/asio/execution/mapping.hpp @@ -0,0 +1,888 @@ +// +// execution/mapping.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_MAPPING_HPP +#define BOOST_ASIO_EXECUTION_MAPPING_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe what guarantees an executor makes about the mapping +/// of execution agents on to threads of execution. +struct mapping_t +{ + /// The mapping_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The top-level mapping_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level mapping_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// A sub-property that indicates that execution agents are mapped on to + /// threads of execution. + struct thread_t + { + /// The mapping_t::thread_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The mapping_t::thread_t property can be required. + static constexpr bool is_requirable = true; + + /// The mapping_t::thread_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// Default constructor. + constexpr thread_t(); + + /// Get the value associated with a property object. + /** + * @returns thread_t(); + */ + static constexpr mapping_t value(); + }; + + /// A sub-property that indicates that execution agents are mapped on to + /// new threads of execution. + struct new_thread_t + { + /// The mapping_t::new_thread_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The mapping_t::new_thread_t property can be required. + static constexpr bool is_requirable = true; + + /// The mapping_t::new_thread_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// Default constructor. + constexpr new_thread_t(); + + /// Get the value associated with a property object. + /** + * @returns new_thread_t(); + */ + static constexpr mapping_t value(); + }; + + /// A sub-property that indicates that the mapping of execution agents is + /// implementation-defined. + struct other_t + { + /// The mapping_t::other_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The mapping_t::other_t property can be required. + static constexpr bool is_requirable = true; + + /// The mapping_t::other_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef mapping_t polymorphic_query_result_type; + + /// Default constructor. + constexpr other_t(); + + /// Get the value associated with a property object. + /** + * @returns other_t(); + */ + static constexpr mapping_t value(); + }; + + /// A special value used for accessing the mapping_t::thread_t property. + static constexpr thread_t thread; + + /// A special value used for accessing the mapping_t::new_thread_t property. + static constexpr new_thread_t new_thread; + + /// A special value used for accessing the mapping_t::other_t property. + static constexpr other_t other; + + /// Default constructor. + constexpr mapping_t(); + + /// Construct from a sub-property value. + constexpr mapping_t(thread_t); + + /// Construct from a sub-property value. + constexpr mapping_t(new_thread_t); + + /// Construct from a sub-property value. + constexpr mapping_t(other_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const mapping_t& a, const mapping_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const mapping_t& a, const mapping_t& b) noexcept; +}; + +/// A special value used for accessing the mapping_t property. +constexpr mapping_t mapping; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace mapping { + +template struct thread_t; +template struct new_thread_t; +template struct other_t; + +} // namespace mapping + +template +struct mapping_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef mapping_t polymorphic_query_result_type; + + typedef detail::mapping::thread_t thread_t; + typedef detail::mapping::new_thread_t new_thread_t; + typedef detail::mapping::other_t other_t; + + BOOST_ASIO_CONSTEXPR mapping_t() + : value_(-1) + { + } + + BOOST_ASIO_CONSTEXPR mapping_t(thread_t) + : value_(0) + { + } + + BOOST_ASIO_CONSTEXPR mapping_t(new_thread_t) + : value_(1) + { + } + + BOOST_ASIO_CONSTEXPR mapping_t(other_t) + : value_(2) + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = mapping_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const mapping_t& a, const mapping_t& b) + { + return a.value_ == b.value_; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const mapping_t& a, const mapping_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_mapping_t + { + BOOST_ASIO_CONSTEXPR convertible_from_mapping_t(mapping_t) {} + }; + + template + friend BOOST_ASIO_CONSTEXPR mapping_t query( + const Executor& ex, convertible_from_mapping_t, + typename enable_if< + can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::thread_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, thread_t()); + } + + template + friend BOOST_ASIO_CONSTEXPR mapping_t query( + const Executor& ex, convertible_from_mapping_t, + typename enable_if< + !can_query::value + && can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::new_thread_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, new_thread_t()); + } + + template + friend BOOST_ASIO_CONSTEXPR mapping_t query( + const Executor& ex, convertible_from_mapping_t, + typename enable_if< + !can_query::value + && !can_query::value + && can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::other_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, other_t()); + } + + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(thread_t, thread); + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(new_thread_t, new_thread); + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(other_t, other); + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) + static const mapping_t instance; +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T mapping_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +template +const mapping_t mapping_t::instance; +#endif + +template +const typename mapping_t::thread_t mapping_t::thread; + +template +const typename mapping_t::new_thread_t mapping_t::new_thread; + +template +const typename mapping_t::other_t mapping_t::other; + +namespace mapping { + +template +struct thread_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef mapping_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR thread_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template + static BOOST_ASIO_CONSTEXPR thread_t static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query >::value + && !can_query >::value + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return thread_t(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = thread_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR mapping_t value() + { + return thread_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const thread_t&, const thread_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const thread_t&, const thread_t&) + { + return false; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T thread_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct new_thread_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef mapping_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR new_thread_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = new_thread_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR mapping_t value() + { + return new_thread_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const new_thread_t&, const new_thread_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const new_thread_t&, const new_thread_t&) + { + return false; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T new_thread_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct other_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef mapping_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR other_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = other_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR mapping_t value() + { + return other_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const other_t&, const other_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const other_t&, const other_t&) + { + return false; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T other_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace mapping +} // namespace detail + +typedef detail::mapping_t<> mapping_t; + +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr mapping_t mapping; +#else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const mapping_t& mapping = mapping_t::instance; } +#endif + +} // namespace execution + +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::mapping_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::mapping_t result_type; +}; + +template +struct query_free_default::value + && !can_query::value + && can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::mapping_t result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + && !can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::mapping_t::thread_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::mapping_t::thread_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::mapping_t::new_thread_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::mapping_t::other_t>::value)); +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_MAPPING_HPP diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 index 8a743b72..79584d8b 100644 --- a/test/execution/Jamfile.v2 +++ b/test/execution/Jamfile.v2 @@ -44,5 +44,6 @@ test-suite "asio" : [ run blocking.cpp ] [ run execute.cpp ] [ run invocable_archetype.cpp ] + [ run mapping.cpp ] [ run outstanding_work.cpp ] ; diff --git a/test/execution/mapping.cpp b/test/execution/mapping.cpp new file mode 100644 index 00000000..39bfa5aa --- /dev/null +++ b/test/execution/mapping.cpp @@ -0,0 +1,2000 @@ +// +// mapping.cpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include +#include +#include "../unit_test.hpp" + +namespace exec = boost::asio::execution; + +typedef exec::mapping_t s; +typedef exec::mapping_t::thread_t n1; +typedef exec::mapping_t::new_thread_t n2; +typedef exec::mapping_t::other_t n3; + +struct ex_nq_nr +{ + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template <> +struct is_executor : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct ex_cq_nr +{ + static BOOST_ASIO_CONSTEXPR ResultType query(ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + ex_cq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef Result result_type; // Must return raw result type. + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return Result(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_nr +{ + ResultType query(ParamType) const BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_nr +{ + friend ResultType query(const ex_fq_nr&, ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + CurrentType query(OtherType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + ex_mq_mr require( + OtherType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend CurrentType query(const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +void test_can_query() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_query() +{ + exec::mapping_t result1 = boost::asio::query(Executor(), Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); + + Executor ex1 = {}; + exec::mapping_t result2 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result2 == ExpectedResult()); + + const Executor ex2 = {}; + exec::mapping_t result3 = boost::asio::query(ex2, Param()); + BOOST_ASIO_CHECK(result3 == ExpectedResult()); +} + +template +void test_constexpr_query() +{ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) + constexpr Executor ex1 = {}; + constexpr exec::mapping_t result1 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); +#endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +} + +template +void test_can_require() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_require() +{ + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(Executor(), Param()), + Param()) == ExpectedResult()); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex1, Param()), + Param()) == ExpectedResult()); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex2, Param()), + Param()) == ExpectedResult()); +} + +template +void test_can_prefer() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_prefer() +{ + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(Executor(), Param()), + s())) == s(ExpectedResult())); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex1, Param()), + s())) == s(ExpectedResult())); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex2, Param()), + s())) == s(ExpectedResult())); +} + +void test_vars() +{ + BOOST_ASIO_CHECK(s() == exec::mapping); + BOOST_ASIO_CHECK(n1() == exec::mapping.thread); + BOOST_ASIO_CHECK(n2() == exec::mapping.new_thread); + BOOST_ASIO_CHECK(n3() == exec::mapping.other); +} + +BOOST_ASIO_TEST_SUITE +( + "mapping", + + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + + BOOST_ASIO_TEST_CASE3(test_query) + BOOST_ASIO_TEST_CASE3(test_query) + + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + + BOOST_ASIO_TEST_CASE3(test_require) + + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + + BOOST_ASIO_TEST_CASE3(test_prefer) + BOOST_ASIO_TEST_CASE3(test_prefer) + BOOST_ASIO_TEST_CASE3(test_prefer) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE(test_vars) +) From bfeec7cd2bfb708749c108393141e8d9186207d1 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:54:30 +1000 Subject: [PATCH 52/90] Add execution::relationship property. --- include/boost/asio.hpp | 1 + include/boost/asio/execution/relationship.hpp | 699 +++++++++ test/execution/Jamfile.v2 | 1 + test/execution/relationship.cpp | 1272 +++++++++++++++++ 4 files changed, 1973 insertions(+) create mode 100644 include/boost/asio/execution/relationship.hpp create mode 100644 test/execution/relationship.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 2e996797..0b808f60 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution/relationship.hpp b/include/boost/asio/execution/relationship.hpp new file mode 100644 index 00000000..bc45f88b --- /dev/null +++ b/include/boost/asio/execution/relationship.hpp @@ -0,0 +1,699 @@ +// +// execution/relationship.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_RELATIONSHIP_HPP +#define BOOST_ASIO_EXECUTION_RELATIONSHIP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe whether submitted tasks represent continuations of +/// the calling context. +struct relationship_t +{ + /// The relationship_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The top-level relationship_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level relationship_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef relationship_t polymorphic_query_result_type; + + /// A sub-property that indicates that the executor does not represent a + /// continuation of the calling context. + struct fork_t + { + /// The relationship_t::fork_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The relationship_t::fork_t property can be required. + static constexpr bool is_requirable = true; + + /// The relationship_t::fork_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef relationship_t polymorphic_query_result_type; + + /// Default constructor. + constexpr fork_t(); + + /// Get the value associated with a property object. + /** + * @returns fork_t(); + */ + static constexpr relationship_t value(); + }; + + /// A sub-property that indicates that the executor represents a continuation + /// of the calling context. + struct continuation_t + { + /// The relationship_t::continuation_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The relationship_t::continuation_t property can be required. + static constexpr bool is_requirable = true; + + /// The relationship_t::continuation_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef relationship_t polymorphic_query_result_type; + + /// Default constructor. + constexpr continuation_t(); + + /// Get the value associated with a property object. + /** + * @returns continuation_t(); + */ + static constexpr relationship_t value(); + }; + + /// A special value used for accessing the relationship_t::fork_t property. + static constexpr fork_t fork; + + /// A special value used for accessing the relationship_t::continuation_t + /// property. + static constexpr continuation_t continuation; + + /// Default constructor. + constexpr relationship_t(); + + /// Construct from a sub-property value. + constexpr relationship_t(fork_t); + + /// Construct from a sub-property value. + constexpr relationship_t(continuation_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const relationship_t& a, const relationship_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const relationship_t& a, const relationship_t& b) noexcept; +}; + +/// A special value used for accessing the relationship_t property. +constexpr relationship_t relationship; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace relationship { + +template struct fork_t; +template struct continuation_t; + +} // namespace relationship + +template +struct relationship_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef relationship_t polymorphic_query_result_type; + + typedef detail::relationship::fork_t fork_t; + typedef detail::relationship::continuation_t continuation_t; + + BOOST_ASIO_CONSTEXPR relationship_t() + : value_(-1) + { + } + + BOOST_ASIO_CONSTEXPR relationship_t(fork_t) + : value_(0) + { + } + + BOOST_ASIO_CONSTEXPR relationship_t(continuation_t) + : value_(1) + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member< + T, relationship_t>::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member< + T, relationship_t + >::is_noexcept)) + { + return traits::query_static_constexpr_member< + T, relationship_t>::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member< + T, relationship_t>::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member< + T, relationship_t>::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = relationship_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const relationship_t& a, const relationship_t& b) + { + return a.value_ == b.value_; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const relationship_t& a, const relationship_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_relationship_t + { + BOOST_ASIO_CONSTEXPR convertible_from_relationship_t(relationship_t) + { + } + }; + + template + friend BOOST_ASIO_CONSTEXPR relationship_t query( + const Executor& ex, convertible_from_relationship_t, + typename enable_if< + can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::fork_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, fork_t()); + } + + template + friend BOOST_ASIO_CONSTEXPR relationship_t query( + const Executor& ex, convertible_from_relationship_t, + typename enable_if< + !can_query::value + && can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::continuation_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, continuation_t()); + } + + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(fork_t, fork); + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(continuation_t, continuation); + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) + static const relationship_t instance; +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T relationship_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +template +const relationship_t relationship_t::instance; +#endif + +template +const typename relationship_t::fork_t +relationship_t::fork; + +template +const typename relationship_t::continuation_t +relationship_t::continuation; + +namespace relationship { + +template +struct fork_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef relationship_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR fork_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template + static BOOST_ASIO_CONSTEXPR fork_t static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query >::value + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return fork_t(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = fork_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR relationship_t value() + { + return fork_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const fork_t&, const fork_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const fork_t&, const fork_t&) + { + return false; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T fork_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct continuation_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef relationship_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR continuation_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = continuation_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR relationship_t value() + { + return continuation_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const continuation_t&, const continuation_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const continuation_t&, const continuation_t&) + { + return false; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T continuation_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace relationship +} // namespace detail + +typedef detail::relationship_t<> relationship_t; + +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr relationship_t relationship; +#else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const relationship_t& + relationship = relationship_t::instance; } +#endif + +} // namespace execution + +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::relationship_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::relationship_t result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::relationship_t::fork_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::relationship_t::fork_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::relationship_t::continuation_t>::value)); +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_RELATIONSHIP_HPP diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 index 79584d8b..c1008f30 100644 --- a/test/execution/Jamfile.v2 +++ b/test/execution/Jamfile.v2 @@ -46,4 +46,5 @@ test-suite "asio" : [ run invocable_archetype.cpp ] [ run mapping.cpp ] [ run outstanding_work.cpp ] + [ run relationship.cpp ] ; diff --git a/test/execution/relationship.cpp b/test/execution/relationship.cpp new file mode 100644 index 00000000..109a96d9 --- /dev/null +++ b/test/execution/relationship.cpp @@ -0,0 +1,1272 @@ +// +// relationship.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include +#include +#include "../unit_test.hpp" + +namespace exec = boost::asio::execution; + +typedef exec::relationship_t s; +typedef exec::relationship_t::fork_t n1; +typedef exec::relationship_t::continuation_t n2; + +struct ex_nq_nr +{ + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template <> +struct is_executor : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct ex_cq_nr +{ + static BOOST_ASIO_CONSTEXPR ResultType query(ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + ex_cq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef Result result_type; // Must return raw result type. + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return Result(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_nr +{ + ResultType query(ParamType) const BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_nr +{ + friend ResultType query(const ex_fq_nr&, ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + CurrentType query(OtherType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + ex_mq_mr require( + OtherType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend CurrentType query(const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +void test_can_query() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_query() +{ + exec::relationship_t result1 = boost::asio::query(Executor(), Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); + + Executor ex1 = {}; + exec::relationship_t result2 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result2 == ExpectedResult()); + + const Executor ex2 = {}; + exec::relationship_t result3 = boost::asio::query(ex2, Param()); + BOOST_ASIO_CHECK(result3 == ExpectedResult()); +} + +template +void test_constexpr_query() +{ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) + constexpr Executor ex1 = {}; + constexpr exec::relationship_t result1 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); +#endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +} + +template +void test_can_require() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_require() +{ + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(Executor(), Param()), + Param()) == ExpectedResult()); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex1, Param()), + Param()) == ExpectedResult()); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex2, Param()), + Param()) == ExpectedResult()); +} + +template +void test_can_prefer() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_prefer() +{ + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(Executor(), Param()), + s())) == s(ExpectedResult())); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex1, Param()), + s())) == s(ExpectedResult())); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex2, Param()), + s())) == s(ExpectedResult())); +} + +void test_vars() +{ + BOOST_ASIO_CHECK(s() == exec::relationship); + BOOST_ASIO_CHECK(n1() == exec::relationship.fork); + BOOST_ASIO_CHECK(n2() == exec::relationship.continuation); +} + +BOOST_ASIO_TEST_SUITE +( + "relationship", + + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + + BOOST_ASIO_TEST_CASE3(test_query) + BOOST_ASIO_TEST_CASE3(test_query) + + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + + BOOST_ASIO_TEST_CASE3(test_require) + + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + + BOOST_ASIO_TEST_CASE3(test_prefer) + BOOST_ASIO_TEST_CASE3(test_prefer) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE(test_vars) +) From 3f90ca5cb23b6cbc4fe794d8efa8af776e895dc8 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:55:18 +1000 Subject: [PATCH 53/90] Add execution::blocking_adaptation property. --- include/boost/asio.hpp | 1 + .../asio/execution/blocking_adaptation.hpp | 699 +++++++++ test/execution/Jamfile.v2 | 1 + test/execution/blocking_adaptation.cpp | 1272 +++++++++++++++++ 4 files changed, 1973 insertions(+) create mode 100644 include/boost/asio/execution/blocking_adaptation.hpp create mode 100644 test/execution/blocking_adaptation.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 0b808f60..7d37f89c 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution/blocking_adaptation.hpp b/include/boost/asio/execution/blocking_adaptation.hpp new file mode 100644 index 00000000..56f197c9 --- /dev/null +++ b/include/boost/asio/execution/blocking_adaptation.hpp @@ -0,0 +1,699 @@ +// +// execution/blocking_adaptation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP +#define BOOST_ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to describe whether automatic adaptation of an executor is +/// allowed in order to apply the blocking_adaptation_t::allowed_t property. +struct blocking_adaptation_t +{ + /// The blocking_adaptation_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The top-level blocking_adaptation_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level blocking_adaptation_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef blocking_adaptation_t polymorphic_query_result_type; + + /// A sub-property that indicates that automatic adaptation is not allowed. + struct disallowed_t + { + /// The blocking_adaptation_t::disallowed_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The blocking_adaptation_t::disallowed_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_adaptation_t::disallowed_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_adaptation_t polymorphic_query_result_type; + + /// Default constructor. + constexpr disallowed_t(); + + /// Get the value associated with a property object. + /** + * @returns disallowed_t(); + */ + static constexpr blocking_adaptation_t value(); + }; + + /// A sub-property that indicates that automatic adaptation is allowed. + struct allowed_t + { + /// The blocking_adaptation_t::allowed_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The blocking_adaptation_t::allowed_t property can be required. + static constexpr bool is_requirable = true; + + /// The blocking_adaptation_t::allowed_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef blocking_adaptation_t polymorphic_query_result_type; + + /// Default constructor. + constexpr allowed_t(); + + /// Get the value associated with a property object. + /** + * @returns allowed_t(); + */ + static constexpr blocking_adaptation_t value(); + }; + + /// A special value used for accessing the blocking_adaptation_t::disallowed_t + /// property. + static constexpr disallowed_t disallowed; + + /// A special value used for accessing the blocking_adaptation_t::allowed_t + /// property. + static constexpr allowed_t allowed; + + /// Default constructor. + constexpr blocking_adaptation_t(); + + /// Construct from a sub-property value. + constexpr blocking_adaptation_t(disallowed_t); + + /// Construct from a sub-property value. + constexpr blocking_adaptation_t(allowed_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept; +}; + +/// A special value used for accessing the blocking_adaptation_t property. +constexpr blocking_adaptation_t blocking_adaptation; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace blocking_adaptation { + +template struct disallowed_t; +template struct allowed_t; + +} // namespace blocking_adaptation + +template +struct blocking_adaptation_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef blocking_adaptation_t polymorphic_query_result_type; + + typedef detail::blocking_adaptation::disallowed_t disallowed_t; + typedef detail::blocking_adaptation::allowed_t allowed_t; + + BOOST_ASIO_CONSTEXPR blocking_adaptation_t() + : value_(-1) + { + } + + BOOST_ASIO_CONSTEXPR blocking_adaptation_t(disallowed_t) + : value_(0) + { + } + + BOOST_ASIO_CONSTEXPR blocking_adaptation_t(allowed_t) + : value_(1) + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member< + T, blocking_adaptation_t>::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member< + T, blocking_adaptation_t + >::is_noexcept)) + { + return traits::query_static_constexpr_member< + T, blocking_adaptation_t>::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member< + T, blocking_adaptation_t>::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member< + T, blocking_adaptation_t>::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = blocking_adaptation_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) + { + return a.value_ == b.value_; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const blocking_adaptation_t& a, const blocking_adaptation_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_blocking_adaptation_t + { + BOOST_ASIO_CONSTEXPR convertible_from_blocking_adaptation_t( + blocking_adaptation_t) + { + } + }; + + template + friend BOOST_ASIO_CONSTEXPR blocking_adaptation_t query( + const Executor& ex, convertible_from_blocking_adaptation_t, + typename enable_if< + can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::disallowed_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, disallowed_t()); + } + + template + friend BOOST_ASIO_CONSTEXPR blocking_adaptation_t query( + const Executor& ex, convertible_from_blocking_adaptation_t, + typename enable_if< + !can_query::value + && can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::allowed_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, allowed_t()); + } + + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(disallowed_t, disallowed); + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(allowed_t, allowed); + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) + static const blocking_adaptation_t instance; +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T blocking_adaptation_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +template +const blocking_adaptation_t blocking_adaptation_t::instance; +#endif + +template +const typename blocking_adaptation_t::disallowed_t +blocking_adaptation_t::disallowed; + +template +const typename blocking_adaptation_t::allowed_t +blocking_adaptation_t::allowed; + +namespace blocking_adaptation { + +template +struct disallowed_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef blocking_adaptation_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR disallowed_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template + static BOOST_ASIO_CONSTEXPR disallowed_t static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query >::value + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return disallowed_t(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = disallowed_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR blocking_adaptation_t value() + { + return disallowed_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const disallowed_t&, const disallowed_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const disallowed_t&, const disallowed_t&) + { + return false; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T disallowed_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct allowed_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef blocking_adaptation_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR allowed_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = allowed_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR blocking_adaptation_t value() + { + return allowed_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const allowed_t&, const allowed_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const allowed_t&, const allowed_t&) + { + return false; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T allowed_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace blocking_adaptation +} // namespace detail + +typedef detail::blocking_adaptation_t<> blocking_adaptation_t; + +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr blocking_adaptation_t blocking_adaptation; +#else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const blocking_adaptation_t& + blocking_adaptation = blocking_adaptation_t::instance; } +#endif + +} // namespace execution + +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query::value)); + + typedef execution::blocking_adaptation_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::blocking_adaptation_t result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::blocking_adaptation_t::disallowed_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::blocking_adaptation_t::disallowed_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::blocking_adaptation_t::allowed_t>::value)); +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 index c1008f30..efc3f5c6 100644 --- a/test/execution/Jamfile.v2 +++ b/test/execution/Jamfile.v2 @@ -42,6 +42,7 @@ project test-suite "asio" : [ run blocking.cpp ] + [ run blocking_adaptation.cpp ] [ run execute.cpp ] [ run invocable_archetype.cpp ] [ run mapping.cpp ] diff --git a/test/execution/blocking_adaptation.cpp b/test/execution/blocking_adaptation.cpp new file mode 100644 index 00000000..ccdeeb8a --- /dev/null +++ b/test/execution/blocking_adaptation.cpp @@ -0,0 +1,1272 @@ +// +// blocking_adaptation.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include +#include +#include "../unit_test.hpp" + +namespace exec = boost::asio::execution; + +typedef exec::blocking_adaptation_t s; +typedef exec::blocking_adaptation_t::disallowed_t n1; +typedef exec::blocking_adaptation_t::allowed_t n2; + +struct ex_nq_nr +{ + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template <> +struct is_executor : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct ex_cq_nr +{ + static BOOST_ASIO_CONSTEXPR ResultType query(ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + ex_cq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef Result result_type; // Must return raw result type. + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return Result(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_nr +{ + ResultType query(ParamType) const BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_nr +{ + friend ResultType query(const ex_fq_nr&, ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + CurrentType query(OtherType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + ex_mq_mr require( + OtherType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend CurrentType query(const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +void test_can_query() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_query() +{ + exec::blocking_adaptation_t result1 = boost::asio::query(Executor(), Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); + + Executor ex1 = {}; + exec::blocking_adaptation_t result2 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result2 == ExpectedResult()); + + const Executor ex2 = {}; + exec::blocking_adaptation_t result3 = boost::asio::query(ex2, Param()); + BOOST_ASIO_CHECK(result3 == ExpectedResult()); +} + +template +void test_constexpr_query() +{ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) + constexpr Executor ex1 = {}; + constexpr exec::blocking_adaptation_t result1 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); +#endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +} + +template +void test_can_require() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_require() +{ + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(Executor(), Param()), + Param()) == ExpectedResult()); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex1, Param()), + Param()) == ExpectedResult()); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex2, Param()), + Param()) == ExpectedResult()); +} + +template +void test_can_prefer() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_prefer() +{ + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(Executor(), Param()), + s())) == s(ExpectedResult())); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex1, Param()), + s())) == s(ExpectedResult())); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex2, Param()), + s())) == s(ExpectedResult())); +} + +void test_vars() +{ + BOOST_ASIO_CHECK(s() == exec::blocking_adaptation); + BOOST_ASIO_CHECK(n1() == exec::blocking_adaptation.disallowed); + BOOST_ASIO_CHECK(n2() == exec::blocking_adaptation.allowed); +} + +BOOST_ASIO_TEST_SUITE +( + "blocking_adaptation", + + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + + BOOST_ASIO_TEST_CASE3(test_query) + BOOST_ASIO_TEST_CASE3(test_query) + + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + + BOOST_ASIO_TEST_CASE3(test_require) + + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + + BOOST_ASIO_TEST_CASE3(test_prefer) + BOOST_ASIO_TEST_CASE3(test_prefer) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + + BOOST_ASIO_TEST_CASE(test_vars) +) From 74a13e99203d7ee03b05ff2105ce8feddb997055 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:56:27 +1000 Subject: [PATCH 54/90] Add execution::bulk_guarantee property. --- include/boost/asio.hpp | 1 + .../boost/asio/execution/bulk_guarantee.hpp | 988 ++++++++ test/execution/Jamfile.v2 | 1 + test/execution/bulk_guarantee.cpp | 2000 +++++++++++++++++ 4 files changed, 2990 insertions(+) create mode 100644 include/boost/asio/execution/bulk_guarantee.hpp create mode 100644 test/execution/bulk_guarantee.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 7d37f89c..238987c1 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution/bulk_guarantee.hpp b/include/boost/asio/execution/bulk_guarantee.hpp new file mode 100644 index 00000000..ced2fe2e --- /dev/null +++ b/include/boost/asio/execution/bulk_guarantee.hpp @@ -0,0 +1,988 @@ +// +// execution/bulk_guarantee.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_BULK_GUARANTEE_HPP +#define BOOST_ASIO_EXECUTION_BULK_GUARANTEE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property to communicate the forward progress and ordering guarantees of +/// execution agents associated with the bulk execution. +struct bulk_guarantee_t +{ + /// The bulk_guarantee_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The top-level bulk_guarantee_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The top-level bulk_guarantee_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef bulk_guarantee_t polymorphic_query_result_type; + + /// A sub-property that indicates that execution agents within the same bulk + /// execution may be parallelised and vectorised. + struct unsequenced_t + { + /// The bulk_guarantee_t::unsequenced_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The bulk_guarantee_t::unsequenced_t property can be required. + static constexpr bool is_requirable = true; + + /// The bulk_guarantee_t::unsequenced_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef bulk_guarantee_t polymorphic_query_result_type; + + /// Default constructor. + constexpr unsequenced_t(); + + /// Get the value associated with a property object. + /** + * @returns unsequenced_t(); + */ + static constexpr bulk_guarantee_t value(); + }; + + /// A sub-property that indicates that execution agents within the same bulk + /// execution may not be parallelised and vectorised. + struct sequenced_t + { + /// The bulk_guarantee_t::sequenced_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The bulk_guarantee_t::sequenced_t property can be required. + static constexpr bool is_requirable = true; + + /// The bulk_guarantee_t::sequenced_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef bulk_guarantee_t polymorphic_query_result_type; + + /// Default constructor. + constexpr sequenced_t(); + + /// Get the value associated with a property object. + /** + * @returns sequenced_t(); + */ + static constexpr bulk_guarantee_t value(); + }; + + /// A sub-property that indicates that execution agents within the same bulk + /// execution may be parallelised. + struct parallel_t + { + /// The bulk_guarantee_t::parallel_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The bulk_guarantee_t::parallel_t property can be required. + static constexpr bool is_requirable = true; + + /// The bulk_guarantee_t::parallel_t property can be preferred. + static constexpr bool is_preferable = true; + + /// The type returned by queries against an @c any_executor. + typedef bulk_guarantee_t polymorphic_query_result_type; + + /// Default constructor. + constexpr parallel_t(); + + /// Get the value associated with a property object. + /** + * @returns parallel_t(); + */ + static constexpr bulk_guarantee_t value(); + }; + + /// A special value used for accessing the bulk_guarantee_t::unsequenced_t + /// property. + static constexpr unsequenced_t unsequenced; + + /// A special value used for accessing the bulk_guarantee_t::sequenced_t + /// property. + static constexpr sequenced_t sequenced; + + /// A special value used for accessing the bulk_guarantee_t::parallel_t + /// property. + static constexpr parallel_t parallel; + + /// Default constructor. + constexpr bulk_guarantee_t(); + + /// Construct from a sub-property value. + constexpr bulk_guarantee_t(unsequenced_t); + + /// Construct from a sub-property value. + constexpr bulk_guarantee_t(sequenced_t); + + /// Construct from a sub-property value. + constexpr bulk_guarantee_t(parallel_t); + + /// Compare property values for equality. + friend constexpr bool operator==( + const bulk_guarantee_t& a, const bulk_guarantee_t& b) noexcept; + + /// Compare property values for inequality. + friend constexpr bool operator!=( + const bulk_guarantee_t& a, const bulk_guarantee_t& b) noexcept; +}; + +/// A special value used for accessing the bulk_guarantee_t property. +constexpr bulk_guarantee_t bulk_guarantee; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { +namespace bulk_guarantee { + +template struct unsequenced_t; +template struct sequenced_t; +template struct parallel_t; + +} // namespace bulk_guarantee + +template +struct bulk_guarantee_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef bulk_guarantee_t polymorphic_query_result_type; + + typedef detail::bulk_guarantee::unsequenced_t unsequenced_t; + typedef detail::bulk_guarantee::sequenced_t sequenced_t; + typedef detail::bulk_guarantee::parallel_t parallel_t; + + BOOST_ASIO_CONSTEXPR bulk_guarantee_t() + : value_(-1) + { + } + + BOOST_ASIO_CONSTEXPR bulk_guarantee_t(unsequenced_t) + : value_(0) + { + } + + BOOST_ASIO_CONSTEXPR bulk_guarantee_t(sequenced_t) + : value_(1) + { + } + + BOOST_ASIO_CONSTEXPR bulk_guarantee_t(parallel_t) + : value_(2) + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member< + T, bulk_guarantee_t>::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return traits::static_query::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = bulk_guarantee_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const bulk_guarantee_t& a, const bulk_guarantee_t& b) + { + return a.value_ == b.value_; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const bulk_guarantee_t& a, const bulk_guarantee_t& b) + { + return a.value_ != b.value_; + } + + struct convertible_from_bulk_guarantee_t + { + BOOST_ASIO_CONSTEXPR convertible_from_bulk_guarantee_t(bulk_guarantee_t) {} + }; + + template + friend BOOST_ASIO_CONSTEXPR bulk_guarantee_t query( + const Executor& ex, convertible_from_bulk_guarantee_t, + typename enable_if< + can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::unsequenced_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, unsequenced_t()); + } + + template + friend BOOST_ASIO_CONSTEXPR bulk_guarantee_t query( + const Executor& ex, convertible_from_bulk_guarantee_t, + typename enable_if< + !can_query::value + && can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::sequenced_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, sequenced_t()); + } + + template + friend BOOST_ASIO_CONSTEXPR bulk_guarantee_t query( + const Executor& ex, convertible_from_bulk_guarantee_t, + typename enable_if< + !can_query::value + && !can_query::value + && can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::parallel_t>::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, parallel_t()); + } + + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(unsequenced_t, unsequenced); + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(sequenced_t, sequenced); + BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(parallel_t, parallel); + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) + static const bulk_guarantee_t instance; +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) + +private: + int value_; +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T bulk_guarantee_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +template +const bulk_guarantee_t bulk_guarantee_t::instance; +#endif + +template +const typename bulk_guarantee_t::unsequenced_t +bulk_guarantee_t::unsequenced; + +template +const typename bulk_guarantee_t::sequenced_t +bulk_guarantee_t::sequenced; + +template +const typename bulk_guarantee_t::parallel_t +bulk_guarantee_t::parallel; + +namespace bulk_guarantee { + +template +struct unsequenced_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef bulk_guarantee_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR unsequenced_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template + static BOOST_ASIO_CONSTEXPR unsequenced_t static_query( + typename enable_if< + !traits::query_static_constexpr_member::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query >::value + && !can_query >::value + >::type* = 0) BOOST_ASIO_NOEXCEPT + { + return unsequenced_t(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = unsequenced_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR bulk_guarantee_t value() + { + return unsequenced_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const unsequenced_t&, const unsequenced_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const unsequenced_t&, const unsequenced_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const unsequenced_t&, const sequenced_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const unsequenced_t&, const sequenced_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const unsequenced_t&, const parallel_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const unsequenced_t&, const parallel_t&) + { + return true; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T unsequenced_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct sequenced_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef bulk_guarantee_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR sequenced_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = sequenced_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR bulk_guarantee_t value() + { + return sequenced_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const sequenced_t&, const sequenced_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const sequenced_t&, const sequenced_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const sequenced_t&, const unsequenced_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const sequenced_t&, const unsequenced_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const sequenced_t&, const parallel_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const sequenced_t&, const parallel_t&) + { + return true; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T sequenced_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct parallel_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + typedef bulk_guarantee_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR parallel_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = parallel_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + static BOOST_ASIO_CONSTEXPR bulk_guarantee_t value() + { + return parallel_t(); + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const parallel_t&, const parallel_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const parallel_t&, const parallel_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const parallel_t&, const unsequenced_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const parallel_t&, const unsequenced_t&) + { + return true; + } + + friend BOOST_ASIO_CONSTEXPR bool operator==( + const parallel_t&, const sequenced_t&) + { + return false; + } + + friend BOOST_ASIO_CONSTEXPR bool operator!=( + const parallel_t&, const sequenced_t&) + { + return true; + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T parallel_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace bulk_guarantee +} // namespace detail + +typedef detail::bulk_guarantee_t<> bulk_guarantee_t; + +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr bulk_guarantee_t bulk_guarantee; +#else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const bulk_guarantee_t& + bulk_guarantee = bulk_guarantee_t::instance; } +#endif + +} // namespace execution + +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free_default::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::bulk_guarantee_t result_type; +}; + +template +struct query_free_default::value + && can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::bulk_guarantee_t result_type; +}; + +template +struct query_free_default::value + && !can_query::value + && can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef execution::bulk_guarantee_t result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::static_query::is_valid + && !traits::static_query::is_valid + && traits::static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::static_query::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::static_query::value(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + && !traits::query_member::is_valid + && !traits::query_free::is_valid + && !can_query::value + && !can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::bulk_guarantee_t::unsequenced_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::bulk_guarantee_t::unsequenced_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::bulk_guarantee_t::sequenced_t>::value)); +}; + +template +struct static_require::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = + (is_same::result_type, + execution::bulk_guarantee_t::parallel_t>::value)); +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_BULK_GUARANTEE_HPP diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 index efc3f5c6..37d28753 100644 --- a/test/execution/Jamfile.v2 +++ b/test/execution/Jamfile.v2 @@ -43,6 +43,7 @@ project test-suite "asio" : [ run blocking.cpp ] [ run blocking_adaptation.cpp ] + [ run bulk_guarantee.cpp ] [ run execute.cpp ] [ run invocable_archetype.cpp ] [ run mapping.cpp ] diff --git a/test/execution/bulk_guarantee.cpp b/test/execution/bulk_guarantee.cpp new file mode 100644 index 00000000..af4c9cd5 --- /dev/null +++ b/test/execution/bulk_guarantee.cpp @@ -0,0 +1,2000 @@ +// +// bulk_guarantee.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include +#include +#include "../unit_test.hpp" + +namespace exec = boost::asio::execution; + +typedef exec::bulk_guarantee_t s; +typedef exec::bulk_guarantee_t::unsequenced_t n1; +typedef exec::bulk_guarantee_t::sequenced_t n2; +typedef exec::bulk_guarantee_t::parallel_t n3; + +struct ex_nq_nr +{ + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_nq_nr&, const ex_nq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template <> +struct is_executor : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct ex_cq_nr +{ + static BOOST_ASIO_CONSTEXPR ResultType query(ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_cq_nr&, const ex_cq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + ex_cq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef Result result_type; // Must return raw result type. + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return Result(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_nr +{ + ResultType query(ParamType) const BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_nr&, const ex_mq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_nr +{ + friend ResultType query(const ex_fq_nr&, ParamType) BOOST_ASIO_NOEXCEPT + { + return Result(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_nr&, const ex_fq_nr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_nr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ResultType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + CurrentType query(OtherType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + ex_mq_mr require( + OtherType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_mq_mr +{ + CurrentType query(CurrentType) const BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + ex_mq_mr require( + CurrentType) const BOOST_ASIO_NOEXCEPT + { + return ex_mq_mr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_mq_mr&, const ex_mq_mr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +template +struct require_member< + ex_mq_mr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_mq_mr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend CurrentType query(const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, OtherType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +template +struct ex_fq_fr +{ + friend CurrentType query(const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return CurrentType(); + } + + friend ex_fq_fr require( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + friend ex_fq_fr prefer( + const ex_fq_fr&, CurrentType) BOOST_ASIO_NOEXCEPT + { + return ex_fq_fr(); + } + + template + void execute(const F&) const + { + } + + friend bool operator==(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const ex_fq_fr&, const ex_fq_fr&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template +struct is_executor > + : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + || boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef CurrentType result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct require_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +template +struct prefer_free< + ex_fq_fr, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + && !boost::asio::is_same::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef ex_fq_fr result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace traits +} // namespace asio +} // namespace boost + +template +void test_can_query() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_query::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_query() +{ + exec::bulk_guarantee_t result1 = boost::asio::query(Executor(), Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); + + Executor ex1 = {}; + exec::bulk_guarantee_t result2 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result2 == ExpectedResult()); + + const Executor ex2 = {}; + exec::bulk_guarantee_t result3 = boost::asio::query(ex2, Param()); + BOOST_ASIO_CHECK(result3 == ExpectedResult()); +} + +template +void test_constexpr_query() +{ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) + constexpr Executor ex1 = {}; + constexpr exec::bulk_guarantee_t result1 = boost::asio::query(ex1, Param()); + BOOST_ASIO_CHECK(result1 == ExpectedResult()); +#endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +} + +template +void test_can_require() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_require::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_require() +{ + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(Executor(), Param()), + Param()) == ExpectedResult()); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex1, Param()), + Param()) == ExpectedResult()); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + boost::asio::query( + boost::asio::require(ex2, Param()), + Param()) == ExpectedResult()); +} + +template +void test_can_prefer() +{ + BOOST_ASIO_CONSTEXPR bool b1 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b1 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b2 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b2 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b3 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b3 == ExpectedResult); + + BOOST_ASIO_CONSTEXPR bool b4 = + boost::asio::can_prefer::value; + BOOST_ASIO_CHECK(b4 == ExpectedResult); +} + +template +void test_prefer() +{ + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(Executor(), Param()), + s())) == s(ExpectedResult())); + + Executor ex1 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex1, Param()), + s())) == s(ExpectedResult())); + + const Executor ex2 = {}; + BOOST_ASIO_CHECK( + s(boost::asio::query( + boost::asio::prefer(ex2, Param()), + s())) == s(ExpectedResult())); +} + +void test_vars() +{ + BOOST_ASIO_CHECK(s() == exec::bulk_guarantee); + BOOST_ASIO_CHECK(n1() == exec::bulk_guarantee.unsequenced); + BOOST_ASIO_CHECK(n2() == exec::bulk_guarantee.sequenced); + BOOST_ASIO_CHECK(n3() == exec::bulk_guarantee.parallel); +} + +BOOST_ASIO_TEST_SUITE +( + "bulk_guarantee", + + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + BOOST_ASIO_TEST_CASE3(test_can_query) + + BOOST_ASIO_TEST_CASE3(test_query) + BOOST_ASIO_TEST_CASE3(test_query) + + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + BOOST_ASIO_TEST_CASE3(test_constexpr_query) + + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + BOOST_ASIO_TEST_CASE3(test_can_require) + + BOOST_ASIO_TEST_CASE3(test_require) + + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + BOOST_ASIO_TEST_CASE3(test_can_prefer) + + BOOST_ASIO_TEST_CASE3(test_prefer) + BOOST_ASIO_TEST_CASE3(test_prefer) + BOOST_ASIO_TEST_CASE3(test_prefer) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_constexpr_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_require, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_query, s, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_query, s, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_query, s, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE5(test_can_require, n3, false>) + + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE5(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE5(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE5(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, s, true>) + BOOST_ASIO_TEST_CASE4(test_can_query, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_query, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n1>) + BOOST_ASIO_TEST_CASE4(test_query, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n2>) + BOOST_ASIO_TEST_CASE4(test_query, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_query, s, n3>) + BOOST_ASIO_TEST_CASE4(test_query, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_require, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n1, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n2, false>) + BOOST_ASIO_TEST_CASE4(test_can_require, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_require, n3, n3>) + + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, s, false>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n1, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n2, true>) + BOOST_ASIO_TEST_CASE4(test_can_prefer, n3, true>) + + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n1>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n2>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n1, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n2, n3>) + BOOST_ASIO_TEST_CASE4(test_prefer, n3, n3>) + + BOOST_ASIO_TEST_CASE(test_vars) +) From f080c0196519443d758c4be2875a05f33843a838 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:56:47 +1000 Subject: [PATCH 55/90] Add execution::allocator property. --- include/boost/asio.hpp | 1 + include/boost/asio/execution/allocator.hpp | 243 +++++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 include/boost/asio/execution/allocator.hpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 238987c1..345f8066 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution/allocator.hpp b/include/boost/asio/execution/allocator.hpp new file mode 100644 index 00000000..407ed3ac --- /dev/null +++ b/include/boost/asio/execution/allocator.hpp @@ -0,0 +1,243 @@ +// +// execution/allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_ALLOCATOR_HPP +#define BOOST_ASIO_EXECUTION_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that is used to obtain the execution context that is associated +/// with an executor. +template +struct allocator_t +{ + /// The allocator_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The allocator_t property can be required. + static constexpr bool is_requirable = true; + + /// The allocator_t property can be preferred. + static constexpr bool is_preferable = true; + + /// Default constructor. + constexpr allocator_t(); + + /// Obtain the allocator stored in the allocator_t property object. + /** + * Present only if @c ProtoAllocator is non-void. + */ + constexpr ProtoAllocator value() const; + + /// Create an allocator_t object with a different allocator. + /** + * Present only if @c ProtoAllocator is void. + */ + template + allocator_t allocator; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { + +template +struct allocator_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = allocator_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + BOOST_ASIO_CONSTEXPR ProtoAllocator value() const + { + return a_; + } + +private: + friend struct allocator_t; + + explicit BOOST_ASIO_CONSTEXPR allocator_t(const ProtoAllocator& a) + : a_(a) + { + } + + ProtoAllocator a_; +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T allocator_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template <> +struct allocator_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); + + BOOST_ASIO_CONSTEXPR allocator_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = allocator_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + template + BOOST_ASIO_CONSTEXPR allocator_t operator()( + const OtherProtoAllocator& a) const + { + return allocator_t(a); + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template +const T allocator_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr allocator_t allocator; +#else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +template +struct allocator_instance +{ + static allocator_t instance; +}; + +template +allocator_t allocator_instance::instance; + +namespace { +static const allocator_t& allocator = allocator_instance::instance; +} // namespace +#endif + +} // namespace execution + +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property > + : execution::is_executor +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query, + typename enable_if< + traits::query_static_constexpr_member >::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member >::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member >::value(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_ALLOCATOR_HPP From f1b382b32b88eaa94c5aacb46307f6bda3a87b1d Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:57:09 +1000 Subject: [PATCH 56/90] Add execution::occupancy property. --- include/boost/asio.hpp | 1 + include/boost/asio/execution/occupancy.hpp | 173 +++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 include/boost/asio/execution/occupancy.hpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 345f8066..597479f3 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution/occupancy.hpp b/include/boost/asio/execution/occupancy.hpp new file mode 100644 index 00000000..39850aa2 --- /dev/null +++ b/include/boost/asio/execution/occupancy.hpp @@ -0,0 +1,173 @@ +// +// execution/occupancy.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_OCCUPANCY_HPP +#define BOOST_ASIO_EXECUTION_OCCUPANCY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that gives an estimate of the number of execution agents that +/// should occupy the associated execution context. +struct occupancy_t +{ + /// The occupancy_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The occupancy_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The occupancy_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef std::size_t polymorphic_query_result_type; +}; + +/// A special value used for accessing the occupancy_t property. +constexpr occupancy_t occupancy; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { + +template +struct occupancy_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + typedef std::size_t polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR occupancy_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = occupancy_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) + static const occupancy_t instance; +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T occupancy_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +template +const occupancy_t occupancy_t::instance; +#endif + +} // namespace detail + +typedef detail::occupancy_t<> occupancy_t; + +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr occupancy_t occupancy; +#else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const occupancy_t& occupancy = occupancy_t::instance; } +#endif + +} // namespace execution + +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_OCCUPANCY_HPP From ec2f491be00f91300c60d2bf9e75ad9b051b1d67 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:57:38 +1000 Subject: [PATCH 57/90] Add execution::context property. --- include/boost/asio.hpp | 1 + include/boost/asio/execution/context.hpp | 169 +++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 include/boost/asio/execution/context.hpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 597479f3..6b3f4803 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution/context.hpp b/include/boost/asio/execution/context.hpp new file mode 100644 index 00000000..35e8da8a --- /dev/null +++ b/include/boost/asio/execution/context.hpp @@ -0,0 +1,169 @@ +// +// execution/context.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_CONTEXT2_HPP +#define BOOST_ASIO_EXECUTION_CONTEXT2_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that is used to obtain the execution context that is associated +/// with an executor. +struct context_t +{ + /// The context_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The context_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The context_t property cannot be preferred. + static constexpr bool is_preferable = false; +}; + +/// A special value used for accessing the context_t property. +constexpr context_t context; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { + +template +struct context_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + + BOOST_ASIO_CONSTEXPR context_t() + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = context_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) + static const context_t instance; +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T context_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +template +const context_t context_t::instance; +#endif + +} // namespace detail + +typedef detail::context_t<> context_t; + +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr context_t context; +#else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +namespace { static const context_t& context = context_t::instance; } +#endif + +} // namespace execution + +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property + : execution::is_executor +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query::is_valid + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef typename traits::query_static_constexpr_member::result_type result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return traits::query_static_constexpr_member::value(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_CONTEXT2_HPP From 3783cc109344528ef9535af92e831f94449b46ce Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 22:58:43 +1000 Subject: [PATCH 58/90] Add execution::any_executor. --- include/boost/asio.hpp | 1 + include/boost/asio/detail/assert.hpp | 8 + include/boost/asio/detail/config.hpp | 23 + .../boost/asio/detail/executor_function.hpp | 169 +- include/boost/asio/detail/memory.hpp | 3 + include/boost/asio/detail/type_traits.hpp | 8 + include/boost/asio/execution/any_executor.hpp | 1972 +++++++++++++++++ include/boost/asio/execution/bad_executor.hpp | 49 + .../asio/execution/impl/bad_executor.ipp | 42 + include/boost/asio/executor.hpp | 3 +- include/boost/asio/impl/executor.hpp | 93 - include/boost/asio/impl/src.hpp | 1 + test/execution/Jamfile.v2 | 1 + test/execution/any_executor.cpp | 139 ++ 14 files changed, 2383 insertions(+), 129 deletions(-) create mode 100644 include/boost/asio/execution/any_executor.hpp create mode 100644 include/boost/asio/execution/bad_executor.hpp create mode 100644 include/boost/asio/execution/impl/bad_executor.ipp create mode 100644 test/execution/any_executor.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 6b3f4803..188d8bbc 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/detail/assert.hpp b/include/boost/asio/detail/assert.hpp index 1c935754..8634176a 100644 --- a/include/boost/asio/detail/assert.hpp +++ b/include/boost/asio/detail/assert.hpp @@ -29,4 +29,12 @@ # define BOOST_ASIO_ASSERT(expr) assert(expr) #endif // defined(BOOST_ASIO_HAS_BOOST_ASSERT) +#if defined(BOOST_ASIO_HAS_STATIC_ASSERT) +# define BOOST_ASIO_STATIC_ASSERT(c, n, m) static_assert((c), m) +#else // defined(BOOST_ASIO_HAS_STATIC_ASSERT) +# define BOOST_ASIO_STATIC_ASSERT(c, n, m) \ + typedef char static_assert_ ## n \ + [(c) ? 1 : -1] BOOST_ASIO_UNUSED_TYPEDEF +#endif // defined(BOOST_ASIO_HAS_STATIC_ASSERT) + #endif // BOOST_ASIO_DETAIL_ASSERT_HPP diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp index e113ff2d..48578a87 100644 --- a/include/boost/asio/detail/config.hpp +++ b/include/boost/asio/detail/config.hpp @@ -493,6 +493,29 @@ # endif // !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) #endif // !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +// Support static_assert on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_STATIC_ASSERT) +# if !defined(BOOST_ASIO_DISABLE_STATIC_ASSERT) +# if defined(__clang__) +# if __has_feature(__cxx_static_assert__) +# define BOOST_ASIO_HAS_STATIC_ASSERT 1 +# endif // __has_feature(__cxx_static_assert__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STATIC_ASSERT 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_STATIC_ASSERT 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STATIC_ASSERT) +#endif // !defined(BOOST_ASIO_HAS_STATIC_ASSERT) + // Standard library support for system errors. # if !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) # if defined(__clang__) diff --git a/include/boost/asio/detail/executor_function.hpp b/include/boost/asio/detail/executor_function.hpp index d13a2ca2..14e0440e 100644 --- a/include/boost/asio/detail/executor_function.hpp +++ b/include/boost/asio/detail/executor_function.hpp @@ -17,6 +17,7 @@ #include #include +#include #include @@ -24,57 +25,80 @@ namespace boost { namespace asio { namespace detail { -class executor_function_base +#if defined(BOOST_ASIO_HAS_MOVE) + +// Lightweight, move-only function object wrapper. +class executor_function { public: - void complete() + template + explicit executor_function(F f, const Alloc& a) { - func_(this, true); + // Allocate and construct an object to wrap the function. + typedef impl impl_type; + typename impl_type::ptr p = { + detail::addressof(a), impl_type::ptr::allocate(a), 0 }; + impl_ = new (p.v) impl_type(BOOST_ASIO_MOVE_CAST(F)(f), a); + p.v = 0; } - void destroy() + executor_function(executor_function&& other) BOOST_ASIO_NOEXCEPT + : impl_(other.impl_) { - func_(this, false); + other.impl_ = 0; } -protected: - typedef void (*func_type)(executor_function_base*, bool); - - executor_function_base(func_type func) - : func_(func) + ~executor_function() { + if (impl_) + impl_->complete_(impl_, false); } - // Prevents deletion through this type. - ~executor_function_base() + void operator()() { + if (impl_) + { + impl_base* i = impl_; + impl_ = 0; + i->complete_(i, true); + } } private: - func_type func_; -}; - -template -class executor_function : public executor_function_base -{ -public: - BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( - thread_info_base::executor_function_tag, executor_function); - - template - executor_function(BOOST_ASIO_MOVE_ARG(F) f, const Alloc& allocator) - : executor_function_base(&executor_function::do_complete), - function_(BOOST_ASIO_MOVE_CAST(F)(f)), - allocator_(allocator) + // Base class for polymorphic function implementations. + struct impl_base { - } + void (*complete_)(impl_base*, bool); + }; - static void do_complete(executor_function_base* base, bool call) + // Polymorphic function implementation. + template + struct impl : impl_base + { + BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( + thread_info_base::executor_function_tag, impl); + + template + impl(BOOST_ASIO_MOVE_ARG(F) f, const Alloc& a) + : function_(BOOST_ASIO_MOVE_CAST(F)(f)), + allocator_(a) + { + complete_ = &executor_function::complete; + } + + Function function_; + Alloc allocator_; + }; + + // Helper to complete function invocation. + template + static void complete(impl_base* base, bool call) { // Take ownership of the function object. - executor_function* o(static_cast(base)); - Alloc allocator(o->allocator_); - ptr p = { detail::addressof(allocator), o, o }; + impl* i(static_cast*>(base)); + Alloc allocator(i->allocator_); + typename impl::ptr p = { + detail::addressof(allocator), i, i }; // Make a copy of the function so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a @@ -82,7 +106,7 @@ public: // associated with the function. Consequently, a local copy of the function // is required to ensure that any owning sub-object remains valid until // after we have deallocated the memory here. - Function function(BOOST_ASIO_MOVE_CAST(Function)(o->function_)); + Function function(BOOST_ASIO_MOVE_CAST(Function)(i->function_)); p.reset(); // Make the upcall if required. @@ -92,9 +116,84 @@ public: } } + impl_base* impl_; +}; + +#else // defined(BOOST_ASIO_HAS_MOVE) + +// Not so lightweight, copyable function object wrapper. +class executor_function +{ +public: + template + explicit executor_function(const F& f, const Alloc&) + : impl_(new impl::type>(f)) + { + } + + void operator()() + { + impl_->complete_(impl_.get()); + } + private: - Function function_; - Alloc allocator_; + // Base class for polymorphic function implementations. + struct impl_base + { + void (*complete_)(impl_base*); + }; + + // Polymorphic function implementation. + template + struct impl : impl_base + { + impl(const F& f) + : function_(f) + { + complete_ = &executor_function::complete; + } + + F function_; + }; + + // Helper to complete function invocation. + template + static void complete(impl_base* i) + { + static_cast*>(i)->function_(); + } + + shared_ptr impl_; +}; + +#endif // defined(BOOST_ASIO_HAS_MOVE) + +// Lightweight, non-owning, copyable function object wrapper. +class executor_function_view +{ +public: + template + explicit executor_function_view(F& f) BOOST_ASIO_NOEXCEPT + : complete_(&executor_function_view::complete), + function_(&f) + { + } + + void operator()() + { + complete_(function_); + } + +private: + // Helper to complete function invocation. + template + static void complete(void* f) + { + (*static_cast(f))(); + } + + void (*complete_)(void*); + void* function_; }; } // namespace detail diff --git a/include/boost/asio/detail/memory.hpp b/include/boost/asio/detail/memory.hpp index 0f92263c..438abceb 100644 --- a/include/boost/asio/detail/memory.hpp +++ b/include/boost/asio/detail/memory.hpp @@ -19,6 +19,7 @@ #include #if !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +# include # include # include #endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) @@ -32,9 +33,11 @@ namespace asio { namespace detail { #if defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +using std::make_shared; using std::shared_ptr; using std::weak_ptr; #else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +using boost::make_shared; using boost::shared_ptr; using boost::weak_ptr; #endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) diff --git a/include/boost/asio/detail/type_traits.hpp b/include/boost/asio/detail/type_traits.hpp index 7d3dab85..06550808 100644 --- a/include/boost/asio/detail/type_traits.hpp +++ b/include/boost/asio/detail/type_traits.hpp @@ -21,6 +21,8 @@ # include #else // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) # include +# include +# include # include # include # include @@ -46,6 +48,8 @@ namespace asio { #if defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) using std::add_const; +using std::aligned_storage; +using std::alignment_of; using std::conditional; using std::decay; using std::declval; @@ -62,6 +66,7 @@ using std::is_function; using std::is_nothrow_copy_constructible; using std::is_nothrow_destructible; using std::is_same; +using std::is_scalar; using std::remove_pointer; using std::remove_reference; #if defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) @@ -74,6 +79,8 @@ using std::result_of; using std::true_type; #else // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) using boost::add_const; +using boost::aligned_storage; +using boost::alignment_of; template struct enable_if : boost::enable_if_c {}; using boost::conditional; @@ -93,6 +100,7 @@ struct is_nothrow_copy_constructible : boost::has_nothrow_copy {}; template struct is_nothrow_destructible : boost::has_nothrow_destructor {}; using boost::is_same; +using boost::is_scalar; using boost::remove_pointer; using boost::remove_reference; using boost::result_of; diff --git a/include/boost/asio/execution/any_executor.hpp b/include/boost/asio/execution/any_executor.hpp new file mode 100644 index 00000000..fd6efc73 --- /dev/null +++ b/include/boost/asio/execution/any_executor.hpp @@ -0,0 +1,1972 @@ +// +// execution/any_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_ANY_EXECUTOR_HPP +#define BOOST_ASIO_EXECUTION_ANY_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// Polymorphic executor wrapper. +template +class any_executor +{ +public: + /// Default constructor. + any_executor() noexcept; + + /// Copy constructor. + any_executor(const any_executor& e) noexcept; + + /// Move constructor. + any_executor(any_executor&& e) noexcept; + + /// Construct to point to the same target as another any_executor. + template + any_executor(any_executor e); + + /// Construct a polymorphic wrapper for the specified executor. + template + any_executor(Executor e); + + /// Assignment operator. + any_executor& operator=(const any_executor& e) noexcept; + + /// Move assignment operator. + any_executor& operator=(any_executor&& e) noexcept; + + /// Assignment operator to create a polymorphic wrapper for the specified + /// executor. + template + any_executor& operator=(Executor e); + + /// Destructor. + ~any_executor(); + + //void swap(any_executor& other) noexcept; + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * boost::asio::require and boost::asio::prefer customisation points. + * + * For example: + * @code execution::any_executor ex = ...; + * auto ex2 = boost::asio::requre(ex, execution::blocking.possibly); @endcode + */ + template + any_executor require(Property) const; + + /// Obtain a polymorphic wrapper with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * boost::asio::prefer customisation point. + * + * For example: + * @code execution::any_executor ex = ...; + * auto ex2 = boost::asio::prefer(ex, execution::blocking.possibly); @endcode + */ + template + any_executor prefer(Property) const; + + /// Obtain the value associated with the specified property. + /** + * Do not call this function directly. It is intended for use with the + * boost::asio::query customisation point. + * + * For example: + * @code execution::any_executor ex = ...; + * size_t n = boost::asio::query(ex, execution::occupancy); @endcode + */ + template + typename Property::polymorphic_query_result_type query(Property) const; + + /// Execute the function on the target executor. + /** + * Do not call this function directly. It is intended for use with the + * execution::execute customisation point. + * + * For example: + * @code execution::any_executor<> ex = ...; + * execution::execute(ex, my_function_object); @endcode + * + * Throws boost::asio::bad_executor if the polymorphic wrapper has no target. + */ + template + void execute(Function&& f) const; + + /// Obtain the underlying execution context. + /** + * This function is provided for backward compatibility. It is automatically + * defined when the @c SupportableProperties... list includes a property of + * type execution::context_as, for some type U. + */ + automatically_determined context() const; + + /// Determine whether the wrapper has a target executor. + /** + * @returns @c true if the polymorphic wrapper has a target executor, + * otherwise false. + */ + explicit operator bool() const noexcept; + + /// Get the type of the target executor. + const type_info& target_type() const noexcept; + + /// Get a pointer to the target executor. + template Executor* target() noexcept; + + /// Get a pointer to the target executor. + template const Executor* target() const noexcept; +}; + +/// Equality operator. +/** + * @relates any_executor + */ +template +bool operator==(const any_executor& a, + const any_executor& b) noexcept; + +/// Inequality operator. +/** + * @relates any_executor + */ +template +bool operator!=(const any_executor& a, + const any_executor& b) noexcept; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +class any_executor; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +class any_executor; + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct context_as_t; + +namespace detail { + +// Traits used to detect whether a property is requirable or preferable, taking +// into account that T::is_requirable or T::is_preferable may not not be well +// formed. + +template +struct is_requirable : false_type {}; + +template +struct is_requirable::type> : + true_type {}; + +template +struct is_preferable : false_type {}; + +template +struct is_preferable::type> : + true_type {}; + +// Trait used to detect context_as property, for backward compatibility. + +template +struct is_context_as : false_type {}; + +template +struct is_context_as > : true_type {}; + +// Helper template to: +// - Check if a target can supply the supportable properties. +// - Find the first convertible-from-T property in the list. + +template +struct supportable_properties; + +template +struct supportable_properties +{ + template + struct is_valid_target : integral_constant::value + ? can_require::value + : true + ) + && + ( + is_preferable::value + ? can_prefer::value + : true + ) + && + ( + !is_requirable::value && !is_preferable::value + ? can_query::value + : true + ) + > + { + }; + + struct found + { + BOOST_ASIO_STATIC_CONSTEXPR(bool, value = true); + typedef Prop type; + typedef typename Prop::polymorphic_query_result_type query_result_type; + BOOST_ASIO_STATIC_CONSTEXPR(std::size_t, index = I); + }; + + struct not_found + { + BOOST_ASIO_STATIC_CONSTEXPR(bool, value = false); + }; + + template + struct find_convertible_property : + conditional< + is_same::value || is_convertible::value, + found, + not_found + >::type {}; + + template + struct find_convertible_requirable_property : + conditional< + is_requirable::value + && (is_same::value || is_convertible::value), + found, + not_found + >::type {}; + + template + struct find_convertible_preferable_property : + conditional< + is_preferable::value + && (is_same::value || is_convertible::value), + found, + not_found + >::type {}; + + struct find_context_as_property : + conditional< + is_context_as::value, + found, + not_found + >::type {}; +}; + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct supportable_properties +{ + template + struct is_valid_target : integral_constant::template is_valid_target::value + && + supportable_properties::template is_valid_target::value + ) + > + { + }; + + template + struct find_convertible_property : + conditional< + is_convertible::value, + typename supportable_properties::found, + typename supportable_properties::template find_convertible_property + >::type {}; + + template + struct find_convertible_requirable_property : + conditional< + is_requirable::value + && is_convertible::value, + typename supportable_properties::found, + typename supportable_properties::template find_convertible_requirable_property + >::type {}; + + template + struct find_convertible_preferable_property : + conditional< + is_preferable::value + && is_convertible::value, + typename supportable_properties::found, + typename supportable_properties::template find_convertible_preferable_property + >::type {}; + + struct find_context_as_property : + conditional< + is_context_as::value, + typename supportable_properties::found, + typename supportable_properties::find_context_as_property + >::type {}; +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF(n) \ + template \ + struct supportable_properties \ + { \ + template \ + struct is_valid_target : integral_constant::template is_valid_target::value \ + && \ + supportable_properties::template \ + is_valid_target::value \ + ) \ + > \ + { \ + }; \ + \ + template \ + struct find_convertible_property : \ + conditional< \ + is_convertible::value, \ + typename supportable_properties::found, \ + typename supportable_properties::template \ + find_convertible_property \ + >::type {}; \ + \ + template \ + struct find_convertible_requirable_property : \ + conditional< \ + is_requirable::value \ + && is_convertible::value, \ + typename supportable_properties::found, \ + typename supportable_properties::template \ + find_convertible_requirable_property \ + >::type {}; \ + \ + template \ + struct find_convertible_preferable_property : \ + conditional< \ + is_preferable::value \ + && is_convertible::value, \ + typename supportable_properties::found, \ + typename supportable_properties::template \ + find_convertible_preferable_property \ + >::type {}; \ + \ + struct find_context_as_property : \ + conditional< \ + is_context_as::value, \ + typename supportable_properties::found, \ + typename supportable_properties::find_context_as_property \ + >::type {}; \ + }; \ + /**/ +BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF) +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +class any_executor_base +{ +public: + any_executor_base() BOOST_ASIO_NOEXCEPT + : object_fns_(object_fns_table()), + target_(0), + target_fns_(target_fns_table()), + blocking_() + { + } + + template + any_executor_base(Executor ex, false_type) + : target_fns_(target_fns_table()), + blocking_( + any_executor_base::query_blocking( + ex, can_query())) + { + any_executor_base::construct_object(ex, + integral_constant::value <= alignment_of::value + >()); + } + + template + any_executor_base(Executor other, true_type) + : object_fns_(object_fns_table >()), + target_fns_(other.target_fns_), + blocking_(other.blocking_) + { + boost::asio::detail::shared_ptr p = + boost::asio::detail::make_shared( + BOOST_ASIO_MOVE_CAST(Executor)(other)); + target_ = p->template target(); + new (&object_) boost::asio::detail::shared_ptr( + BOOST_ASIO_MOVE_CAST(boost::asio::detail::shared_ptr)(p)); + } + + any_executor_base(const any_executor_base& other) BOOST_ASIO_NOEXCEPT + : object_fns_(other.object_fns_), + target_fns_(other.target_fns_), + blocking_(other.blocking_) + { + object_fns_->copy(*this, other); + } + + ~any_executor_base() + { + object_fns_->destroy(*this); + } + + any_executor_base& operator=( + const any_executor_base& other) BOOST_ASIO_NOEXCEPT + { + if (this != &other) + { + object_fns_->destroy(*this); + object_fns_ = other.object_fns_; + target_fns_ = other.target_fns_; + blocking_ = other.blocking_; + object_fns_->copy(*this, other); + } + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + + any_executor_base(any_executor_base&& other) BOOST_ASIO_NOEXCEPT + : object_fns_(other.object_fns_), + target_fns_(other.target_fns_), + blocking_(other.blocking_) + { + other.object_fns_ = object_fns_table(); + other.target_fns_ = target_fns_table(); + other.blocking_ = execution::blocking_t(); + object_fns_->move(*this, other); + other.target_ = 0; + } + + any_executor_base& operator=( + any_executor_base&& other) BOOST_ASIO_NOEXCEPT + { + if (this != &other) + { + object_fns_->destroy(*this); + object_fns_ = other.object_fns_; + other.object_fns_ = object_fns_table(); + target_fns_ = other.target_fns_; + other.target_fns_ = target_fns_table(); + blocking_ = other.blocking_; + other.blocking_ = execution::blocking_t(); + object_fns_->move(*this, other); + other.target_ = 0; + } + return *this; + } + +#endif // defined(BOOST_ASIO_HAS_MOVE) + + template + void execute(BOOST_ASIO_MOVE_ARG(F) f) const + { + if (blocking_ == execution::blocking.always) + { + boost::asio::detail::non_const_lvalue f2(f); + target_fns_->blocking_execute(*this, function_view(f2.value)); + } + else + { + target_fns_->execute(*this, + function(BOOST_ASIO_MOVE_CAST(F)(f), std::allocator())); + } + } + + template + Executor* target() + { + return static_cast(target_); + } + + template + const Executor* target() const + { + return static_cast(target_); + } + + const std::type_info& target_type() const + { + return target_fns_->target_type(); + } + + struct unspecified_bool_type_t {}; + typedef void (*unspecified_bool_type)(unspecified_bool_type_t); + static void unspecified_bool_true(unspecified_bool_type_t) {} + + operator unspecified_bool_type() const BOOST_ASIO_NOEXCEPT + { + return target_ ? &any_executor_base::unspecified_bool_true : 0; + } + + bool operator!() const BOOST_ASIO_NOEXCEPT + { + return target_ == 0; + } + +protected: + bool equality_helper(const any_executor_base& other) const BOOST_ASIO_NOEXCEPT + { + if (target_ == other.target_) + return true; + if (target_ && !other.target_) + return false; + if (!target_ && other.target_) + return false; + if (target_fns_ != other.target_fns_) + return false; + return target_fns_->equal(*this, other); + } + + template + Ex& object() + { + return *static_cast(static_cast(&object_)); + } + + template + const Ex& object() const + { + return *static_cast(static_cast(&object_)); + } + + struct object_fns + { + void (*destroy)(any_executor_base&); + void (*copy)(any_executor_base&, const any_executor_base&); + void (*move)(any_executor_base&, any_executor_base&); + const void* (*target)(const any_executor_base&); + }; + + static void destroy_void(any_executor_base&) + { + } + + static void copy_void(any_executor_base&, const any_executor_base&) + { + } + + static void move_void(any_executor_base&, any_executor_base&) + { + } + + static const void* target_void(const any_executor_base&) + { + return 0; + } + + template + static const object_fns* object_fns_table( + typename enable_if< + is_same::value + >::type* = 0) + { + static const object_fns fns = + { + &any_executor_base::destroy_void, + &any_executor_base::copy_void, + &any_executor_base::move_void, + &any_executor_base::target_void + }; + return &fns; + } + + static void destroy_shared(any_executor_base& ex) + { + typedef boost::asio::detail::shared_ptr type; + ex.object().~type(); + } + + static void copy_shared(any_executor_base& ex1, const any_executor_base& ex2) + { + typedef boost::asio::detail::shared_ptr type; + new (&ex1.object_) type(ex2.object()); + ex1.target_ = ex2.target_; + } + + static void move_shared(any_executor_base& ex1, any_executor_base& ex2) + { + typedef boost::asio::detail::shared_ptr type; + new (&ex1.object_) type(BOOST_ASIO_MOVE_CAST(type)(ex2.object())); + ex1.target_ = ex2.target_; + ex2.object().~type(); + } + + static const void* target_shared(const any_executor_base& ex) + { + typedef boost::asio::detail::shared_ptr type; + return ex.object().get(); + } + + template + static const object_fns* object_fns_table( + typename enable_if< + is_same >::value + >::type* = 0) + { + static const object_fns fns = + { + &any_executor_base::destroy_shared, + &any_executor_base::copy_shared, + &any_executor_base::move_shared, + &any_executor_base::target_shared + }; + return &fns; + } + + template + static void destroy_object(any_executor_base& ex) + { + ex.object().~Obj(); + } + + template + static void copy_object(any_executor_base& ex1, const any_executor_base& ex2) + { + new (&ex1.object_) Obj(ex2.object()); + ex1.target_ = &ex1.object(); + } + + template + static void move_object(any_executor_base& ex1, any_executor_base& ex2) + { + new (&ex1.object_) Obj(BOOST_ASIO_MOVE_CAST(Obj)(ex2.object())); + ex1.target_ = &ex1.object(); + ex2.object().~Obj(); + } + + template + static const void* target_object(const any_executor_base& ex) + { + return &ex.object(); + } + + template + static const object_fns* object_fns_table( + typename enable_if< + !is_same::value + && !is_same >::value + >::type* = 0) + { + static const object_fns fns = + { + &any_executor_base::destroy_object, + &any_executor_base::copy_object, + &any_executor_base::move_object, + &any_executor_base::target_object + }; + return &fns; + } + + typedef boost::asio::detail::executor_function function; + typedef boost::asio::detail::executor_function_view function_view; + + struct target_fns + { + const std::type_info& (*target_type)(); + bool (*equal)(const any_executor_base&, const any_executor_base&); + void (*execute)(const any_executor_base&, BOOST_ASIO_MOVE_ARG(function)); + void (*blocking_execute)(const any_executor_base&, function_view); + }; + + static const std::type_info& target_type_void() + { + return typeid(void); + } + + static bool equal_void(const any_executor_base&, const any_executor_base&) + { + return true; + } + + static void execute_void(const any_executor_base&, + BOOST_ASIO_MOVE_ARG(function)) + { + bad_executor ex; + boost::asio::detail::throw_exception(ex); + } + + static void blocking_execute_void(const any_executor_base&, function_view) + { + bad_executor ex; + boost::asio::detail::throw_exception(ex); + } + + template + static const target_fns* target_fns_table( + typename enable_if< + is_same::value + >::type* = 0) + { + static const target_fns fns = + { + &any_executor_base::target_type_void, + &any_executor_base::equal_void, + &any_executor_base::execute_void, + &any_executor_base::blocking_execute_void + }; + return &fns; + } + + template + static const std::type_info& target_type_ex() + { + return typeid(Ex); + } + + template + static bool equal_ex(const any_executor_base& ex1, + const any_executor_base& ex2) + { + return *ex1.target() == *ex2.target(); + } + + template + static void execute_ex(const any_executor_base& ex, + BOOST_ASIO_MOVE_ARG(function) f) + { + ex.target()->execute(BOOST_ASIO_MOVE_CAST(function)(f)); + } + + template + static void blocking_execute_ex(const any_executor_base& ex, function_view f) + { + ex.target()->execute(f); + } + + template + static const target_fns* target_fns_table( + typename enable_if< + !is_same::value + >::type* = 0) + { + static const target_fns fns = + { + &any_executor_base::target_type_ex, + &any_executor_base::equal_ex, + &any_executor_base::execute_ex, + &any_executor_base::blocking_execute_ex + }; + return &fns; + } + +#if defined(BOOST_ASIO_MSVC) +# pragma warning (push) +# pragma warning (disable:4702) +#endif // defined(BOOST_ASIO_MSVC) + + template + static void query_fn_impl(void*, const void*, const void*, + typename enable_if< + is_same::value + >::type*) + { + bad_executor ex; + boost::asio::detail::throw_exception(ex); + } + + template + static void query_fn_impl(void*, const void* ex, const void* prop, + typename enable_if< + !is_same::value + && boost::asio::can_query::value + && is_same::value + >::type*) + { + boost::asio::query(*static_cast(ex), + *static_cast(prop)); + } + + template + static void query_fn_impl(void*, const void*, const void*, + typename enable_if< + !is_same::value + && !boost::asio::can_query::value + && is_same::value + >::type*) + { + } + + template + static void query_fn_impl(void* result, const void* ex, const void* prop, + typename enable_if< + !is_same::value + && boost::asio::can_query::value + && !is_same::value + && is_reference::value + >::type*) + { + *static_cast::type**>(result) + = &static_cast( + boost::asio::query(*static_cast(ex), + *static_cast(prop))); + } + + template + static void query_fn_impl(void*, const void*, const void*, + typename enable_if< + !is_same::value + && !boost::asio::can_query::value + && !is_same::value + && is_reference::value + >::type*) + { + std::terminate(); // Combination should not be possible. + } + + template + static void query_fn_impl(void* result, const void* ex, const void* prop, + typename enable_if< + !is_same::value + && boost::asio::can_query::value + && !is_same::value + && is_scalar::value + >::type*) + { + *static_cast(result) + = static_cast( + boost::asio::query(*static_cast(ex), + *static_cast(prop))); + } + + template + static void query_fn_impl(void* result, const void*, const void*, + typename enable_if< + !is_same::value + && !boost::asio::can_query::value + && !is_same::value + && is_scalar::value + >::type*) + { + *static_cast(result) + = typename Prop::polymorphic_query_result_type(); + } + + template + static void query_fn_impl(void* result, const void* ex, const void* prop, + typename enable_if< + !is_same::value + && boost::asio::can_query::value + && !is_same::value + && !is_reference::value + && !is_scalar::value + >::type*) + { + *static_cast(result) + = new typename Prop::polymorphic_query_result_type( + boost::asio::query(*static_cast(ex), + *static_cast(prop))); + } + + template + static void query_fn_impl(void* result, const void*, const void*, ...) + { + *static_cast(result) + = new typename Prop::polymorphic_query_result_type(); + } + + template + static void query_fn(void* result, const void* ex, const void* prop) + { + query_fn_impl(result, ex, prop, 0); + } + + template + static Poly require_fn_impl(const void*, const void*, + typename enable_if< + is_same::value + >::type*) + { + bad_executor ex; + boost::asio::detail::throw_exception(ex); + return Poly(); + } + + template + static Poly require_fn_impl(const void* ex, const void* prop, + typename enable_if< + !is_same::value && Prop::is_requirable + >::type*) + { + return boost::asio::require(*static_cast(ex), + *static_cast(prop)); + } + + template + static Poly require_fn_impl(const void*, const void*, ...) + { + return Poly(); + } + + template + static Poly require_fn(const void* ex, const void* prop) + { + return require_fn_impl(ex, prop, 0); + } + + template + static Poly prefer_fn_impl(const void*, const void*, + typename enable_if< + is_same::value + >::type*) + { + bad_executor ex; + boost::asio::detail::throw_exception(ex); + return Poly(); + } + + template + static Poly prefer_fn_impl(const void* ex, const void* prop, + typename enable_if< + !is_same::value && Prop::is_preferable + >::type*) + { + return boost::asio::prefer(*static_cast(ex), + *static_cast(prop)); + } + + template + static Poly prefer_fn_impl(const void*, const void*, ...) + { + return Poly(); + } + + template + static Poly prefer_fn(const void* ex, const void* prop) + { + return prefer_fn_impl(ex, prop, 0); + } + + template + struct prop_fns + { + void (*query)(void*, const void*, const void*); + Poly (*require)(const void*, const void*); + Poly (*prefer)(const void*, const void*); + }; + +#if defined(BOOST_ASIO_MSVC) +# pragma warning (pop) +#endif // defined(BOOST_ASIO_MSVC) + +private: + template + static execution::blocking_t query_blocking(const Executor& ex, true_type) + { + return boost::asio::query(ex, execution::blocking); + } + + template + static execution::blocking_t query_blocking(const Executor&, false_type) + { + return execution::blocking_t(); + } + + template + void construct_object(Executor& ex, true_type) + { + object_fns_ = object_fns_table(); + target_ = new (&object_) Executor(BOOST_ASIO_MOVE_CAST(Executor)(ex)); + } + + template + void construct_object(Executor& ex, false_type) + { + object_fns_ = object_fns_table >(); + boost::asio::detail::shared_ptr p = + boost::asio::detail::make_shared( + BOOST_ASIO_MOVE_CAST(Executor)(ex)); + target_ = p.get(); + new (&object_) boost::asio::detail::shared_ptr( + BOOST_ASIO_MOVE_CAST(boost::asio::detail::shared_ptr)(p)); + } + +/*private:*/public: +// template friend class any_executor; + + typedef aligned_storage< + sizeof(boost::asio::detail::shared_ptr), + alignment_of >::value + >::type object_type; + + object_type object_; + const object_fns* object_fns_; + void* target_; + const target_fns* target_fns_; + execution::blocking_t blocking_; +}; + +template +struct any_executor_context +{ +}; + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) + +template +struct any_executor_context::type> +{ + typename Property::query_result_type context() const + { + return static_cast(this)->query(typename Property::type()); + } +}; + +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) + +} // namespace detail + +template <> +class any_executor<> : public detail::any_executor_base +{ +public: + any_executor() BOOST_ASIO_NOEXCEPT + : detail::any_executor_base() + { + } + + template + any_executor(Executor ex) + : detail::any_executor_base( + BOOST_ASIO_MOVE_CAST(Executor)(ex), false_type()) + { + BOOST_ASIO_STATIC_ASSERT(is_executor::value, + any_executor_target_must_be_an_executor, + "any_executor target must be an executor"); + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + any_executor(any_executor other) + : detail::any_executor_base( + static_cast(other)) + { + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + any_executor(any_executor other) + : detail::any_executor_base( + static_cast(other)) + { + } + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + any_executor(const any_executor& other) BOOST_ASIO_NOEXCEPT + : detail::any_executor_base( + static_cast(other)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + + any_executor(any_executor&& other) BOOST_ASIO_NOEXCEPT + : detail::any_executor_base( + static_cast( + static_cast(other))) + { + } + +#endif // defined(BOOST_ASIO_HAS_MOVE) + + using detail::any_executor_base::operator=; + using detail::any_executor_base::execute; + using detail::any_executor_base::target; + using detail::any_executor_base::target_type; + using detail::any_executor_base::operator unspecified_bool_type; + using detail::any_executor_base::operator!; + + bool equality_helper(const any_executor& other) const BOOST_ASIO_NOEXCEPT + { + return any_executor_base::equality_helper(other); + } +}; + +inline bool operator==(const any_executor<>& a, + const any_executor<>& b) BOOST_ASIO_NOEXCEPT +{ + return a.equality_helper(b); +} + +inline bool operator!=(const any_executor<>& a, + const any_executor<>& b) BOOST_ASIO_NOEXCEPT +{ + return !a.equality_helper(b); +} + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +class any_executor : + public detail::any_executor_base, + public detail::any_executor_context< + any_executor, + typename detail::supportable_properties< + 0, void(SupportableProperties...)>::find_context_as_property> +{ +public: + any_executor() BOOST_ASIO_NOEXCEPT + : detail::any_executor_base(), + prop_fns_(prop_fns_table()) + { + } + + template + any_executor(Executor ex) + : detail::any_executor_base( + BOOST_ASIO_MOVE_CAST(Executor)(ex), false_type()), + prop_fns_(prop_fns_table()) + { + BOOST_ASIO_STATIC_ASSERT(is_executor::value, + any_executor_target_must_be_an_executor, + "any_executor target must be an executor"); + + BOOST_ASIO_STATIC_ASSERT( + (detail::supportable_properties< + 0, void(SupportableProperties...)>::template + is_valid_target::value), + any_executor_target_must_support_listed_properties, + "any_executor target must support listed properties"); + } + + template + any_executor(any_executor other) + : detail::any_executor_base(BOOST_ASIO_MOVE_CAST( + any_executor)(other), true_type()), + prop_fns_(prop_fns_table >()) + { + BOOST_ASIO_STATIC_ASSERT( + (detail::supportable_properties< + 0, void(SupportableProperties...)>::template is_valid_target< + any_executor >::value), + any_executor_target_must_support_listed_properties, + "any_executor target must support listed properties"); + } + + any_executor(const any_executor& other) BOOST_ASIO_NOEXCEPT + : detail::any_executor_base( + static_cast(other)), + prop_fns_(other.prop_fns_) + { + } + + any_executor& operator=(const any_executor& other) BOOST_ASIO_NOEXCEPT + { + if (this != &other) + { + prop_fns_ = other.prop_fns_; + detail::any_executor_base::operator=( + static_cast(other)); + } + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + + any_executor(any_executor&& other) BOOST_ASIO_NOEXCEPT + : detail::any_executor_base( + static_cast( + static_cast(other))), + prop_fns_(other.prop_fns_) + { + other.prop_fns_ = prop_fns_table(); + } + + any_executor& operator=(any_executor&& other) BOOST_ASIO_NOEXCEPT + { + if (this != &other) + { + prop_fns_ = other.prop_fns_; + detail::any_executor_base::operator=( + static_cast( + static_cast(other))); + } + return *this; + } + +#endif // defined(BOOST_ASIO_HAS_MOVE) + + using detail::any_executor_base::execute; + using detail::any_executor_base::target; + using detail::any_executor_base::target_type; + using detail::any_executor_base::operator unspecified_bool_type; + using detail::any_executor_base::operator!; + + bool equality_helper(const any_executor& other) const BOOST_ASIO_NOEXCEPT + { + return any_executor_base::equality_helper(other); + } + + template + struct find_convertible_property : + detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_property {}; + + template + void query(const Property& p, + typename enable_if< + is_same< + typename find_convertible_property::query_result_type, + void + >::value + >::type* = 0) const + { + typedef find_convertible_property found; + prop_fns_[found::index].query(0, object_fns_->target(*this), + &static_cast(p)); + } + + template + typename find_convertible_property::query_result_type + query(const Property& p, + typename enable_if< + !is_same< + typename find_convertible_property::query_result_type, + void + >::value + && + is_reference< + typename find_convertible_property::query_result_type + >::value + >::type* = 0) const + { + typedef find_convertible_property found; + typename remove_reference< + typename found::query_result_type>::type* result = 0; + prop_fns_[found::index].query(&result, object_fns_->target(*this), + &static_cast(p)); + return *result; + } + + template + typename find_convertible_property::query_result_type + query(const Property& p, + typename enable_if< + !is_same< + typename find_convertible_property::query_result_type, + void + >::value + && + is_scalar< + typename find_convertible_property::query_result_type + >::value + >::type* = 0) const + { + typedef find_convertible_property found; + typename found::query_result_type result; + prop_fns_[found::index].query(&result, object_fns_->target(*this), + &static_cast(p)); + return result; + } + + template + typename find_convertible_property::query_result_type + query(const Property& p, + typename enable_if< + !is_same< + typename find_convertible_property::query_result_type, + void + >::value + && + !is_reference< + typename find_convertible_property::query_result_type + >::value + && + !is_scalar< + typename find_convertible_property::query_result_type + >::value + >::type* = 0) const + { + typedef find_convertible_property found; + typename found::query_result_type* result; + prop_fns_[found::index].query(&result, object_fns_->target(*this), + &static_cast(p)); + return *boost::asio::detail::scoped_ptr< + typename found::query_result_type>(result); + } + + template + struct find_convertible_requirable_property : + detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_requirable_property {}; + + template + any_executor require(const Property& p, + typename enable_if< + find_convertible_requirable_property::value + >::type* = 0) const + { + typedef find_convertible_requirable_property found; + return prop_fns_[found::index].require(object_fns_->target(*this), + &static_cast(p)); + } + + template + struct find_convertible_preferable_property : + detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_preferable_property {}; + + template + any_executor prefer(const Property& p, + typename enable_if< + find_convertible_preferable_property::value + >::type* = 0) const + { + typedef find_convertible_preferable_property found; + return prop_fns_[found::index].prefer(object_fns_->target(*this), + &static_cast(p)); + } + +//private: + template + static const prop_fns* prop_fns_table() + { + static const prop_fns fns[] = + { + { + &detail::any_executor_base::query_fn< + Ex, SupportableProperties>, + &detail::any_executor_base::require_fn< + any_executor, Ex, SupportableProperties>, + &detail::any_executor_base::prefer_fn< + any_executor, Ex, SupportableProperties> + }... + }; + return fns; + } + + const prop_fns* prop_fns_; +}; + +template +inline bool operator==(const any_executor& a, + const any_executor& b) BOOST_ASIO_NOEXCEPT +{ + return a.equality_helper(b); +} + +template +inline bool operator!=(const any_executor& a, + const any_executor& b) BOOST_ASIO_NOEXCEPT +{ + return !a.equality_helper(b); +} + +template +struct is_executor > : true_type +{ +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \ + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_##n + +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1 \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2 \ + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3 \ + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4 \ + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5 \ + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6 \ + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7 \ + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8 \ + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7, \ + { \ + &detail::any_executor_base::query_fn, \ + &detail::any_executor_base::require_fn, \ + &detail::any_executor_base::prefer_fn \ + } + +#if defined(BOOST_ASIO_HAS_MOVE) + +# define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \ + any_executor(any_executor&& other) BOOST_ASIO_NOEXCEPT \ + : detail::any_executor_base( \ + static_cast( \ + static_cast(other))), \ + prop_fns_(other.prop_fns_) \ + { \ + other.prop_fns_ = prop_fns_table(); \ + } \ + \ + any_executor& operator=(any_executor&& other) BOOST_ASIO_NOEXCEPT \ + { \ + if (this != &other) \ + { \ + prop_fns_ = other.prop_fns_; \ + detail::any_executor_base::operator=( \ + static_cast( \ + static_cast(other))); \ + } \ + return *this; \ + } \ + /**/ +#else // defined(BOOST_ASIO_HAS_MOVE) + +# define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS + +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_DEF(n) \ + template \ + class any_executor : \ + public detail::any_executor_base, \ + public detail::any_executor_context< \ + any_executor, \ + typename detail::supportable_properties< \ + 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::find_context_as_property> \ + { \ + public: \ + any_executor() BOOST_ASIO_NOEXCEPT \ + : detail::any_executor_base(), \ + prop_fns_(prop_fns_table()) \ + { \ + } \ + \ + template \ + any_executor(Executor ex, \ + typename enable_if< \ + !is_base_of< \ + detail::any_executor_base, \ + Executor \ + >::value \ + >::type* = 0) \ + : detail::any_executor_base(BOOST_ASIO_MOVE_CAST( \ + Executor)(ex), false_type()), \ + prop_fns_(prop_fns_table()) \ + { \ + BOOST_ASIO_STATIC_ASSERT(is_executor::value, \ + any_executor_target_must_be_an_executor, \ + "any_executor target must be an executor"); \ + \ + BOOST_ASIO_STATIC_ASSERT( \ + (detail::supportable_properties< \ + 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ + is_valid_target::value), \ + any_executor_target_must_support_listed_properties, \ + "any_executor target must support listed properties"); \ + } \ + \ + any_executor(const any_executor& other) BOOST_ASIO_NOEXCEPT \ + : detail::any_executor_base( \ + static_cast(other)), \ + prop_fns_(other.prop_fns_) \ + { \ + } \ + \ + any_executor(any_executor<> other) \ + : detail::any_executor_base(BOOST_ASIO_MOVE_CAST( \ + any_executor<>)(other), true_type()), \ + prop_fns_(prop_fns_table >()) \ + { \ + } \ + \ + template \ + any_executor(OtherAnyExecutor other, \ + typename enable_if< \ + is_base_of< \ + detail::any_executor_base, \ + OtherAnyExecutor \ + >::value \ + >::type* = 0) \ + : detail::any_executor_base(BOOST_ASIO_MOVE_CAST( \ + OtherAnyExecutor)(other), true_type()), \ + prop_fns_(prop_fns_table()) \ + { \ + BOOST_ASIO_STATIC_ASSERT( \ + OtherAnyExecutor::supportable_properties_type::template \ + is_valid_target >::value, \ + any_executor_target_must_support_listed_properties, \ + "any_executor target must support listed properties"); \ + } \ + \ + any_executor& operator=(const any_executor& other) BOOST_ASIO_NOEXCEPT \ + { \ + if (this != &other) \ + { \ + prop_fns_ = other.prop_fns_; \ + detail::any_executor_base::operator=( \ + static_cast(other)); \ + } \ + return *this; \ + } \ + \ + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \ + \ + using detail::any_executor_base::execute; \ + using detail::any_executor_base::target; \ + using detail::any_executor_base::target_type; \ + using detail::any_executor_base::operator unspecified_bool_type; \ + using detail::any_executor_base::operator!; \ + \ + bool equality_helper(const any_executor& other) const BOOST_ASIO_NOEXCEPT \ + { \ + return any_executor_base::equality_helper(other); \ + } \ + \ + template \ + struct find_convertible_property : \ + detail::supportable_properties< \ + 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_property {}; \ + \ + template \ + void query(const Property& p, \ + typename enable_if< \ + is_same< \ + typename find_convertible_property::query_result_type, \ + void \ + >::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_property found; \ + prop_fns_[found::index].query(0, object_fns_->target(*this), \ + &static_cast(p)); \ + } \ + \ + template \ + typename find_convertible_property::query_result_type \ + query(const Property& p, \ + typename enable_if< \ + !is_same< \ + typename find_convertible_property::query_result_type, \ + void \ + >::value \ + && \ + is_reference< \ + typename find_convertible_property::query_result_type \ + >::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_property found; \ + typename remove_reference< \ + typename found::query_result_type>::type* result; \ + prop_fns_[found::index].query(&result, object_fns_->target(*this), \ + &static_cast(p)); \ + return *result; \ + } \ + \ + template \ + typename find_convertible_property::query_result_type \ + query(const Property& p, \ + typename enable_if< \ + !is_same< \ + typename find_convertible_property::query_result_type, \ + void \ + >::value \ + && \ + is_scalar< \ + typename find_convertible_property::query_result_type \ + >::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_property found; \ + typename found::query_result_type result; \ + prop_fns_[found::index].query(&result, object_fns_->target(*this), \ + &static_cast(p)); \ + return result; \ + } \ + \ + template \ + typename find_convertible_property::query_result_type \ + query(const Property& p, \ + typename enable_if< \ + !is_same< \ + typename find_convertible_property::query_result_type, \ + void \ + >::value \ + && \ + !is_reference< \ + typename find_convertible_property::query_result_type \ + >::value \ + && \ + !is_scalar< \ + typename find_convertible_property::query_result_type \ + >::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_property found; \ + typename found::query_result_type* result; \ + prop_fns_[found::index].query(&result, object_fns_->target(*this), \ + &static_cast(p)); \ + return *boost::asio::detail::scoped_ptr< \ + typename found::query_result_type>(result); \ + } \ + \ + template \ + struct find_convertible_requirable_property : \ + detail::supportable_properties< \ + 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_requirable_property {}; \ + \ + template \ + any_executor require(const Property& p, \ + typename enable_if< \ + find_convertible_requirable_property::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_requirable_property found; \ + return prop_fns_[found::index].require(object_fns_->target(*this), \ + &static_cast(p)); \ + } \ + \ + template \ + struct find_convertible_preferable_property : \ + detail::supportable_properties< \ + 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_preferable_property {}; \ + \ + template \ + any_executor prefer(const Property& p, \ + typename enable_if< \ + find_convertible_preferable_property::value \ + >::type* = 0) const \ + { \ + typedef find_convertible_preferable_property found; \ + return prop_fns_[found::index].prefer(object_fns_->target(*this), \ + &static_cast(p)); \ + } \ + \ + template \ + static const prop_fns* prop_fns_table() \ + { \ + static const prop_fns fns[] = \ + { \ + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \ + }; \ + return fns; \ + } \ + \ + const prop_fns* prop_fns_; \ + typedef detail::supportable_properties<0, \ + void(BOOST_ASIO_VARIADIC_TARGS(n))> supportable_properties_type; \ + }; \ + \ + template \ + inline bool operator==(const any_executor& a, \ + const any_executor& b) BOOST_ASIO_NOEXCEPT \ + { \ + return a.equality_helper(b); \ + } \ + \ + template \ + inline bool operator!=(const any_executor& a, \ + const any_executor& b) BOOST_ASIO_NOEXCEPT \ + { \ + return !a.equality_helper(b); \ + } \ + \ + template \ + struct is_executor > : true_type \ + { \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ANY_EXECUTOR_DEF) +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_DEF +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1 +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2 +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3 +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4 +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5 +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6 +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7 +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8 + +#endif // if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +} // namespace execution +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct execute_member, F> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef void result_type; +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct execute_member, F> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef void result_type; +}; + +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF(n) \ + template \ + struct execute_member< \ + execution::any_executor, F> \ + { \ + static const bool is_valid = true; \ + static const bool is_noexcept = false; \ + typedef void result_type; \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE( + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF) +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct query_member< + execution::any_executor, Prop, + typename enable_if< + execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_property::value + >::type> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef typename execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_property::query_result_type result_type; +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF(n) \ + template \ + struct query_member< \ + execution::any_executor, Prop, \ + typename enable_if< \ + execution::detail::supportable_properties< \ + 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_property::value \ + >::type> \ + { \ + static const bool is_valid = true; \ + static const bool is_noexcept = false; \ + typedef typename execution::detail::supportable_properties< \ + 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_property::query_result_type result_type; \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF) +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct require_member< + execution::any_executor, Prop, + typename enable_if< + execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_requirable_property::value + >::type> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef execution::any_executor result_type; +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF(n) \ + template \ + struct require_member< \ + execution::any_executor, Prop, \ + typename enable_if< \ + execution::detail::supportable_properties< \ + 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_requirable_property::value \ + >::type> \ + { \ + static const bool is_valid = true; \ + static const bool is_noexcept = false; \ + typedef execution::any_executor result_type; \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE( + BOOST_ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF) +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct prefer_member< + execution::any_executor, Prop, + typename enable_if< + execution::detail::supportable_properties< + 0, void(SupportableProperties...)>::template + find_convertible_preferable_property::value + >::type> +{ + static const bool is_valid = true; + static const bool is_noexcept = false; + typedef execution::any_executor result_type; +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF(n) \ + template \ + struct prefer_member< \ + execution::any_executor, Prop, \ + typename enable_if< \ + execution::detail::supportable_properties< \ + 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ + find_convertible_preferable_property::value \ + >::type> \ + { \ + static const bool is_valid = true; \ + static const bool is_noexcept = false; \ + typedef execution::any_executor result_type; \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF) +#undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_ANY_EXECUTOR_HPP diff --git a/include/boost/asio/execution/bad_executor.hpp b/include/boost/asio/execution/bad_executor.hpp new file mode 100644 index 00000000..c73d8763 --- /dev/null +++ b/include/boost/asio/execution/bad_executor.hpp @@ -0,0 +1,49 @@ +// +// execution/bad_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_BAD_EXECUTOR_HPP +#define BOOST_ASIO_EXECUTION_BAD_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +namespace boost { +namespace asio { +namespace execution { + +/// Exception thrown when trying to access an empty polymorphic executor. +class bad_executor + : public std::exception +{ +public: + /// Constructor. + BOOST_ASIO_DECL bad_executor() BOOST_ASIO_NOEXCEPT; + + /// Obtain message associated with exception. + BOOST_ASIO_DECL virtual const char* what() const + BOOST_ASIO_NOEXCEPT_OR_NOTHROW; +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_EXECUTION_BAD_EXECUTOR_HPP diff --git a/include/boost/asio/execution/impl/bad_executor.ipp b/include/boost/asio/execution/impl/bad_executor.ipp new file mode 100644 index 00000000..4729a64b --- /dev/null +++ b/include/boost/asio/execution/impl/bad_executor.ipp @@ -0,0 +1,42 @@ +// +// exection/impl/bad_executor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP +#define BOOST_ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace execution { + +bad_executor::bad_executor() BOOST_ASIO_NOEXCEPT +{ +} + +const char* bad_executor::what() const BOOST_ASIO_NOEXCEPT_OR_NOTHROW +{ + return "bad executor"; +} + +} // namespace execution +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP diff --git a/include/boost/asio/executor.hpp b/include/boost/asio/executor.hpp index a71c8b5a..d3c8268c 100644 --- a/include/boost/asio/executor.hpp +++ b/include/boost/asio/executor.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -254,7 +255,7 @@ public: private: #if !defined(GENERATING_DOCUMENTATION) - class function; + typedef detail::executor_function function; template class impl; #if !defined(BOOST_ASIO_NO_TYPEID) diff --git a/include/boost/asio/impl/executor.hpp b/include/boost/asio/impl/executor.hpp index 58f78f37..7a3a097d 100644 --- a/include/boost/asio/impl/executor.hpp +++ b/include/boost/asio/impl/executor.hpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -31,98 +30,6 @@ namespace asio { #if !defined(GENERATING_DOCUMENTATION) -#if defined(BOOST_ASIO_HAS_MOVE) - -// Lightweight, move-only function object wrapper. -class executor::function -{ -public: - template - explicit function(F f, const Alloc& a) - { - // Allocate and construct an operation to wrap the function. - typedef detail::executor_function func_type; - typename func_type::ptr p = { - detail::addressof(a), func_type::ptr::allocate(a), 0 }; - func_ = new (p.v) func_type(BOOST_ASIO_MOVE_CAST(F)(f), a); - p.v = 0; - } - - function(function&& other) BOOST_ASIO_NOEXCEPT - : func_(other.func_) - { - other.func_ = 0; - } - - ~function() - { - if (func_) - func_->destroy(); - } - - void operator()() - { - if (func_) - { - detail::executor_function_base* func = func_; - func_ = 0; - func->complete(); - } - } - -private: - detail::executor_function_base* func_; -}; - -#else // defined(BOOST_ASIO_HAS_MOVE) - -// Not so lightweight, copyable function object wrapper. -class executor::function -{ -public: - template - explicit function(const F& f, const Alloc&) - : impl_(new impl(f)) - { - } - - void operator()() - { - impl_->invoke_(impl_.get()); - } - -private: - // Base class for polymorphic function implementations. - struct impl_base - { - void (*invoke_)(impl_base*); - }; - - // Polymorphic function implementation. - template - struct impl : impl_base - { - impl(const F& f) - : function_(f) - { - invoke_ = &function::invoke; - } - - F function_; - }; - - // Helper to invoke a function. - template - static void invoke(impl_base* i) - { - static_cast*>(i)->function_(); - } - - detail::shared_ptr impl_; -}; - -#endif // defined(BOOST_ASIO_HAS_MOVE) - // Default polymorphic executor implementation. template class executor::impl diff --git a/include/boost/asio/impl/src.hpp b/include/boost/asio/impl/src.hpp index 56322b1e..40bd1aea 100644 --- a/include/boost/asio/impl/src.hpp +++ b/include/boost/asio/impl/src.hpp @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 index 37d28753..a3431073 100644 --- a/test/execution/Jamfile.v2 +++ b/test/execution/Jamfile.v2 @@ -41,6 +41,7 @@ project ; test-suite "asio" : + [ run any_executor.cpp ] [ run blocking.cpp ] [ run blocking_adaptation.cpp ] [ run bulk_guarantee.cpp ] diff --git a/test/execution/any_executor.cpp b/test/execution/any_executor.cpp new file mode 100644 index 00000000..69d15f57 --- /dev/null +++ b/test/execution/any_executor.cpp @@ -0,0 +1,139 @@ +// +// any_executor.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include "../unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +using namespace boost::asio; + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif + +void increment(int* count) +{ + ++(*count); +} + +void any_executor_executor_query_test() +{ + thread_pool pool(1); + execution::any_executor< + execution::blocking_t, + execution::outstanding_work_t, + execution::relationship_t, + execution::mapping_t::thread_t, + execution::occupancy_t> + ex(pool.executor()); + + BOOST_ASIO_CHECK( + boost::asio::query(ex, boost::asio::execution::blocking) + == boost::asio::execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex, boost::asio::execution::blocking.possibly) + == boost::asio::execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex, boost::asio::execution::outstanding_work) + == boost::asio::execution::outstanding_work.untracked); + + BOOST_ASIO_CHECK( + boost::asio::query(ex, boost::asio::execution::outstanding_work.untracked) + == boost::asio::execution::outstanding_work.untracked); + + BOOST_ASIO_CHECK( + boost::asio::query(ex, boost::asio::execution::relationship) + == boost::asio::execution::relationship.fork); + + BOOST_ASIO_CHECK( + boost::asio::query(ex, boost::asio::execution::relationship.fork) + == boost::asio::execution::relationship.fork); + + BOOST_ASIO_CHECK( + boost::asio::query(ex, boost::asio::execution::mapping) + == boost::asio::execution::mapping.thread); + + BOOST_ASIO_CHECK( + boost::asio::query(ex, boost::asio::execution::occupancy) + == 1); +} + +void any_executor_executor_execute_test() +{ + int count = 0; + thread_pool pool(1); + execution::any_executor< + execution::blocking_t::possibly_t, + execution::blocking_t::never_t, + execution::outstanding_work_t::untracked_t, + execution::outstanding_work_t::tracked_t, + execution::relationship_t::continuation_t> + ex(pool.executor()); + + boost::asio::execution::execute(pool.executor(), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.possibly), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.tracked), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + bindns::bind(increment, &count)); + + pool.wait(); + + BOOST_ASIO_CHECK(count == 6); +} + +BOOST_ASIO_TEST_SUITE +( + "any_executor", + BOOST_ASIO_TEST_CASE(any_executor_executor_query_test) + BOOST_ASIO_TEST_CASE(any_executor_executor_execute_test) +) From d2cb3bbdc6664ce63058894909187baebf0cce62 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:01:56 +1000 Subject: [PATCH 59/90] Add execution::prefer_only property adapter. --- include/boost/asio.hpp | 1 + include/boost/asio/execution/prefer_only.hpp | 329 ++++++++++++ test/execution/Jamfile.v2 | 1 + test/execution/prefer_only.cpp | 531 +++++++++++++++++++ 4 files changed, 862 insertions(+) create mode 100644 include/boost/asio/execution/prefer_only.hpp create mode 100644 test/execution/prefer_only.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 188d8bbc..252b8688 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution/prefer_only.hpp b/include/boost/asio/execution/prefer_only.hpp new file mode 100644 index 00000000..88d43015 --- /dev/null +++ b/include/boost/asio/execution/prefer_only.hpp @@ -0,0 +1,329 @@ +// +// execution/prefer_only.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_PREFER_ONLY_HPP +#define BOOST_ASIO_EXECUTION_PREFER_ONLY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that is used to obtain the execution context that is associated +/// with an executor. +template +struct prefer_only +{ + /// The context_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The context_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The context_t property can be preferred, it the underlying property can + /// be preferred. + /** + * @c true if @c Property::is_preferable is @c true, otherwise @c false. + */ + static constexpr bool is_preferable = automatically_determined; + + /// The type returned by queries against an @c any_executor. + typedef typename Property::polymorphic_query_result_type + polymorphic_query_result_type; +}; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { +namespace detail { + +template +struct prefer_only_is_preferable +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); +}; + +template +struct prefer_only_is_preferable::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); +}; + +template +struct prefer_only_polymorphic_query_result_type +{ +}; + +template +struct prefer_only_polymorphic_query_result_type::type> +{ + typedef typename InnerProperty::polymorphic_query_result_type + polymorphic_query_result_type; +}; + +template +struct prefer_only_property +{ + InnerProperty property; + + prefer_only_property(const InnerProperty& p) + : property(p) + { + } +}; + +#if defined(BOOST_ASIO_HAS_DECLTYPE) \ + && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +template +struct prefer_only_property().value()) + >::type> +{ + InnerProperty property; + + prefer_only_property(const InnerProperty& p) + : property(p) + { + } + + BOOST_ASIO_CONSTEXPR auto value() const + BOOST_ASIO_NOEXCEPT_IF(( + noexcept(boost::asio::declval().value()))) + -> decltype(boost::asio::declval().value()) + { + return property.value(); + } +}; + +#else // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +struct prefer_only_memfns_base +{ + void value(); +}; + +template +struct prefer_only_memfns_derived + : T, prefer_only_memfns_base +{ +}; + +template +struct prefer_only_memfns_check +{ +}; + +template +char (&prefer_only_value_memfn_helper(...))[2]; + +template +char prefer_only_value_memfn_helper( + prefer_only_memfns_check< + void (prefer_only_memfns_base::*)(), + &prefer_only_memfns_derived::value>*); + +template +struct prefer_only_property(0)) != 1 + && !is_same::value + >::type> +{ + InnerProperty property; + + prefer_only_property(const InnerProperty& p) + : property(p) + { + } + + BOOST_ASIO_CONSTEXPR typename InnerProperty::polymorphic_query_result_type + value() const + { + return property.value(); + } +}; + +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +} // namespace detail + +template +struct prefer_only : + detail::prefer_only_is_preferable, + detail::prefer_only_polymorphic_query_result_type, + detail::prefer_only_property +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + + BOOST_ASIO_CONSTEXPR prefer_only(const InnerProperty& p) + : detail::prefer_only_property(p) + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::static_query::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::static_query::is_noexcept)) + { + return traits::static_query::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const T static_query_v + = prefer_only::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + template + friend BOOST_ASIO_CONSTEXPR + typename prefer_result_type::type + prefer(const Executor& ex, const prefer_only& p, + typename enable_if< + is_same::value + && can_prefer::value + >::type* = 0) +#if !defined(BOOST_ASIO_MSVC) \ + && !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_prefer::value)) +#endif // !defined(BOOST_ASIO_MSVC) + // && !defined(__clang__) + { + return boost::asio::prefer(ex, p.property); + } + + template + friend BOOST_ASIO_CONSTEXPR + typename query_result_type::type + query(const Executor& ex, const prefer_only& p, + typename enable_if< + is_same::value + && can_query::value + >::type* = 0) +#if !defined(BOOST_ASIO_MSVC) \ + && !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(BOOST_ASIO_MSVC) + // && !defined(__clang__) + { + return boost::asio::query(ex, p.property); + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const T prefer_only::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +} // namespace execution + +template +struct is_applicable_property > + : is_applicable_property +{ +}; + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query > : + static_query +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +template +struct prefer_free_default, + typename enable_if< + can_prefer::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_prefer::value)); + + typedef typename prefer_result_type::type result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free, + typename enable_if< + can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef typename query_result_type::type result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_PREFER_ONLY_HPP diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 index a3431073..e0b30db8 100644 --- a/test/execution/Jamfile.v2 +++ b/test/execution/Jamfile.v2 @@ -49,5 +49,6 @@ test-suite "asio" : [ run invocable_archetype.cpp ] [ run mapping.cpp ] [ run outstanding_work.cpp ] + [ run prefer_only.cpp ] [ run relationship.cpp ] ; diff --git a/test/execution/prefer_only.cpp b/test/execution/prefer_only.cpp new file mode 100644 index 00000000..6f04ddfb --- /dev/null +++ b/test/execution/prefer_only.cpp @@ -0,0 +1,531 @@ +// +// prefer_only.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include "../unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +using namespace boost::asio; + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif + +static int possibly_blocking_count = 0; +static int never_blocking_count = 0; + +struct possibly_blocking_executor +{ + template + void execute(const F&) const + { + ++possibly_blocking_count; + } + + friend bool operator==(const possibly_blocking_executor&, + const possibly_blocking_executor&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const possibly_blocking_executor&, + const possibly_blocking_executor&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template <> +struct is_executor : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +struct never_blocking_executor +{ + static BOOST_ASIO_CONSTEXPR execution::blocking_t::never_t + query(execution::blocking_t) BOOST_ASIO_NOEXCEPT + { + return execution::blocking_t::never_t(); + } + + template + void execute(const F&) const + { + ++never_blocking_count; + } + + friend bool operator==(const never_blocking_executor&, + const never_blocking_executor&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + friend bool operator!=(const never_blocking_executor&, + const never_blocking_executor&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template <> +struct is_executor : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +template +struct query_static_constexpr_member< + never_blocking_executor, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::blocking_t::never_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() + { + return result_type(); + } +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +struct either_blocking_executor +{ + execution::blocking_t blocking_; + + explicit either_blocking_executor(execution::blocking_t b) + : blocking_(b) + { + } + + execution::blocking_t query(execution::blocking_t) const BOOST_ASIO_NOEXCEPT + { + return blocking_; + } + + either_blocking_executor require(execution::blocking_t::possibly_t) const + { + return either_blocking_executor(execution::blocking.possibly); + } + + either_blocking_executor require(execution::blocking_t::never_t) const + { + return either_blocking_executor(execution::blocking.never); + } + + template + void execute(const F&) const + { + if (blocking_ == execution::blocking.never) + ++never_blocking_count; + else + ++possibly_blocking_count; + } + + friend bool operator==(const either_blocking_executor& a, + const either_blocking_executor& b) BOOST_ASIO_NOEXCEPT + { + return a.blocking_ == b.blocking_; + } + + friend bool operator!=(const either_blocking_executor& a, + const either_blocking_executor& b) BOOST_ASIO_NOEXCEPT + { + return a.blocking_ != b.blocking_; + } +}; + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +namespace boost { +namespace asio { +namespace execution { + +template <> +struct is_executor : boost::asio::true_type +{ +}; + +} // namespace execution +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +template +struct query_member< + either_blocking_executor, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + + typedef execution::blocking_t result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +namespace boost { +namespace asio { +namespace traits { + +template +struct require_member< + either_blocking_executor, Param, + typename boost::asio::enable_if< + boost::asio::is_convertible::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + + typedef either_blocking_executor result_type; +}; + +} // namespace traits +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +void prefer_only_executor_query_test() +{ + typedef execution::any_executor< + execution::blocking_t, + execution::prefer_only, + execution::prefer_only + > executor_type; + + executor_type ex1 = possibly_blocking_executor(); + + BOOST_ASIO_CHECK( + boost::asio::query(ex1, execution::blocking) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex1, execution::blocking.possibly) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex1, execution::blocking.never) + == execution::blocking.possibly); + + executor_type ex2 = boost::asio::prefer(ex1, execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex2, execution::blocking) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex2, execution::blocking.possibly) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex2, execution::blocking.never) + == execution::blocking.possibly); + + executor_type ex3 = boost::asio::prefer(ex1, execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex3, execution::blocking) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex3, execution::blocking.possibly) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex3, execution::blocking.never) + == execution::blocking.possibly); + + executor_type ex4 = never_blocking_executor(); + + BOOST_ASIO_CHECK( + boost::asio::query(ex4, execution::blocking) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex4, execution::blocking.possibly) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex4, execution::blocking.never) + == execution::blocking.never); + + executor_type ex5 = boost::asio::prefer(ex4, execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex5, execution::blocking) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex5, execution::blocking.possibly) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex5, execution::blocking.never) + == execution::blocking.never); + + executor_type ex6 = boost::asio::prefer(ex4, execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex6, execution::blocking) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex6, execution::blocking.possibly) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex6, execution::blocking.never) + == execution::blocking.never); + + executor_type ex7 = either_blocking_executor(execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex7, execution::blocking) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex7, execution::blocking.possibly) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex7, execution::blocking.never) + == execution::blocking.possibly); + + executor_type ex8 = boost::asio::prefer(ex7, execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex8, execution::blocking) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex8, execution::blocking.possibly) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex8, execution::blocking.never) + == execution::blocking.possibly); + + executor_type ex9 = boost::asio::prefer(ex7, execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex9, execution::blocking) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex9, execution::blocking.possibly) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex9, execution::blocking.never) + == execution::blocking.never); + + executor_type ex10 = either_blocking_executor(execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex10, execution::blocking) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex10, execution::blocking.possibly) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex10, execution::blocking.never) + == execution::blocking.never); + + executor_type ex11 = boost::asio::prefer(ex7, execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex11, execution::blocking) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex11, execution::blocking.possibly) + == execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ex11, execution::blocking.never) + == execution::blocking.possibly); + + executor_type ex12 = boost::asio::prefer(ex7, execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex12, execution::blocking) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex12, execution::blocking.possibly) + == execution::blocking.never); + + BOOST_ASIO_CHECK( + boost::asio::query(ex12, execution::blocking.never) + == execution::blocking.never); +} + +void do_nothing() +{ +} + +void prefer_only_executor_execute_test() +{ + typedef execution::any_executor< + execution::blocking_t, + execution::prefer_only, + execution::prefer_only + > executor_type; + + executor_type ex1 = possibly_blocking_executor(); + + execution::execute(ex1, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 1); + BOOST_ASIO_CHECK(never_blocking_count == 0); + + executor_type ex2 = boost::asio::prefer(ex1, execution::blocking.possibly); + + execution::execute(ex2, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 2); + BOOST_ASIO_CHECK(never_blocking_count == 0); + + executor_type ex3 = boost::asio::prefer(ex1, execution::blocking.never); + + execution::execute(ex3, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 3); + BOOST_ASIO_CHECK(never_blocking_count == 0); + + executor_type ex4 = never_blocking_executor(); + + execution::execute(ex4, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 3); + BOOST_ASIO_CHECK(never_blocking_count == 1); + + executor_type ex5 = boost::asio::prefer(ex4, execution::blocking.possibly); + + execution::execute(ex5, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 3); + BOOST_ASIO_CHECK(never_blocking_count == 2); + + executor_type ex6 = boost::asio::prefer(ex4, execution::blocking.never); + + execution::execute(ex6, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 3); + BOOST_ASIO_CHECK(never_blocking_count == 3); + + executor_type ex7 = either_blocking_executor(execution::blocking.possibly); + + execution::execute(ex7, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 4); + BOOST_ASIO_CHECK(never_blocking_count == 3); + + executor_type ex8 = boost::asio::prefer(ex7, execution::blocking.possibly); + + execution::execute(ex8, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 5); + BOOST_ASIO_CHECK(never_blocking_count == 3); + + executor_type ex9 = boost::asio::prefer(ex7, execution::blocking.never); + + execution::execute(ex9, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 5); + BOOST_ASIO_CHECK(never_blocking_count == 4); + + executor_type ex10 = either_blocking_executor(execution::blocking.never); + + execution::execute(ex10, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 5); + BOOST_ASIO_CHECK(never_blocking_count == 5); + + executor_type ex11 = boost::asio::prefer(ex7, execution::blocking.possibly); + + execution::execute(ex11, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 6); + BOOST_ASIO_CHECK(never_blocking_count == 5); + + executor_type ex12 = boost::asio::prefer(ex7, execution::blocking.never); + + execution::execute(ex12, &do_nothing); + BOOST_ASIO_CHECK(possibly_blocking_count == 6); + BOOST_ASIO_CHECK(never_blocking_count == 6); +} + +BOOST_ASIO_TEST_SUITE +( + "prefer_only", + BOOST_ASIO_TEST_CASE(prefer_only_executor_query_test) + BOOST_ASIO_TEST_CASE(prefer_only_executor_execute_test) +) From ac7e13f51bbbc75eaa64cb41b99206116ec89b7f Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:03:15 +1000 Subject: [PATCH 60/90] Add execution::context_as property adapter. --- include/boost/asio.hpp | 1 + include/boost/asio/detail/type_traits.hpp | 2 + include/boost/asio/execution/context_as.hpp | 194 ++++++++++++++++++++ test/execution/Jamfile.v2 | 1 + test/execution/context_as.cpp | 157 ++++++++++++++++ 5 files changed, 355 insertions(+) create mode 100644 include/boost/asio/execution/context_as.hpp create mode 100644 test/execution/context_as.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 252b8688..e1cd248c 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/detail/type_traits.hpp b/include/boost/asio/detail/type_traits.hpp index 06550808..a6a0d0e6 100644 --- a/include/boost/asio/detail/type_traits.hpp +++ b/include/boost/asio/detail/type_traits.hpp @@ -65,6 +65,7 @@ using std::is_destructible; using std::is_function; using std::is_nothrow_copy_constructible; using std::is_nothrow_destructible; +using std::is_reference; using std::is_same; using std::is_scalar; using std::remove_pointer; @@ -99,6 +100,7 @@ template struct is_nothrow_copy_constructible : boost::has_nothrow_copy {}; template struct is_nothrow_destructible : boost::has_nothrow_destructor {}; +using boost::is_reference; using boost::is_same; using boost::is_scalar; using boost::remove_pointer; diff --git a/include/boost/asio/execution/context_as.hpp b/include/boost/asio/execution/context_as.hpp new file mode 100644 index 00000000..99fd10de --- /dev/null +++ b/include/boost/asio/execution/context_as.hpp @@ -0,0 +1,194 @@ +// +// execution/context_as.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_CONTEXT_AS_HPP +#define BOOST_ASIO_EXECUTION_CONTEXT_AS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(GENERATING_DOCUMENTATION) + +namespace execution { + +/// A property that is used to obtain the execution context that is associated +/// with an executor. +template +struct context_as_t +{ + /// The context_t property applies to executors. + template + static constexpr bool is_applicable_property_v = is_executor_v; + + /// The context_t property cannot be required. + static constexpr bool is_requirable = false; + + /// The context_t property cannot be preferred. + static constexpr bool is_preferable = false; + + /// The type returned by queries against an @c any_executor. + typedef T polymorphic_query_result_type; +}; + +/// A special value used for accessing the context_as_t property. +template +constexpr context_as_t context_as; + +} // namespace execution + +#else // defined(GENERATING_DOCUMENTATION) + +namespace execution { + +template +struct context_as_t +{ +#if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + template + BOOST_ASIO_STATIC_CONSTEXPR(bool, + is_applicable_property_v = is_executor::value); +#endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); + + typedef T polymorphic_query_result_type; + + BOOST_ASIO_CONSTEXPR context_as_t() + { + } + + BOOST_ASIO_CONSTEXPR context_as_t(context_t) + { + } + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + template + static BOOST_ASIO_CONSTEXPR + typename traits::query_static_constexpr_member::result_type + static_query() + BOOST_ASIO_NOEXCEPT_IF(( + traits::query_static_constexpr_member::is_noexcept)) + { + return traits::query_static_constexpr_member::value(); + } + + template ())> + static BOOST_ASIO_CONSTEXPR const U static_query_v + = context_as_t::static_query(); +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + + template + friend BOOST_ASIO_CONSTEXPR U query( + const Executor& ex, const context_as_t&, + typename enable_if< + is_same::value + && can_query::value + >::type* = 0) +#if defined(_MSC_VER) // Visual C++ wants the type to be qualified. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#elif !defined(__clang__) // Clang crashes if noexcept is used here. + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) +#endif // !defined(__clang__) + { + return boost::asio::query(ex, context); + } +}; + +#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +template template +const U context_as_t::static_query_v; +#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if (defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) \ + && defined(BOOST_ASIO_HAS_CONSTEXPR)) \ + || defined(GENERATING_DOCUMENTATION) +template +constexpr context_as_t context_as{}; +#endif // (defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + // && defined(BOOST_ASIO_HAS_CONSTEXPR)) + // || defined(GENERATING_DOCUMENTATION) + +} // namespace execution + +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +template +struct is_applicable_property > + : execution::is_executor +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ + || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +template +struct static_query, + typename enable_if< + static_query::is_valid + >::type> : static_query +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) + // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +template +struct query_free, + typename enable_if< + can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + + typedef U result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) + +} // namespace traits + +#endif // defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTION_CONTEXT_AS_HPP diff --git a/test/execution/Jamfile.v2 b/test/execution/Jamfile.v2 index e0b30db8..eee590b0 100644 --- a/test/execution/Jamfile.v2 +++ b/test/execution/Jamfile.v2 @@ -45,6 +45,7 @@ test-suite "asio" : [ run blocking.cpp ] [ run blocking_adaptation.cpp ] [ run bulk_guarantee.cpp ] + [ run context_as.cpp ] [ run execute.cpp ] [ run invocable_archetype.cpp ] [ run mapping.cpp ] diff --git a/test/execution/context_as.cpp b/test/execution/context_as.cpp new file mode 100644 index 00000000..480bccb3 --- /dev/null +++ b/test/execution/context_as.cpp @@ -0,0 +1,157 @@ +// +// context_as.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include + +#include +#include +#include +#include "../unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +using namespace boost::asio; + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif + +void context_as_executor_query_test() +{ + static_thread_pool pool(1); + + BOOST_ASIO_CHECK( + &boost::asio::query(pool.executor(), + execution::context_as_t()) + == &pool); + + execution::any_executor< + execution::context_as_t + > ex1 = pool.executor(); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex1, + execution::context_as_t()) + == &pool); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex1, execution::context) + == &pool); + + BOOST_ASIO_CHECK( + &boost::asio::query(pool.executor(), + execution::context_as_t()) + == &pool); + + execution::any_executor< + execution::context_as_t + > ex2 = pool.executor(); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex2, + execution::context_as_t()) + == &pool); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex2, execution::context) + == &pool); + + io_context io_ctx; + + BOOST_ASIO_CHECK( + &boost::asio::query(io_ctx.get_executor(), + execution::context_as_t()) + == &io_ctx); + + execution::any_executor< + execution::context_as_t + > ex3 = io_ctx.get_executor(); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex3, + execution::context_as_t()) + == &io_ctx); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex3, execution::context) + == &io_ctx); + + BOOST_ASIO_CHECK( + &boost::asio::query(io_ctx.get_executor(), + execution::context_as_t()) + == &io_ctx); + + execution::any_executor< + execution::context_as_t + > ex4 = io_ctx.get_executor(); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex4, + execution::context_as_t()) + == &io_ctx); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex4, execution::context) + == &io_ctx); + + BOOST_ASIO_CHECK( + &boost::asio::query(io_ctx.get_executor(), + execution::context_as_t()) + == &io_ctx); + + execution::any_executor< + execution::context_as_t + > ex5 = io_ctx.get_executor(); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex5, + execution::context_as_t()) + == &io_ctx); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex5, execution::context) + == &io_ctx); + + BOOST_ASIO_CHECK( + &boost::asio::query(io_ctx.get_executor(), + execution::context_as_t()) + == &io_ctx); + + execution::any_executor< + execution::context_as_t + > ex6 = io_ctx.get_executor(); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex6, + execution::context_as_t()) + == &io_ctx); + + BOOST_ASIO_CHECK( + &boost::asio::query(ex6, execution::context) + == &io_ctx); +} + +BOOST_ASIO_TEST_SUITE +( + "context_as", + BOOST_ASIO_TEST_CASE(context_as_executor_query_test) +) From 9a743f078e0cc81af44a6fef322e0914de953dff Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:03:59 +1000 Subject: [PATCH 61/90] Add "asio/execution.hpp" convenience header. --- include/boost/asio.hpp | 1 + include/boost/asio/execution.hpp | 35 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 include/boost/asio/execution.hpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index e1cd248c..56354c63 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/execution.hpp b/include/boost/asio/execution.hpp new file mode 100644 index 00000000..1a2985c6 --- /dev/null +++ b/include/boost/asio/execution.hpp @@ -0,0 +1,35 @@ +// +// execution.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_HPP +#define BOOST_ASIO_EXECUTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_ASIO_EXECUTION_HPP From 0a662cb309e9f490ea8be9edc40a9a9692a14e31 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:11:15 +1000 Subject: [PATCH 62/90] Add static_thread_pool (as thread_pool in standard executor form). --- include/boost/asio.hpp | 1 + .../asio/detail/blocking_executor_op.hpp | 109 +++ .../detail/conditionally_enabled_event.hpp | 8 + include/boost/asio/detail/config.hpp | 3 + include/boost/asio/detail/null_event.hpp | 6 + include/boost/asio/detail/posix_event.hpp | 12 + include/boost/asio/detail/std_event.hpp | 12 + include/boost/asio/detail/win_event.hpp | 12 + include/boost/asio/impl/thread_pool.hpp | 226 +++++- include/boost/asio/impl/thread_pool.ipp | 68 +- include/boost/asio/static_thread_pool.hpp | 33 + include/boost/asio/thread_pool.hpp | 669 ++++++++++++++++-- test/Jamfile.v2 | 6 +- test/static_thread_pool.cpp | 30 + test/thread_pool.cpp | 136 +++- 15 files changed, 1243 insertions(+), 88 deletions(-) create mode 100644 include/boost/asio/detail/blocking_executor_op.hpp create mode 100644 include/boost/asio/static_thread_pool.hpp create mode 100644 test/static_thread_pool.cpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index 56354c63..ddcc1a43 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -138,6 +138,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/detail/blocking_executor_op.hpp b/include/boost/asio/detail/blocking_executor_op.hpp new file mode 100644 index 00000000..7ca1cfff --- /dev/null +++ b/include/boost/asio/detail/blocking_executor_op.hpp @@ -0,0 +1,109 @@ +// +// detail/blocking_executor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP +#define BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class blocking_executor_op_base : public Operation +{ +public: + blocking_executor_op_base(typename Operation::func_type complete_func) + : Operation(complete_func), + is_complete_(false) + { + } + + void wait() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!is_complete_) + event_.wait(lock); + } + +protected: + struct do_complete_cleanup + { + ~do_complete_cleanup() + { + boost::asio::detail::mutex::scoped_lock lock(op_->mutex_); + op_->is_complete_ = true; + op_->event_.unlock_and_signal_one_for_destruction(lock); + } + + blocking_executor_op_base* op_; + }; + +private: + boost::asio::detail::mutex mutex_; + boost::asio::detail::event event_; + bool is_complete_; +}; + +template +class blocking_executor_op : public blocking_executor_op_base +{ +public: + blocking_executor_op(Handler& h) + : blocking_executor_op_base(&blocking_executor_op::do_complete), + handler_(h) + { + } + + static void do_complete(void* owner, Operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + blocking_executor_op* o(static_cast(base)); + + typename blocking_executor_op_base::do_complete_cleanup + on_exit = { o }; + (void)on_exit; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN(()); + boost_asio_handler_invoke_helpers::invoke(o->handler_, o->handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler& handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP diff --git a/include/boost/asio/detail/conditionally_enabled_event.hpp b/include/boost/asio/detail/conditionally_enabled_event.hpp index 18100546..4fb3071e 100644 --- a/include/boost/asio/detail/conditionally_enabled_event.hpp +++ b/include/boost/asio/detail/conditionally_enabled_event.hpp @@ -65,6 +65,14 @@ public: event_.unlock_and_signal_one(lock); } + // Unlock the mutex and signal one waiter who may destroy us. + void unlock_and_signal_one_for_destruction( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.unlock_and_signal_one(lock); + } + // If there's a waiter, unlock the mutex and signal it. bool maybe_unlock_and_signal_one( conditionally_enabled_mutex::scoped_lock& lock) diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp index 48578a87..b56c7d6e 100644 --- a/include/boost/asio/detail/config.hpp +++ b/include/boost/asio/detail/config.hpp @@ -61,6 +61,9 @@ # define BOOST_ASIO_DECL #endif // !defined(BOOST_ASIO_DECL) +// Helper macro for documentation. +#define BOOST_ASIO_UNSPECIFIED(e) e + // Microsoft Visual C++ detection. #if !defined(BOOST_ASIO_MSVC) # if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) diff --git a/include/boost/asio/detail/null_event.hpp b/include/boost/asio/detail/null_event.hpp index bb11cb00..fa52981a 100644 --- a/include/boost/asio/detail/null_event.hpp +++ b/include/boost/asio/detail/null_event.hpp @@ -56,6 +56,12 @@ public: { } + // Unlock the mutex and signal one waiter who may destroy us. + template + void unlock_and_signal_one_for_destruction(Lock&) + { + } + // If there's a waiter, unlock the mutex and signal it. template bool maybe_unlock_and_signal_one(Lock&) diff --git a/include/boost/asio/detail/posix_event.hpp b/include/boost/asio/detail/posix_event.hpp index e2052300..b5a34860 100644 --- a/include/boost/asio/detail/posix_event.hpp +++ b/include/boost/asio/detail/posix_event.hpp @@ -71,6 +71,18 @@ public: ::pthread_cond_signal(&cond_); // Ignore EINVAL. } + // Unlock the mutex and signal one waiter who may destroy us. + template + void unlock_and_signal_one_for_destruction(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + if (have_waiters) + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + lock.unlock(); + } + // If there's a waiter, unlock the mutex and signal it. template bool maybe_unlock_and_signal_one(Lock& lock) diff --git a/include/boost/asio/detail/std_event.hpp b/include/boost/asio/detail/std_event.hpp index 914f9d93..32ad0441 100644 --- a/include/boost/asio/detail/std_event.hpp +++ b/include/boost/asio/detail/std_event.hpp @@ -74,6 +74,18 @@ public: cond_.notify_one(); } + // Unlock the mutex and signal one waiter who may destroy us. + template + void unlock_and_signal_one(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + if (have_waiters) + cond_.notify_one(); + lock.unlock(); + } + // If there's a waiter, unlock the mutex and signal it. template bool maybe_unlock_and_signal_one(Lock& lock) diff --git a/include/boost/asio/detail/win_event.hpp b/include/boost/asio/detail/win_event.hpp index 6d456713..617593e9 100644 --- a/include/boost/asio/detail/win_event.hpp +++ b/include/boost/asio/detail/win_event.hpp @@ -68,6 +68,18 @@ public: ::SetEvent(events_[1]); } + // Unlock the mutex and signal one waiter who may destroy us. + template + void unlock_and_signal_one_for_destruction(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + if (have_waiters) + ::SetEvent(events_[1]); + lock.unlock(); + } + // If there's a waiter, unlock the mutex and signal it. template bool maybe_unlock_and_signal_one(Lock& lock) diff --git a/include/boost/asio/impl/thread_pool.hpp b/include/boost/asio/impl/thread_pool.hpp index 50484ea5..60788400 100644 --- a/include/boost/asio/impl/thread_pool.hpp +++ b/include/boost/asio/impl/thread_pool.hpp @@ -15,8 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include #include #include +#include #include #include #include @@ -32,32 +34,185 @@ thread_pool::get_executor() BOOST_ASIO_NOEXCEPT return executor_type(*this); } -inline thread_pool& -thread_pool::executor_type::context() const BOOST_ASIO_NOEXCEPT +inline thread_pool::executor_type +thread_pool::executor() BOOST_ASIO_NOEXCEPT { - return pool_; + return executor_type(*this); } -inline void -thread_pool::executor_type::on_work_started() const BOOST_ASIO_NOEXCEPT +template +thread_pool::basic_executor_type& +thread_pool::basic_executor_type::operator=( + const basic_executor_type& other) BOOST_ASIO_NOEXCEPT { - pool_.scheduler_.work_started(); + if (this != &other) + { + thread_pool* old_thread_pool = pool_; + pool_ = other.pool_; + allocator_ = other.allocator_; + bits_ = other.bits_; + if (Bits & outstanding_work_tracked) + { + if (pool_) + pool_->scheduler_.work_started(); + if (old_thread_pool) + old_thread_pool->scheduler_.work_finished(); + } + } + return *this; } -inline void thread_pool::executor_type::on_work_finished() -const BOOST_ASIO_NOEXCEPT +#if defined(BOOST_ASIO_HAS_MOVE) +template +thread_pool::basic_executor_type& +thread_pool::basic_executor_type::operator=( + basic_executor_type&& other) BOOST_ASIO_NOEXCEPT { - pool_.scheduler_.work_finished(); + if (this != &other) + { + pool_ = other.pool_; + allocator_ = std::move(other.allocator_); + bits_ = other.bits_; + if (Bits & outstanding_work_tracked) + other.pool_ = 0; + } + return *this; +} +#endif // defined(BOOST_ASIO_HAS_MOVE) + +template +inline bool thread_pool::basic_executor_type::running_in_this_thread() const BOOST_ASIO_NOEXCEPT +{ + return pool_->scheduler_.can_dispatch(); } -template -void thread_pool::executor_type::dispatch( - BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template +template +void thread_pool::basic_executor_type::do_execute(BOOST_ASIO_MOVE_ARG(Function) f, false_type) const +{ + typedef typename decay::type function_type; + + // Invoke immediately if the blocking.possibly property is enabled and we are + // already inside the thread pool. + if ((bits_ & blocking_never) == 0 && pool_->scheduler_.can_dispatch()) + { + // Make a local, non-const copy of the function. + function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(BOOST_ASIO_NO_EXCEPTIONS) + try + { +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(BOOST_ASIO_NO_EXCEPTIONS) + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); + return; +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + catch (...) + { + pool_->scheduler_.capture_current_exception(); + return; + } +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(allocator_), + op::ptr::allocate(allocator_), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); + + if ((bits_ & relationship_continuation) != 0) + { + BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p, + "thread_pool", pool_, 0, "execute(blk=never,rel=cont)")); + } + else + { + BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p, + "thread_pool", pool_, 0, "execute(blk=never,rel=fork)")); + } + + pool_->scheduler_.post_immediate_completion(p.p, + (bits_ & relationship_continuation) != 0); + p.v = p.p = 0; +} + +template +template +void thread_pool::basic_executor_type::do_execute(BOOST_ASIO_MOVE_ARG(Function) f, true_type) const +{ + // Obtain a non-const instance of the function. + detail::non_const_lvalue f2(f); + + // Invoke immediately if we are already inside the thread pool. + if (pool_->scheduler_.can_dispatch()) + { +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try + { +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(f2.value, f2.value); + return; +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + catch (...) + { + std::terminate(); + } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + + // Construct an operation to wrap the function. + typedef typename decay::type function_type; + detail::blocking_executor_op op(f2.value); + + BOOST_ASIO_HANDLER_CREATION((*pool_, op, + "thread_pool", pool_, 0, "execute(blk=always)")); + + pool_->scheduler_.post_immediate_completion(&op, false); + op.wait(); +} + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) +template +inline thread_pool& thread_pool::basic_executor_type< + Allocator, Bits>::context() const BOOST_ASIO_NOEXCEPT +{ + return *pool_; +} + +template +inline void thread_pool::basic_executor_type::on_work_started() const BOOST_ASIO_NOEXCEPT +{ + pool_->scheduler_.work_started(); +} + +template +inline void thread_pool::basic_executor_type::on_work_finished() const BOOST_ASIO_NOEXCEPT +{ + pool_->scheduler_.work_finished(); +} + +template +template +void thread_pool::basic_executor_type::dispatch( + BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay::type function_type; // Invoke immediately if we are already inside the thread pool. - if (pool_.scheduler_.can_dispatch()) + if (pool_->scheduler_.can_dispatch()) { // Make a local, non-const copy of the function. function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); @@ -68,58 +223,55 @@ void thread_pool::executor_type::dispatch( } // Allocate and construct an operation to wrap the function. - typedef detail::executor_op op; + typedef detail::executor_op op; typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); - BOOST_ASIO_HANDLER_CREATION((pool_, *p.p, - "thread_pool", &this->context(), 0, "dispatch")); + BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p, + "thread_pool", pool_, 0, "dispatch")); - pool_.scheduler_.post_immediate_completion(p.p, false); + pool_->scheduler_.post_immediate_completion(p.p, false); p.v = p.p = 0; } -template -void thread_pool::executor_type::post( - BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template +template +void thread_pool::basic_executor_type::post( + BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay::type function_type; // Allocate and construct an operation to wrap the function. - typedef detail::executor_op op; + typedef detail::executor_op op; typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); - BOOST_ASIO_HANDLER_CREATION((pool_, *p.p, - "thread_pool", &this->context(), 0, "post")); + BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p, + "thread_pool", pool_, 0, "post")); - pool_.scheduler_.post_immediate_completion(p.p, false); + pool_->scheduler_.post_immediate_completion(p.p, false); p.v = p.p = 0; } -template -void thread_pool::executor_type::defer( - BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template +template +void thread_pool::basic_executor_type::defer( + BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay::type function_type; // Allocate and construct an operation to wrap the function. - typedef detail::executor_op op; + typedef detail::executor_op op; typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); - BOOST_ASIO_HANDLER_CREATION((pool_, *p.p, - "thread_pool", &this->context(), 0, "defer")); + BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p, + "thread_pool", pool_, 0, "defer")); - pool_.scheduler_.post_immediate_completion(p.p, true); + pool_->scheduler_.post_immediate_completion(p.p, true); p.v = p.p = 0; } - -inline bool -thread_pool::executor_type::running_in_this_thread() const BOOST_ASIO_NOEXCEPT -{ - return pool_.scheduler_.can_dispatch(); -} +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) } // namespace asio } // namespace boost diff --git a/include/boost/asio/impl/thread_pool.ipp b/include/boost/asio/impl/thread_pool.ipp index cf03f8d2..95dc5707 100644 --- a/include/boost/asio/impl/thread_pool.ipp +++ b/include/boost/asio/impl/thread_pool.ipp @@ -16,7 +16,9 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include +#include #include +#include #include @@ -29,29 +31,68 @@ struct thread_pool::thread_function void operator()() { - boost::system::error_code ec; - scheduler_->run(ec); +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try + { +#endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) + boost::system::error_code ec; + scheduler_->run(ec); +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + catch (...) + { + std::terminate(); + } +#endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) } }; +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) +namespace detail { + +inline long default_thread_pool_size() +{ + std::size_t num_threads = thread::hardware_concurrency() * 2; + num_threads = num_threads == 0 ? 2 : num_threads; + return static_cast(num_threads); +} + +} // namespace detail + thread_pool::thread_pool() - : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))) + : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))), + num_threads_(detail::default_thread_pool_size()) { scheduler_.work_started(); thread_function f = { &scheduler_ }; - std::size_t num_threads = detail::thread::hardware_concurrency() * 2; - threads_.create_threads(f, num_threads ? num_threads : 2); + threads_.create_threads(f, static_cast(num_threads_)); } +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) + +namespace detail { + +inline long clamp_thread_pool_size(std::size_t n) +{ + if (n > 0x7FFFFFFF) + { + std::out_of_range ex("thread pool size"); + boost::asio::detail::throw_exception(ex); + } + return static_cast(n & 0x7FFFFFFF); +} + +} // namespace detail thread_pool::thread_pool(std::size_t num_threads) : scheduler_(add_scheduler(new detail::scheduler( - *this, num_threads == 1 ? 1 : 0, false))) + *this, num_threads == 1 ? 1 : 0, false))), + num_threads_(detail::clamp_thread_pool_size(num_threads)) { scheduler_.work_started(); thread_function f = { &scheduler_ }; - threads_.create_threads(f, num_threads); + threads_.create_threads(f, static_cast(num_threads_)); } thread_pool::~thread_pool() @@ -65,6 +106,13 @@ void thread_pool::stop() scheduler_.stop(); } +void thread_pool::attach() +{ + ++num_threads_; + thread_function f = { &scheduler_ }; + f(); +} + void thread_pool::join() { if (!threads_.empty()) @@ -81,6 +129,12 @@ detail::scheduler& thread_pool::add_scheduler(detail::scheduler* s) return *scoped_impl.release(); } +void thread_pool::wait() +{ + scheduler_.work_finished(); + threads_.join(); +} + } // namespace asio } // namespace boost diff --git a/include/boost/asio/static_thread_pool.hpp b/include/boost/asio/static_thread_pool.hpp new file mode 100644 index 00000000..3ca477a0 --- /dev/null +++ b/include/boost/asio/static_thread_pool.hpp @@ -0,0 +1,33 @@ +// +// static_thread_pool.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_STATIC_THREAD_POOL_HPP +#define BOOST_ASIO_STATIC_THREAD_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +typedef thread_pool static_thread_pool; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_STATIC_THREAD_POOL_HPP diff --git a/include/boost/asio/thread_pool.hpp b/include/boost/asio/thread_pool.hpp index 2cd50251..41e4b7e1 100644 --- a/include/boost/asio/thread_pool.hpp +++ b/include/boost/asio/thread_pool.hpp @@ -16,14 +16,26 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include +#include #include #include +#include #include #include namespace boost { namespace asio { +namespace detail { + struct thread_pool_bits + { + BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1); + BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_always = 2); + BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_mask = 3); + BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 4); + BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 8); + }; +} // namespace detail /// A simple fixed-size thread pool. /** @@ -32,7 +44,7 @@ namespace asio { * * @par Submitting tasks to the pool * - * To submit functions to the thread_pool, use the @ref boost::asio::dispatch, + * To submit functions to the thread pool, use the @ref boost::asio::dispatch, * @ref boost::asio::post or @ref boost::asio::defer free functions. * * For example: @@ -64,10 +76,18 @@ class thread_pool : public execution_context { public: - class executor_type; + template + class basic_executor_type; + template + friend class basic_executor_type; + + typedef basic_executor_type, 0> executor_type; + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Constructs a pool with an automatically determined number of threads. BOOST_ASIO_DECL thread_pool(); +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Constructs a pool with a specified number of threads. BOOST_ASIO_DECL thread_pool(std::size_t num_threads); @@ -81,6 +101,9 @@ public: /// Obtains the executor associated with the pool. executor_type get_executor() BOOST_ASIO_NOEXCEPT; + /// Obtains the executor associated with the pool. + executor_type executor() BOOST_ASIO_NOEXCEPT; + /// Stops the threads. /** * This function stops the threads as soon as possible. As a result of calling @@ -88,6 +111,14 @@ public: */ BOOST_ASIO_DECL void stop(); + /// Attaches the current thread to the pool. + /** + * This function attaches the current thread to the pool so that it may be + * used for executing submitted function objects. Blocks the calling thread + * until the pool is stopped or joined and has no outstanding work. + */ + BOOST_ASIO_DECL void attach(); + /// Joins the threads. /** * This function blocks until the threads in the pool have completed. If @c @@ -96,11 +127,18 @@ public: */ BOOST_ASIO_DECL void join(); + /// Waits for threads to complete. + /** + * This function blocks until the threads in the pool have completed. If @c + * stop() is not called prior to @c wait(), the @c wait() call will wait + * until the pool has no more outstanding work. + */ + BOOST_ASIO_DECL void wait(); + private: thread_pool(const thread_pool&) BOOST_ASIO_DELETED; thread_pool& operator=(const thread_pool&) BOOST_ASIO_DELETED; - friend class executor_type; struct thread_function; // Helper function to create the underlying scheduler. @@ -111,12 +149,246 @@ private: // The threads in the pool. detail::thread_group threads_; + + // The current number of threads in the pool. + detail::atomic_count num_threads_; }; -/// Executor used to submit functions to a thread pool. -class thread_pool::executor_type +template +class thread_pool::basic_executor_type : detail::thread_pool_bits { public: + /// Copy construtor. + basic_executor_type( + const basic_executor_type& other) BOOST_ASIO_NOEXCEPT + : pool_(other.pool_), + allocator_(other.allocator_), + bits_(other.bits_) + { + if (Bits & outstanding_work_tracked) + if (pool_) + pool_->scheduler_.work_started(); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construtor. + basic_executor_type(basic_executor_type&& other) BOOST_ASIO_NOEXCEPT + : pool_(other.pool_), + allocator_(BOOST_ASIO_MOVE_CAST(Allocator)(other.allocator_)), + bits_(other.bits_) + { + if (Bits & outstanding_work_tracked) + other.pool_ = 0; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + ~basic_executor_type() + { + if (Bits & outstanding_work_tracked) + if (pool_) + pool_->scheduler_.work_finished(); + } + + /// Assignment operator. + basic_executor_type& operator=( + const basic_executor_type& other) BOOST_ASIO_NOEXCEPT; + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move assignment operator. + basic_executor_type& operator=( + basic_executor_type&& other) BOOST_ASIO_NOEXCEPT; +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Obtain an executor with the @c blocking.possibly property. + BOOST_ASIO_CONSTEXPR basic_executor_type + require(execution::blocking_t::possibly_t) const + { + return basic_executor_type( + pool_, allocator_, bits_ & ~blocking_mask); + } + + /// Obtain an executor with the @c blocking.always property. + BOOST_ASIO_CONSTEXPR basic_executor_type + require(execution::blocking_t::always_t) const + { + return basic_executor_type( + pool_, allocator_, bits_ & ~blocking_mask); + } + + /// Obtain an executor with the @c blocking.never property. + BOOST_ASIO_CONSTEXPR basic_executor_type + require(execution::blocking_t::never_t) const + { + return basic_executor_type( + pool_, allocator_, (bits_ & ~blocking_mask) | blocking_never); + } + + /// Obtain an executor with the @c relationship.fork property. + BOOST_ASIO_CONSTEXPR basic_executor_type require( + execution::relationship_t::fork_t) const + { + return basic_executor_type(pool_, + allocator_, bits_ & ~relationship_continuation); + } + + /// Obtain an executor with the @c relationship.continuation property. + BOOST_ASIO_CONSTEXPR basic_executor_type require( + execution::relationship_t::continuation_t) const + { + return basic_executor_type(pool_, + allocator_, bits_ | relationship_continuation); + } + + /// Obtain an executor with the @c outstanding_work.tracked property. + BOOST_ASIO_CONSTEXPR basic_executor_type + require(execution::outstanding_work_t::tracked_t) const + { + return basic_executor_type( + pool_, allocator_, bits_); + } + + /// Obtain an executor with the @c outstanding_work.untracked property. + BOOST_ASIO_CONSTEXPR basic_executor_type + require(execution::outstanding_work_t::untracked_t) const + { + return basic_executor_type( + pool_, allocator_, bits_); + } + + /// Obtain an executor with the specified @c allocator property. + template + BOOST_ASIO_CONSTEXPR basic_executor_type + require(execution::allocator_t a) const + { + return basic_executor_type( + pool_, a.value(), bits_); + } + + /// Obtain an executor with the default @c allocator property. + BOOST_ASIO_CONSTEXPR basic_executor_type, Bits> + require(execution::allocator_t) const + { + return basic_executor_type, Bits>( + pool_, std::allocator(), bits_); + } + + /// Query the current value of the @c bulk_guarantee property. + static BOOST_ASIO_CONSTEXPR execution::bulk_guarantee_t query( + execution::bulk_guarantee_t) BOOST_ASIO_NOEXCEPT + { + return execution::bulk_guarantee.parallel; + } + + /// Query the current value of the @c mapping property. + static BOOST_ASIO_CONSTEXPR execution::mapping_t query( + execution::mapping_t) BOOST_ASIO_NOEXCEPT + { + return execution::mapping.thread; + } + + /// Query the current value of the @c context property. + thread_pool& query(execution::context_t) const BOOST_ASIO_NOEXCEPT + { + return *pool_; + } + + /// Query the current value of the @c blocking property. + BOOST_ASIO_CONSTEXPR execution::blocking_t query( + execution::blocking_t) const BOOST_ASIO_NOEXCEPT + { + return (bits_ & blocking_never) + ? execution::blocking_t(execution::blocking.never) + : ((Bits & blocking_always) + ? execution::blocking_t(execution::blocking.always) + : execution::blocking_t(execution::blocking.possibly)); + } + + /// Query the current value of the @c relationship property. + BOOST_ASIO_CONSTEXPR execution::relationship_t query( + execution::relationship_t) const BOOST_ASIO_NOEXCEPT + { + return (bits_ & relationship_continuation) + ? execution::relationship_t(execution::relationship.continuation) + : execution::relationship_t(execution::relationship.fork); + } + + /// Query the current value of the @c outstanding_work property. + static BOOST_ASIO_CONSTEXPR execution::outstanding_work_t query( + execution::outstanding_work_t) BOOST_ASIO_NOEXCEPT + { + return (Bits & outstanding_work_tracked) + ? execution::outstanding_work_t(execution::outstanding_work.tracked) + : execution::outstanding_work_t(execution::outstanding_work.untracked); + } + + /// Query the current value of the @c allocator property. + template + BOOST_ASIO_CONSTEXPR Allocator query( + execution::allocator_t) const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } + + /// Query the current value of the @c allocator property. + BOOST_ASIO_CONSTEXPR Allocator query( + execution::allocator_t) const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } + + /// Query the occupancy (recommended number of work items) for the pool. + std::size_t query(execution::occupancy_t) const BOOST_ASIO_NOEXCEPT + { + return static_cast(pool_->num_threads_); + } + + /// Determine whether the thread pool is running in the current thread. + /** + * @return @c true if the current thread is running the thread pool. Otherwise + * returns @c false. + */ + bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT; + + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying thread pool. + */ + friend bool operator==(const basic_executor_type& a, + const basic_executor_type& b) BOOST_ASIO_NOEXCEPT + { + return a.pool_ == b.pool_ + && a.allocator_ == b.allocator_ + && a.bits_ == b.bits_; + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying thread pool. + */ + friend bool operator!=(const basic_executor_type& a, + const basic_executor_type& b) BOOST_ASIO_NOEXCEPT + { + return a.pool_ != b.pool_ + || a.allocator_ != b.allocator_ + || a.bits_ != b.bits_; + } + + /// Execution function. + template + void execute(BOOST_ASIO_MOVE_ARG(Function) f) const + { + this->do_execute(BOOST_ASIO_MOVE_CAST(Function)(f), + integral_constant()); + } + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Obtain the underlying execution context. thread_pool& context() const BOOST_ASIO_NOEXCEPT; @@ -150,8 +422,9 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template - void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, + const OtherAllocator& a) const; /// Request the thread pool to invoke the given function object. /** @@ -166,8 +439,9 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template - void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template + void post(BOOST_ASIO_MOVE_ARG(Function) f, + const OtherAllocator& a) const; /// Request the thread pool to invoke the given function object. /** @@ -186,46 +460,359 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template - void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; - - /// Determine whether the thread pool is running in the current thread. - /** - * @return @c true if the current thread belongs to the pool. Otherwise - * returns @c false. - */ - bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT; - - /// Compare two executors for equality. - /** - * Two executors are equal if they refer to the same underlying thread pool. - */ - friend bool operator==(const executor_type& a, - const executor_type& b) BOOST_ASIO_NOEXCEPT - { - return &a.pool_ == &b.pool_; - } - - /// Compare two executors for inequality. - /** - * Two executors are equal if they refer to the same underlying thread pool. - */ - friend bool operator!=(const executor_type& a, - const executor_type& b) BOOST_ASIO_NOEXCEPT - { - return &a.pool_ != &b.pool_; - } + template + void defer(BOOST_ASIO_MOVE_ARG(Function) f, + const OtherAllocator& a) const; +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) private: friend class thread_pool; + template friend class basic_executor_type; - // Constructor. - explicit executor_type(thread_pool& p) : pool_(p) {} + // Constructor used by thread_pool::get_executor(). + explicit basic_executor_type(thread_pool& p) BOOST_ASIO_NOEXCEPT + : pool_(&p), + allocator_(), + bits_(0) + { + if (Bits & outstanding_work_tracked) + pool_->scheduler_.work_started(); + } + + // Constructor used by require(). + basic_executor_type(thread_pool* p, + const Allocator& a, unsigned int bits) BOOST_ASIO_NOEXCEPT + : pool_(p), + allocator_(a), + bits_(bits) + { + if (Bits & outstanding_work_tracked) + if (pool_) + pool_->scheduler_.work_started(); + } + + /// Execution helper implementation for possibly and never blocking. + template + void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, false_type) const; + + /// Execution helper implementation for always blocking. + template + void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, true_type) const; // The underlying thread pool. - thread_pool& pool_; + thread_pool* pool_; + + // The allocator used for execution functions. + Allocator allocator_; + + // The runtime-switched properties of the io_context executor. + unsigned int bits_; }; +#if !defined(GENERATING_DOCUMENTATION) + +namespace execution { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct is_executor< + boost::asio::thread_pool::basic_executor_type + > : true_type +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +} // namespace execution +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member< + boost::asio::thread_pool::basic_executor_type, + Function + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::blocking_t::possibly_t + > : boost::asio::detail::thread_pool_bits +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::thread_pool::basic_executor_type< + Allocator, Bits & ~blocking_mask> result_type; +}; + +template +struct require_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::blocking_t::always_t + > : boost::asio::detail::thread_pool_bits +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::thread_pool::basic_executor_type result_type; +}; + +template +struct require_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::blocking_t::never_t + > : boost::asio::detail::thread_pool_bits +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::thread_pool::basic_executor_type< + Allocator, Bits & ~blocking_mask> result_type; +}; + +template +struct require_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::relationship_t::fork_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::thread_pool::basic_executor_type< + Allocator, Bits> result_type; +}; + +template +struct require_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::relationship_t::continuation_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::thread_pool::basic_executor_type< + Allocator, Bits> result_type; +}; + +template +struct require_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::outstanding_work_t::tracked_t + > : boost::asio::detail::thread_pool_bits +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::thread_pool::basic_executor_type< + Allocator, Bits | outstanding_work_tracked> result_type; +}; + +template +struct require_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::outstanding_work_t::untracked_t + > : boost::asio::detail::thread_pool_bits +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::thread_pool::basic_executor_type< + Allocator, Bits & ~outstanding_work_tracked> result_type; +}; + +template +struct require_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::thread_pool::basic_executor_type< + std::allocator, Bits> result_type; +}; + +template +struct require_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::thread_pool::basic_executor_type< + OtherAllocator, Bits> result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + boost::asio::thread_pool::basic_executor_type, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::bulk_guarantee_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::bulk_guarantee_t::parallel_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT + { + return result_type(); + } +}; + +template +struct query_static_constexpr_member< + boost::asio::thread_pool::basic_executor_type, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::outstanding_work_t + >::value + >::type + > : boost::asio::detail::thread_pool_bits +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::outstanding_work_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT + { + return (Bits & outstanding_work_tracked) + ? execution::outstanding_work_t(execution::outstanding_work.tracked) + : execution::outstanding_work_t(execution::outstanding_work.untracked); + } +}; + +template +struct query_static_constexpr_member< + boost::asio::thread_pool::basic_executor_type, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::mapping_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::mapping_t::thread_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT + { + return result_type(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + boost::asio::thread_pool::basic_executor_type, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::blocking_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::blocking_t result_type; +}; + +template +struct query_member< + boost::asio::thread_pool::basic_executor_type, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::relationship_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::relationship_t result_type; +}; + +template +struct query_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::occupancy_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef std::size_t result_type; +}; + +template +struct query_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::context_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::thread_pool& result_type; +}; + +template +struct query_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef Allocator result_type; +}; + +template +struct query_member< + boost::asio::thread_pool::basic_executor_type, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef Allocator result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + } // namespace asio } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b68717e2..fd02ed27 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -176,6 +176,8 @@ test-suite "asio" : [ run signal_set.cpp : : : $(USE_SELECT) : signal_set_select ] [ run socket_base.cpp ] [ run socket_base.cpp : : : $(USE_SELECT) : socket_base_select ] + [ run static_thread_pool.cpp ] + [ run static_thread_pool.cpp : : : $(USE_SELECT) : static_thread_pool_select ] [ link steady_timer.cpp ] [ link steady_timer.cpp : $(USE_SELECT) : steady_timer_select ] [ run strand.cpp ] @@ -190,8 +192,8 @@ test-suite "asio" : [ link system_executor.cpp : $(USE_SELECT) : system_executor_select ] [ link this_coro.cpp ] [ link this_coro.cpp : $(USE_SELECT) : this_coro_select ] - [ link thread_pool.cpp ] - [ link thread_pool.cpp : $(USE_SELECT) : thread_pool_select ] + [ run thread_pool.cpp ] + [ run thread_pool.cpp : : : $(USE_SELECT) : thread_pool_select ] [ link time_traits.cpp ] [ link time_traits.cpp : $(USE_SELECT) : time_traits_select ] [ link ts/buffer.cpp : : ts_buffer ] diff --git a/test/static_thread_pool.cpp b/test/static_thread_pool.cpp new file mode 100644 index 00000000..145e5ba4 --- /dev/null +++ b/test/static_thread_pool.cpp @@ -0,0 +1,30 @@ +// +// static_thread_pool.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "static_thread_pool", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/test/thread_pool.cpp b/test/thread_pool.cpp index 7bf036f0..8cc50907 100644 --- a/test/thread_pool.cpp +++ b/test/thread_pool.cpp @@ -80,7 +80,7 @@ void thread_pool_test() int count3 = 10; boost::asio::post(pool, bindns::bind(nested_decrement_to_zero, &pool, &count3)); - pool.join(); + pool.wait(); BOOST_ASIO_CHECK(count1 == 1); BOOST_ASIO_CHECK(count2 == 0); @@ -158,9 +158,143 @@ void thread_pool_service_test() BOOST_ASIO_CHECK(!boost::asio::has_service(pool3)); } +void thread_pool_executor_query_test() +{ + thread_pool pool(1); + + BOOST_ASIO_CHECK( + &boost::asio::query(pool.executor(), + boost::asio::execution::context) + == &pool); + + BOOST_ASIO_CHECK( + boost::asio::query(pool.executor(), + boost::asio::execution::blocking) + == boost::asio::execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(pool.executor(), + boost::asio::execution::blocking.possibly) + == boost::asio::execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(pool.executor(), + boost::asio::execution::outstanding_work) + == boost::asio::execution::outstanding_work.untracked); + + BOOST_ASIO_CHECK( + boost::asio::query(pool.executor(), + boost::asio::execution::outstanding_work.untracked) + == boost::asio::execution::outstanding_work.untracked); + + BOOST_ASIO_CHECK( + boost::asio::query(pool.executor(), + boost::asio::execution::relationship) + == boost::asio::execution::relationship.fork); + + BOOST_ASIO_CHECK( + boost::asio::query(pool.executor(), + boost::asio::execution::relationship.fork) + == boost::asio::execution::relationship.fork); + + BOOST_ASIO_CHECK( + boost::asio::query(pool.executor(), + boost::asio::execution::bulk_guarantee) + == boost::asio::execution::bulk_guarantee.parallel); + + BOOST_ASIO_CHECK( + boost::asio::query(pool.executor(), + boost::asio::execution::mapping) + == boost::asio::execution::mapping.thread); + + BOOST_ASIO_CHECK( + boost::asio::query(pool.executor(), + boost::asio::execution::allocator) + == std::allocator()); + + BOOST_ASIO_CHECK( + boost::asio::query(pool.executor(), + boost::asio::execution::occupancy) + == 1); +} + +void thread_pool_executor_execute_test() +{ + int count = 0; + thread_pool pool(1); + + boost::asio::execution::execute(pool.executor(), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.possibly), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.always), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.tracked), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.fork), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::prefer( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + boost::asio::execution::allocator(std::allocator())), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::prefer( + boost::asio::require(pool.executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + boost::asio::execution::allocator), + bindns::bind(increment, &count)); + + pool.wait(); + + BOOST_ASIO_CHECK(count == 10); +} + BOOST_ASIO_TEST_SUITE ( "thread_pool", BOOST_ASIO_TEST_CASE(thread_pool_test) BOOST_ASIO_TEST_CASE(thread_pool_service_test) + BOOST_ASIO_TEST_CASE(thread_pool_executor_query_test) + BOOST_ASIO_TEST_CASE(thread_pool_executor_execute_test) ) From 65dfb992736a0d5eb8d356aac9b41df646cdbd69 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Tue, 23 Jun 2020 11:08:03 +1000 Subject: [PATCH 63/90] threadpool --- include/boost/asio/thread_pool.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/asio/thread_pool.hpp b/include/boost/asio/thread_pool.hpp index 41e4b7e1..e7c23214 100644 --- a/include/boost/asio/thread_pool.hpp +++ b/include/boost/asio/thread_pool.hpp @@ -82,6 +82,7 @@ public: template friend class basic_executor_type; + /// Executor used to submit functions to a thread pool. typedef basic_executor_type, 0> executor_type; #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) @@ -154,6 +155,7 @@ private: detail::atomic_count num_threads_; }; +/// Executor implementation type used to submit functions to a thread pool. template class thread_pool::basic_executor_type : detail::thread_pool_bits { @@ -505,7 +507,7 @@ private: // The allocator used for execution functions. Allocator allocator_; - // The runtime-switched properties of the io_context executor. + // The runtime-switched properties of the thread pool executor. unsigned int bits_; }; From 121e8aa6100ba6a76ac957fb8380ea8215fb9af8 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:14:19 +1000 Subject: [PATCH 64/90] Update io_context::executor_type to standard executor form. --- include/boost/asio.hpp | 1 + include/boost/asio/detail/config.hpp | 24 + include/boost/asio/detail/impl/scheduler.ipp | 9 + .../asio/detail/impl/win_iocp_io_context.ipp | 20 +- include/boost/asio/detail/scheduler.hpp | 3 + .../boost/asio/detail/thread_info_base.hpp | 58 ++ .../boost/asio/detail/win_iocp_io_context.hpp | 6 +- include/boost/asio/impl/io_context.hpp | 175 ++++-- .../boost/asio/impl/multiple_exceptions.ipp | 51 ++ include/boost/asio/impl/src.hpp | 1 + include/boost/asio/io_context.hpp | 560 ++++++++++++++++-- include/boost/asio/multiple_exceptions.hpp | 60 ++ test/io_context.cpp | 223 +++++++ 13 files changed, 1107 insertions(+), 84 deletions(-) create mode 100644 include/boost/asio/impl/multiple_exceptions.ipp create mode 100644 include/boost/asio/multiple_exceptions.hpp diff --git a/include/boost/asio.hpp b/include/boost/asio.hpp index ddcc1a43..8e460363 100644 --- a/include/boost/asio.hpp +++ b/include/boost/asio.hpp @@ -118,6 +118,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp index b56c7d6e..66c78bd8 100644 --- a/include/boost/asio/detail/config.hpp +++ b/include/boost/asio/detail/config.hpp @@ -1092,6 +1092,30 @@ # endif // !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) #endif // !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) +// Standard library support for std::exception_ptr and std::current_exception. +#if !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) +# if !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR) +#endif // !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // Standard library support for std::source_location. #if !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) # if !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) diff --git a/include/boost/asio/detail/impl/scheduler.ipp b/include/boost/asio/detail/impl/scheduler.ipp index 4d1d09f5..effe3e23 100644 --- a/include/boost/asio/detail/impl/scheduler.ipp +++ b/include/boost/asio/detail/impl/scheduler.ipp @@ -325,6 +325,12 @@ void scheduler::compensating_work_started() ++static_cast(this_thread)->private_outstanding_work; } +void scheduler::capture_current_exception() +{ + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + this_thread->capture_current_exception(); +} + void scheduler::post_immediate_completion( scheduler::operation* op, bool is_continuation) { @@ -449,6 +455,7 @@ std::size_t scheduler::do_run_one(mutex::scoped_lock& lock, // Complete the operation. May throw an exception. Deletes the object. o->complete(this, ec, task_result); + this_thread.rethrow_pending_exception(); return 1; } @@ -529,6 +536,7 @@ std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock, // Complete the operation. May throw an exception. Deletes the object. o->complete(this, ec, task_result); + this_thread.rethrow_pending_exception(); return 1; } @@ -583,6 +591,7 @@ std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock, // Complete the operation. May throw an exception. Deletes the object. o->complete(this, ec, task_result); + this_thread.rethrow_pending_exception(); return 1; } diff --git a/include/boost/asio/detail/impl/win_iocp_io_context.ipp b/include/boost/asio/detail/impl/win_iocp_io_context.ipp index ff7e23cf..bc9c1d2b 100644 --- a/include/boost/asio/detail/impl/win_iocp_io_context.ipp +++ b/include/boost/asio/detail/impl/win_iocp_io_context.ipp @@ -201,7 +201,7 @@ size_t win_iocp_io_context::run(boost::system::error_code& ec) thread_call_stack::context ctx(this, this_thread); size_t n = 0; - while (do_one(INFINITE, ec)) + while (do_one(INFINITE, this_thread, ec)) if (n != (std::numeric_limits::max)()) ++n; return n; @@ -219,7 +219,7 @@ size_t win_iocp_io_context::run_one(boost::system::error_code& ec) win_iocp_thread_info this_thread; thread_call_stack::context ctx(this, this_thread); - return do_one(INFINITE, ec); + return do_one(INFINITE, this_thread, ec); } size_t win_iocp_io_context::wait_one(long usec, boost::system::error_code& ec) @@ -234,7 +234,7 @@ size_t win_iocp_io_context::wait_one(long usec, boost::system::error_code& ec) win_iocp_thread_info this_thread; thread_call_stack::context ctx(this, this_thread); - return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), ec); + return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), this_thread, ec); } size_t win_iocp_io_context::poll(boost::system::error_code& ec) @@ -250,7 +250,7 @@ size_t win_iocp_io_context::poll(boost::system::error_code& ec) thread_call_stack::context ctx(this, this_thread); size_t n = 0; - while (do_one(0, ec)) + while (do_one(0, this_thread, ec)) if (n != (std::numeric_limits::max)()) ++n; return n; @@ -268,7 +268,7 @@ size_t win_iocp_io_context::poll_one(boost::system::error_code& ec) win_iocp_thread_info this_thread; thread_call_stack::context ctx(this, this_thread); - return do_one(0, ec); + return do_one(0, this_thread, ec); } void win_iocp_io_context::stop() @@ -288,6 +288,12 @@ void win_iocp_io_context::stop() } } +void win_iocp_io_context::capture_current_exception() +{ + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + this_thread->capture_current_exception(); +} + void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op) { // Flag the operation as ready. @@ -397,7 +403,8 @@ void win_iocp_io_context::on_completion(win_iocp_operation* op, } } -size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec) +size_t win_iocp_io_context::do_one(DWORD msec, + win_iocp_thread_info& this_thread, boost::system::error_code& ec) { for (;;) { @@ -459,6 +466,7 @@ size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec) (void)on_exit; op->complete(this, result_ec, bytes_transferred); + this_thread.rethrow_pending_exception(); ec = boost::system::error_code(); return 1; } diff --git a/include/boost/asio/detail/scheduler.hpp b/include/boost/asio/detail/scheduler.hpp index fe6c9a81..148dbdc8 100644 --- a/include/boost/asio/detail/scheduler.hpp +++ b/include/boost/asio/detail/scheduler.hpp @@ -105,6 +105,9 @@ public: return thread_call_stack::contains(this) != 0; } + /// Capture the current exception so it can be rethrown from a run function. + BOOST_ASIO_DECL void capture_current_exception(); + // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. BOOST_ASIO_DECL void post_immediate_completion( diff --git a/include/boost/asio/detail/thread_info_base.hpp b/include/boost/asio/detail/thread_info_base.hpp index d5a8e818..091be139 100644 --- a/include/boost/asio/detail/thread_info_base.hpp +++ b/include/boost/asio/detail/thread_info_base.hpp @@ -15,10 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include #include #include #include +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(BOOST_ASIO_NO_EXCEPTIONS) +# include +# include +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(BOOST_ASIO_NO_EXCEPTIONS) + #include namespace boost { @@ -45,6 +53,11 @@ public: }; thread_info_base() +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(BOOST_ASIO_NO_EXCEPTIONS) + : has_pending_exception_(0) +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(BOOST_ASIO_NO_EXCEPTIONS) { for (int i = 0; i < max_mem_index; ++i) reusable_memory_[i] = 0; @@ -112,10 +125,55 @@ public: ::operator delete(pointer); } + void capture_current_exception() + { +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(BOOST_ASIO_NO_EXCEPTIONS) + switch (has_pending_exception_) + { + case 0: + has_pending_exception_ = 1; + pending_exception_ = std::current_exception(); + break; + case 1: + has_pending_exception_ = 2; + pending_exception_ = + std::make_exception_ptr( + multiple_exceptions(pending_exception_)); + default: + break; + } +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + + void rethrow_pending_exception() + { +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(BOOST_ASIO_NO_EXCEPTIONS) + if (has_pending_exception_ > 0) + { + has_pending_exception_ = 0; + std::exception_ptr ex( + BOOST_ASIO_MOVE_CAST(std::exception_ptr)( + pending_exception_)); + std::rethrow_exception(ex); + } +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + private: enum { chunk_size = 4 }; enum { max_mem_index = 3 }; void* reusable_memory_[max_mem_index]; + +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(BOOST_ASIO_NO_EXCEPTIONS) + int has_pending_exception_; + std::exception_ptr pending_exception_; +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(BOOST_ASIO_NO_EXCEPTIONS) }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_io_context.hpp b/include/boost/asio/detail/win_iocp_io_context.hpp index 9cc7690a..049cdbcf 100644 --- a/include/boost/asio/detail/win_iocp_io_context.hpp +++ b/include/boost/asio/detail/win_iocp_io_context.hpp @@ -115,6 +115,9 @@ public: return thread_call_stack::contains(this) != 0; } + /// Capture the current exception so it can be rethrown from a run function. + BOOST_ASIO_DECL void capture_current_exception(); + // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. void post_immediate_completion(win_iocp_operation* op, bool) @@ -222,7 +225,8 @@ private: // Dequeues at most one operation from the I/O completion port, and then // executes it. Returns the number of operations that were dequeued (i.e. // either 0 or 1). - BOOST_ASIO_DECL size_t do_one(DWORD msec, boost::system::error_code& ec); + BOOST_ASIO_DECL size_t do_one(DWORD msec, + win_iocp_thread_info& this_thread, boost::system::error_code& ec); // Helper to calculate the GetQueuedCompletionStatus timeout. BOOST_ASIO_DECL static DWORD get_gqcs_timeout(); diff --git a/include/boost/asio/impl/io_context.hpp b/include/boost/asio/impl/io_context.hpp index ef33eec3..553a86d5 100644 --- a/include/boost/asio/impl/io_context.hpp +++ b/include/boost/asio/impl/io_context.hpp @@ -231,32 +231,133 @@ io_context::wrap(Handler handler) #endif // !defined(BOOST_ASIO_NO_DEPRECATED) -inline io_context& -io_context::executor_type::context() const BOOST_ASIO_NOEXCEPT +template +io_context::basic_executor_type& +io_context::basic_executor_type::operator=( + const basic_executor_type& other) BOOST_ASIO_NOEXCEPT { - return io_context_; + if (this != &other) + { + io_context* old_io_context = io_context_; + io_context_ = other.io_context_; + allocator_ = other.allocator_; + bits_ = other.bits_; + if (Bits & outstanding_work_tracked) + { + if (io_context_) + io_context_->impl_.work_started(); + if (old_io_context) + old_io_context->impl_.work_finished(); + } + } + return *this; } -inline void -io_context::executor_type::on_work_started() const BOOST_ASIO_NOEXCEPT +#if defined(BOOST_ASIO_HAS_MOVE) +template +io_context::basic_executor_type& +io_context::basic_executor_type::operator=( + basic_executor_type&& other) BOOST_ASIO_NOEXCEPT { - io_context_.impl_.work_started(); + if (this != &other) + { + io_context_ = other.io_context_; + allocator_ = std::move(other.allocator_); + bits_ = other.bits_; + if (Bits & outstanding_work_tracked) + other.io_context_ = 0; + } + return *this; +} +#endif // defined(BOOST_ASIO_HAS_MOVE) + +template +inline bool io_context::basic_executor_type::running_in_this_thread() const BOOST_ASIO_NOEXCEPT +{ + return io_context_->impl_.can_dispatch(); } -inline void -io_context::executor_type::on_work_finished() const BOOST_ASIO_NOEXCEPT +template +template +void io_context::basic_executor_type::execute( + BOOST_ASIO_MOVE_ARG(Function) f) const { - io_context_.impl_.work_finished(); + typedef typename decay::type function_type; + + // Invoke immediately if the blocking.possibly property is enabled and we are + // already inside the thread pool. + if ((bits_ & blocking_never) == 0 && io_context_->impl_.can_dispatch()) + { + // Make a local, non-const copy of the function. + function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(BOOST_ASIO_NO_EXCEPTIONS) + try + { +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(BOOST_ASIO_NO_EXCEPTIONS) + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); + return; +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ + && !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + catch (...) + { + io_context_->impl_.capture_current_exception(); + return; + } +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // && !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(allocator_), + op::ptr::allocate(allocator_), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); + + BOOST_ASIO_HANDLER_CREATION((*io_context_, *p.p, + "io_context", io_context_, 0, "execute")); + + io_context_->impl_.post_immediate_completion(p.p, + (bits_ & relationship_continuation) != 0); + p.v = p.p = 0; } -template -void io_context::executor_type::dispatch( - BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) +template +inline io_context& io_context::basic_executor_type< + Allocator, Bits>::context() const BOOST_ASIO_NOEXCEPT +{ + return *io_context_; +} + +template +inline void io_context::basic_executor_type::on_work_started() const BOOST_ASIO_NOEXCEPT +{ + io_context_->impl_.work_started(); +} + +template +inline void io_context::basic_executor_type::on_work_finished() const BOOST_ASIO_NOEXCEPT +{ + io_context_->impl_.work_finished(); +} + +template +template +void io_context::basic_executor_type::dispatch( + BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay::type function_type; // Invoke immediately if we are already inside the thread pool. - if (io_context_.impl_.can_dispatch()) + if (io_context_->impl_.can_dispatch()) { // Make a local, non-const copy of the function. function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); @@ -267,58 +368,58 @@ void io_context::executor_type::dispatch( } // Allocate and construct an operation to wrap the function. - typedef detail::executor_op op; + typedef detail::executor_op op; typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); - BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, - "io_context", &this->context(), 0, "dispatch")); + BOOST_ASIO_HANDLER_CREATION((*io_context_, *p.p, + "io_context", io_context_, 0, "dispatch")); - io_context_.impl_.post_immediate_completion(p.p, false); + io_context_->impl_.post_immediate_completion(p.p, false); p.v = p.p = 0; } -template -void io_context::executor_type::post( - BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template +template +void io_context::basic_executor_type::post( + BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay::type function_type; // Allocate and construct an operation to wrap the function. - typedef detail::executor_op op; + typedef detail::executor_op op; typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); - BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, - "io_context", &this->context(), 0, "post")); + BOOST_ASIO_HANDLER_CREATION((*io_context_, *p.p, + "io_context", io_context_, 0, "post")); - io_context_.impl_.post_immediate_completion(p.p, false); + io_context_->impl_.post_immediate_completion(p.p, false); p.v = p.p = 0; } -template -void io_context::executor_type::defer( - BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template +template +void io_context::basic_executor_type::defer( + BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay::type function_type; // Allocate and construct an operation to wrap the function. - typedef detail::executor_op op; + typedef detail::executor_op op; typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); - BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, - "io_context", &this->context(), 0, "defer")); + BOOST_ASIO_HANDLER_CREATION((*io_context_, *p.p, + "io_context", io_context_, 0, "defer")); - io_context_.impl_.post_immediate_completion(p.p, true); + io_context_->impl_.post_immediate_completion(p.p, true); p.v = p.p = 0; } - -inline bool -io_context::executor_type::running_in_this_thread() const BOOST_ASIO_NOEXCEPT -{ - return io_context_.impl_.can_dispatch(); -} +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) #if !defined(BOOST_ASIO_NO_DEPRECATED) inline io_context::work::work(boost::asio::io_context& io_context) diff --git a/include/boost/asio/impl/multiple_exceptions.ipp b/include/boost/asio/impl/multiple_exceptions.ipp new file mode 100644 index 00000000..c8530bb9 --- /dev/null +++ b/include/boost/asio/impl/multiple_exceptions.ipp @@ -0,0 +1,51 @@ +// +// impl/multiple_exceptions.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP +#define BOOST_ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + +multiple_exceptions::multiple_exceptions( + std::exception_ptr first) BOOST_ASIO_NOEXCEPT + : first_(BOOST_ASIO_MOVE_CAST(std::exception_ptr)(first)) +{ +} + +const char* multiple_exceptions::what() const BOOST_ASIO_NOEXCEPT_OR_NOTHROW +{ + return "multiple exceptions"; +} + +std::exception_ptr multiple_exceptions::first_exception() const +{ + return first_; +} + +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP diff --git a/include/boost/asio/impl/src.hpp b/include/boost/asio/impl/src.hpp index 40bd1aea..02f44094 100644 --- a/include/boost/asio/impl/src.hpp +++ b/include/boost/asio/impl/src.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/asio/io_context.hpp b/include/boost/asio/io_context.hpp index 225fc86b..0611a4b7 100644 --- a/include/boost/asio/io_context.hpp +++ b/include/boost/asio/io_context.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #if defined(BOOST_ASIO_HAS_CHRONO) @@ -47,6 +48,13 @@ namespace detail { #else typedef class scheduler io_context_impl; #endif + + struct io_context_bits + { + BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1); + BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 2); + BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 4); + }; } // namespace detail /// Provides core I/O functionality. @@ -185,8 +193,13 @@ private: #endif public: - class executor_type; - friend class executor_type; + template + class basic_executor_type; + + template + friend class basic_executor_type; + + typedef basic_executor_type, 0> executor_type; #if !defined(BOOST_ASIO_NO_DEPRECATED) class work; @@ -621,10 +634,214 @@ private: impl_type& impl_; }; -/// Executor used to submit functions to an io_context. -class io_context::executor_type +namespace detail { + +} // namespace detail + +template +class io_context::basic_executor_type : detail::io_context_bits { public: + /// Copy construtor. + basic_executor_type( + const basic_executor_type& other) BOOST_ASIO_NOEXCEPT + : io_context_(other.io_context_), + allocator_(other.allocator_), + bits_(other.bits_) + { + if (Bits & outstanding_work_tracked) + if (io_context_) + io_context_->impl_.work_started(); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construtor. + basic_executor_type(basic_executor_type&& other) BOOST_ASIO_NOEXCEPT + : io_context_(other.io_context_), + allocator_(BOOST_ASIO_MOVE_CAST(Allocator)(other.allocator_)), + bits_(other.bits_) + { + if (Bits & outstanding_work_tracked) + other.io_context_ = 0; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + ~basic_executor_type() + { + if (Bits & outstanding_work_tracked) + if (io_context_) + io_context_->impl_.work_finished(); + } + + /// Assignment operator. + basic_executor_type& operator=( + const basic_executor_type& other) BOOST_ASIO_NOEXCEPT; + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move assignment operator. + basic_executor_type& operator=( + basic_executor_type&& other) BOOST_ASIO_NOEXCEPT; +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Obtain an executor with the @c blocking.possibly property. + BOOST_ASIO_CONSTEXPR basic_executor_type require( + execution::blocking_t::possibly_t) const + { + return basic_executor_type(io_context_, + allocator_, bits_ & ~blocking_never); + } + + /// Obtain an executor with the @c blocking.never property. + BOOST_ASIO_CONSTEXPR basic_executor_type require( + execution::blocking_t::never_t) const + { + return basic_executor_type(io_context_, + allocator_, bits_ | blocking_never); + } + + /// Obtain an executor with the @c relationship.fork property. + BOOST_ASIO_CONSTEXPR basic_executor_type require( + execution::relationship_t::fork_t) const + { + return basic_executor_type(io_context_, + allocator_, bits_ & ~relationship_continuation); + } + + /// Obtain an executor with the @c relationship.continuation property. + BOOST_ASIO_CONSTEXPR basic_executor_type require( + execution::relationship_t::continuation_t) const + { + return basic_executor_type(io_context_, + allocator_, bits_ | relationship_continuation); + } + + /// Obtain an executor with the @c outstanding_work.tracked property. + BOOST_ASIO_CONSTEXPR basic_executor_type + require(execution::outstanding_work_t::tracked_t) const + { + return basic_executor_type( + io_context_, allocator_, bits_); + } + + /// Obtain an executor with the @c outstanding_work.untracked property. + BOOST_ASIO_CONSTEXPR basic_executor_type + require(execution::outstanding_work_t::untracked_t) const + { + return basic_executor_type( + io_context_, allocator_, bits_); + } + + /// Obtain an executor with the specified @c allocator property. + template + BOOST_ASIO_CONSTEXPR basic_executor_type + require(execution::allocator_t a) const + { + return basic_executor_type( + io_context_, a.value(), bits_); + } + + /// Obtain an executor with the default @c allocator property. + BOOST_ASIO_CONSTEXPR basic_executor_type, Bits> + require(execution::allocator_t) const + { + return basic_executor_type, Bits>( + io_context_, std::allocator(), bits_); + } + + /// Query the current value of the @c mapping property. + static BOOST_ASIO_CONSTEXPR execution::mapping_t query( + execution::mapping_t) BOOST_ASIO_NOEXCEPT + { + return execution::mapping.thread; + } + + /// Query the current value of the @c context property. + io_context& query(execution::context_t) const BOOST_ASIO_NOEXCEPT + { + return *io_context_; + } + + /// Query the current value of the @c blocking property. + BOOST_ASIO_CONSTEXPR execution::blocking_t query( + execution::blocking_t) const BOOST_ASIO_NOEXCEPT + { + return (bits_ & blocking_never) + ? execution::blocking_t(execution::blocking.never) + : execution::blocking_t(execution::blocking.possibly); + } + + /// Query the current value of the @c relationship property. + BOOST_ASIO_CONSTEXPR execution::relationship_t query( + execution::relationship_t) const BOOST_ASIO_NOEXCEPT + { + return (bits_ & relationship_continuation) + ? execution::relationship_t(execution::relationship.continuation) + : execution::relationship_t(execution::relationship.fork); + } + + /// Query the current value of the @c outstanding_work property. + static BOOST_ASIO_CONSTEXPR execution::outstanding_work_t query( + execution::outstanding_work_t) BOOST_ASIO_NOEXCEPT + { + return (Bits & outstanding_work_tracked) + ? execution::outstanding_work_t(execution::outstanding_work.tracked) + : execution::outstanding_work_t(execution::outstanding_work.untracked); + } + + /// Query the current value of the @c allocator property. + template + BOOST_ASIO_CONSTEXPR Allocator query( + execution::allocator_t) const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } + + /// Query the current value of the @c allocator property. + BOOST_ASIO_CONSTEXPR Allocator query( + execution::allocator_t) const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } + + /// Determine whether the io_context is running in the current thread. + /** + * @return @c true if the current thread is running the io_context. Otherwise + * returns @c false. + */ + bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT; + + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator==(const basic_executor_type& a, + const basic_executor_type& b) BOOST_ASIO_NOEXCEPT + { + return a.io_context_ == b.io_context_ + && a.allocator_ == b.allocator_ + && a.bits_ == b.bits_; + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator!=(const basic_executor_type& a, + const basic_executor_type& b) BOOST_ASIO_NOEXCEPT + { + return a.io_context_ != b.io_context_ + || a.allocator_ != b.allocator_ + || a.bits_ != b.bits_; + } + + /// Execution function. + template + void execute(BOOST_ASIO_MOVE_ARG(Function) f) const; + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Obtain the underlying execution context. io_context& context() const BOOST_ASIO_NOEXCEPT; @@ -658,8 +875,9 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template - void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, + const OtherAllocator& a) const; /// Request the io_context to invoke the given function object. /** @@ -674,8 +892,9 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template - void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template + void post(BOOST_ASIO_MOVE_ARG(Function) f, + const OtherAllocator& a) const; /// Request the io_context to invoke the given function object. /** @@ -694,44 +913,45 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template - void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; - - /// Determine whether the io_context is running in the current thread. - /** - * @return @c true if the current thread is running the io_context. Otherwise - * returns @c false. - */ - bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT; - - /// Compare two executors for equality. - /** - * Two executors are equal if they refer to the same underlying io_context. - */ - friend bool operator==(const executor_type& a, - const executor_type& b) BOOST_ASIO_NOEXCEPT - { - return &a.io_context_ == &b.io_context_; - } - - /// Compare two executors for inequality. - /** - * Two executors are equal if they refer to the same underlying io_context. - */ - friend bool operator!=(const executor_type& a, - const executor_type& b) BOOST_ASIO_NOEXCEPT - { - return &a.io_context_ != &b.io_context_; - } + template + void defer(BOOST_ASIO_MOVE_ARG(Function) f, + const OtherAllocator& a) const; +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) private: friend class io_context; + template friend class basic_executor_type; - // Constructor. - explicit executor_type(io_context& i) : io_context_(i) {} + // Constructor used by io_context::get_executor(). + explicit basic_executor_type(io_context& i) BOOST_ASIO_NOEXCEPT + : io_context_(&i), + allocator_(), + bits_(0) + { + if (Bits & outstanding_work_tracked) + io_context_->impl_.work_started(); + } + + // Constructor used by require(). + basic_executor_type(io_context* i, + const Allocator& a, unsigned int bits) BOOST_ASIO_NOEXCEPT + : io_context_(i), + allocator_(a), + bits_(bits) + { + if (Bits & outstanding_work_tracked) + if (io_context_) + io_context_->impl_.work_started(); + } // The underlying io_context. - io_context& io_context_; + io_context* io_context_; + + // The allocator used for execution functions. + Allocator allocator_; + + // The runtime-switched properties of the io_context executor. + unsigned int bits_; }; #if !defined(BOOST_ASIO_NO_DEPRECATED) @@ -855,6 +1075,266 @@ template boost::asio::detail::service_id service_base::id; } // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +namespace execution { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct is_executor< + boost::asio::io_context::basic_executor_type + > : true_type +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +} // namespace execution +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member< + boost::asio::io_context::basic_executor_type, + Function + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::blocking_t::possibly_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template +struct require_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::blocking_t::never_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template +struct require_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::relationship_t::fork_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template +struct require_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::relationship_t::continuation_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::io_context::basic_executor_type< + Allocator, Bits> result_type; +}; + +template +struct require_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::outstanding_work_t::tracked_t + > : boost::asio::detail::io_context_bits +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::io_context::basic_executor_type< + Allocator, Bits | outstanding_work_tracked> result_type; +}; + +template +struct require_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::outstanding_work_t::untracked_t + > : boost::asio::detail::io_context_bits +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::io_context::basic_executor_type< + Allocator, Bits & ~outstanding_work_tracked> result_type; +}; + +template +struct require_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::io_context::basic_executor_type< + std::allocator, Bits> result_type; +}; + +template +struct require_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::io_context::basic_executor_type< + OtherAllocator, Bits> result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + boost::asio::io_context::basic_executor_type, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::outstanding_work_t + >::value + >::type + > : boost::asio::detail::io_context_bits +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::outstanding_work_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT + { + return (Bits & outstanding_work_tracked) + ? execution::outstanding_work_t(execution::outstanding_work.tracked) + : execution::outstanding_work_t(execution::outstanding_work.untracked); + } +}; + +template +struct query_static_constexpr_member< + boost::asio::io_context::basic_executor_type, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::mapping_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::mapping_t::thread_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT + { + return result_type(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + boost::asio::io_context::basic_executor_type, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::blocking_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::blocking_t result_type; +}; + +template +struct query_member< + boost::asio::io_context::basic_executor_type, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::relationship_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::relationship_t result_type; +}; + +template +struct query_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::context_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::io_context& result_type; +}; + +template +struct query_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef Allocator result_type; +}; + +template +struct query_member< + boost::asio::io_context::basic_executor_type, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef Allocator result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + } // namespace asio } // namespace boost diff --git a/include/boost/asio/multiple_exceptions.hpp b/include/boost/asio/multiple_exceptions.hpp new file mode 100644 index 00000000..594cbc87 --- /dev/null +++ b/include/boost/asio/multiple_exceptions.hpp @@ -0,0 +1,60 @@ +// +// multiple_exceptions.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_MULTIPLE_EXCEPTIONS_HPP +#define BOOST_ASIO_MULTIPLE_EXCEPTIONS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ + || defined(GENERATING_DOCUMENTATION) + +/// Exception thrown when there are multiple pending exceptions to rethrow. +class multiple_exceptions + : public std::exception +{ +public: + /// Constructor. + BOOST_ASIO_DECL multiple_exceptions( + std::exception_ptr first) BOOST_ASIO_NOEXCEPT; + + /// Obtain message associated with exception. + BOOST_ASIO_DECL virtual const char* what() const + BOOST_ASIO_NOEXCEPT_OR_NOTHROW; + + /// Obtain a pointer to the first exception. + BOOST_ASIO_DECL std::exception_ptr first_exception() const; + +private: + std::exception_ptr first_; +}; + +#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + // || defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_MULTIPLE_EXCEPTIONS_HPP diff --git a/test/io_context.cpp b/test/io_context.cpp index 7b2ff982..83f8b6a8 100644 --- a/test/io_context.cpp +++ b/test/io_context.cpp @@ -354,9 +354,232 @@ void io_context_service_test() BOOST_ASIO_CHECK(!boost::asio::has_service(ioc3)); } +void io_context_executor_query_test() +{ + io_context ioc; + + BOOST_ASIO_CHECK( + &boost::asio::query(ioc.get_executor(), + boost::asio::execution::context) + == &ioc); + + BOOST_ASIO_CHECK( + boost::asio::query(ioc.get_executor(), + boost::asio::execution::blocking) + == boost::asio::execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ioc.get_executor(), + boost::asio::execution::blocking.possibly) + == boost::asio::execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(ioc.get_executor(), + boost::asio::execution::outstanding_work) + == boost::asio::execution::outstanding_work.untracked); + + BOOST_ASIO_CHECK( + boost::asio::query(ioc.get_executor(), + boost::asio::execution::outstanding_work.untracked) + == boost::asio::execution::outstanding_work.untracked); + + BOOST_ASIO_CHECK( + boost::asio::query(ioc.get_executor(), + boost::asio::execution::relationship) + == boost::asio::execution::relationship.fork); + + BOOST_ASIO_CHECK( + boost::asio::query(ioc.get_executor(), + boost::asio::execution::relationship.fork) + == boost::asio::execution::relationship.fork); + + BOOST_ASIO_CHECK( + boost::asio::query(ioc.get_executor(), + boost::asio::execution::mapping) + == boost::asio::execution::mapping.thread); + + BOOST_ASIO_CHECK( + boost::asio::query(ioc.get_executor(), + boost::asio::execution::allocator) + == std::allocator()); +} + +void io_context_executor_execute_test() +{ + io_context ioc; + int count = 0; + + boost::asio::execution::execute(ioc.get_executor(), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::require(ioc.get_executor(), + boost::asio::execution::blocking.possibly), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::require(ioc.get_executor(), + boost::asio::execution::blocking.never), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + BOOST_ASIO_CHECK(!ioc.stopped()); + + boost::asio::execution::execute( + boost::asio::require(ioc.get_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.tracked), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::require(ioc.get_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::require(ioc.get_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.fork), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::require(ioc.get_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::prefer( + boost::asio::require(ioc.get_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + boost::asio::execution::allocator(std::allocator())), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::prefer( + boost::asio::require(ioc.get_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + boost::asio::execution::allocator), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); +} + BOOST_ASIO_TEST_SUITE ( "io_context", BOOST_ASIO_TEST_CASE(io_context_test) BOOST_ASIO_TEST_CASE(io_context_service_test) + BOOST_ASIO_TEST_CASE(io_context_executor_query_test) + BOOST_ASIO_TEST_CASE(io_context_executor_execute_test) ) From d56b243026b57d35d00d9b49070b864d1e4ff783 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Tue, 23 Jun 2020 11:08:10 +1000 Subject: [PATCH 65/90] io_context.hpp --- include/boost/asio/io_context.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/asio/io_context.hpp b/include/boost/asio/io_context.hpp index 0611a4b7..621f3dfe 100644 --- a/include/boost/asio/io_context.hpp +++ b/include/boost/asio/io_context.hpp @@ -199,6 +199,7 @@ public: template friend class basic_executor_type; + /// Executor used to submit functions to an io_context. typedef basic_executor_type, 0> executor_type; #if !defined(BOOST_ASIO_NO_DEPRECATED) @@ -638,6 +639,7 @@ namespace detail { } // namespace detail +/// Executor implementation type used to submit functions to an io_context. template class io_context::basic_executor_type : detail::io_context_bits { From 95eb4eb16cdbaddf32f258384ae180e5c5584835 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:14:37 +1000 Subject: [PATCH 66/90] Update system_executor to standard executor form. --- include/boost/asio/impl/system_context.ipp | 20 +- include/boost/asio/impl/system_executor.hpp | 121 +++++- include/boost/asio/system_context.hpp | 15 +- include/boost/asio/system_executor.hpp | 445 ++++++++++++++++++-- include/boost/asio/ts/netfwd.hpp | 3 +- test/system_executor.cpp | 142 ++++++- 6 files changed, 703 insertions(+), 43 deletions(-) diff --git a/include/boost/asio/impl/system_context.ipp b/include/boost/asio/impl/system_context.ipp index 36fadfbb..8eaba70b 100644 --- a/include/boost/asio/impl/system_context.ipp +++ b/include/boost/asio/impl/system_context.ipp @@ -29,8 +29,19 @@ struct system_context::thread_function void operator()() { - boost::system::error_code ec; - scheduler_->run(ec); +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try + { +#endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) + boost::system::error_code ec; + scheduler_->run(ec); +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + catch (...) + { + std::terminate(); + } +#endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) } }; @@ -40,8 +51,9 @@ system_context::system_context() scheduler_.work_started(); thread_function f = { &scheduler_ }; - std::size_t num_threads = detail::thread::hardware_concurrency() * 2; - threads_.create_threads(f, num_threads ? num_threads : 2); + num_threads_ = detail::thread::hardware_concurrency() * 2; + num_threads_ = num_threads_ ? num_threads_ : 2; + threads_.create_threads(f, num_threads_); } system_context::~system_context() diff --git a/include/boost/asio/impl/system_executor.hpp b/include/boost/asio/impl/system_executor.hpp index ef4760d8..c14729ee 100644 --- a/include/boost/asio/impl/system_executor.hpp +++ b/include/boost/asio/impl/system_executor.hpp @@ -26,22 +26,121 @@ namespace boost { namespace asio { -inline system_context& system_executor::context() const BOOST_ASIO_NOEXCEPT +template +inline system_context& +basic_system_executor::query( + execution::context_t) BOOST_ASIO_NOEXCEPT { return detail::global(); } -template -void system_executor::dispatch( - BOOST_ASIO_MOVE_ARG(Function) f, const Allocator&) const +template +inline std::size_t +basic_system_executor::query( + execution::occupancy_t) const BOOST_ASIO_NOEXCEPT +{ + return detail::global().num_threads_; +} + +template +template +inline void +basic_system_executor::do_execute( + BOOST_ASIO_MOVE_ARG(Function) f, execution::blocking_t::possibly_t) const +{ + // Obtain a non-const instance of the function. + detail::non_const_lvalue f2(f); + +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try + { +#endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(f2.value, f2.value); +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + catch (...) + { + std::terminate(); + } +#endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) +} + +template +template +inline void +basic_system_executor::do_execute( + BOOST_ASIO_MOVE_ARG(Function) f, execution::blocking_t::always_t) const +{ + // Obtain a non-const instance of the function. + detail::non_const_lvalue f2(f); + +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try + { +#endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(f2.value, f2.value); +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + catch (...) + { + std::terminate(); + } +#endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) +} + +template +template +void basic_system_executor::do_execute( + BOOST_ASIO_MOVE_ARG(Function) f, execution::blocking_t::never_t) const +{ + system_context& ctx = detail::global(); + + // Allocate and construct an operation to wrap the function. + typedef typename decay::type function_type; + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(allocator_), + op::ptr::allocate(allocator_), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); + + if (is_same::value) + { + BOOST_ASIO_HANDLER_CREATION((ctx, *p.p, + "system_executor", &ctx, 0, "execute(blk=never,rel=cont)")); + } + else + { + BOOST_ASIO_HANDLER_CREATION((ctx, *p.p, + "system_executor", &ctx, 0, "execute(blk=never,rel=fork)")); + } + + ctx.scheduler_.post_immediate_completion(p.p, + is_same::value); + p.v = p.p = 0; +} + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) +template +inline system_context& basic_system_executor< + Blocking, Relationship, Allocator>::context() const BOOST_ASIO_NOEXCEPT +{ + return detail::global(); +} + +template +template +void basic_system_executor::dispatch( + BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator&) const { typename decay::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); boost_asio_handler_invoke_helpers::invoke(tmp, tmp); } -template -void system_executor::post( - BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template +template +void basic_system_executor::post( + BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay::type function_type; @@ -59,9 +158,10 @@ void system_executor::post( p.v = p.p = 0; } -template -void system_executor::defer( - BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +template +template +void basic_system_executor::defer( + BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay::type function_type; @@ -78,6 +178,7 @@ void system_executor::defer( ctx.scheduler_.post_immediate_completion(p.p, true); p.v = p.p = 0; } +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) } // namespace asio } // namespace boost diff --git a/include/boost/asio/system_context.hpp b/include/boost/asio/system_context.hpp index 62a0db26..c8c2f321 100644 --- a/include/boost/asio/system_context.hpp +++ b/include/boost/asio/system_context.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -25,14 +26,19 @@ namespace boost { namespace asio { -class system_executor; +template +class basic_system_executor; /// The executor context for the system executor. class system_context : public execution_context { public: /// The executor type associated with the context. - typedef system_executor executor_type; + typedef basic_system_executor< + execution::blocking_t::possibly_t, + execution::relationship_t::fork_t, + std::allocator + > executor_type; /// Destructor shuts down all threads in the system thread pool. BOOST_ASIO_DECL ~system_context(); @@ -56,7 +62,7 @@ private: BOOST_ASIO_DECL system_context(); private: - friend class system_executor; + template friend class basic_system_executor; struct thread_function; @@ -68,6 +74,9 @@ private: // The threads in the system thread pool. detail::thread_group threads_; + + // The number of threads in the pool. + std::size_t num_threads_; }; } // namespace asio diff --git a/include/boost/asio/system_executor.hpp b/include/boost/asio/system_executor.hpp index 718d7b86..8f439bde 100644 --- a/include/boost/asio/system_executor.hpp +++ b/include/boost/asio/system_executor.hpp @@ -16,6 +16,8 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include +#include +#include #include @@ -27,13 +29,155 @@ class system_context; /// An executor that uses arbitrary threads. /** * The system executor represents an execution context where functions are - * permitted to run on arbitrary threads. The post() and defer() functions - * schedule the function to run on an unspecified system thread pool, and - * dispatch() invokes the function immediately. + * permitted to run on arbitrary threads. When the blocking.never property is + * established, the system executor will schedule the function to run on an + * unspecified system thread pool. When either blocking.possibly or + * blocking.always is established, the executor invokes the function + * immediately. */ -class system_executor +template +class basic_system_executor { public: + /// Default constructor. + basic_system_executor() BOOST_ASIO_NOEXCEPT + : allocator_(Allocator()) + { + } + + /// Obtain an executor with the @c blocking.possibly property. + basic_system_executor + require(execution::blocking_t::possibly_t) const + { + return basic_system_executor(allocator_); + } + + /// Obtain an executor with the @c blocking.always property. + basic_system_executor + require(execution::blocking_t::always_t) const + { + return basic_system_executor(allocator_); + } + + /// Obtain an executor with the @c blocking.never property. + basic_system_executor + require(execution::blocking_t::never_t) const + { + return basic_system_executor(allocator_); + } + + /// Obtain an executor with the @c relationship.continuation property. + basic_system_executor + require(execution::relationship_t::continuation_t) const + { + return basic_system_executor(allocator_); + } + + /// Obtain an executor with the @c relationship.fork property. + basic_system_executor + require(execution::relationship_t::fork_t) const + { + return basic_system_executor(allocator_); + } + + /// Obtain an executor with the specified @c allocator property. + template + basic_system_executor + require(execution::allocator_t a) const + { + return basic_system_executor(a.value()); + } + + /// Obtain an executor with the default @c allocator property. + basic_system_executor > + require(execution::allocator_t) const + { + return basic_system_executor >(); + } + + /// Query the current value of the @c mapping property. + static BOOST_ASIO_CONSTEXPR execution::mapping_t query( + execution::mapping_t) BOOST_ASIO_NOEXCEPT + { + return execution::mapping.thread; + } + + /// Query the current value of the @c context property. + static system_context& query(execution::context_t) BOOST_ASIO_NOEXCEPT; + + /// Query the current value of the @c blocking property. + static BOOST_ASIO_CONSTEXPR execution::blocking_t query( + execution::blocking_t) BOOST_ASIO_NOEXCEPT + { + return Blocking(); + } + + /// Query the current value of the @c relationship property. + static BOOST_ASIO_CONSTEXPR execution::relationship_t query( + execution::relationship_t) BOOST_ASIO_NOEXCEPT + { + return Relationship(); + } + + /// Query the current value of the @c allocator property. + template + BOOST_ASIO_CONSTEXPR Allocator query( + execution::allocator_t) const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } + + /// Query the current value of the @c allocator property. + BOOST_ASIO_CONSTEXPR Allocator query( + execution::allocator_t) const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } + + /// Query the occupancy (recommended number of work items) for the system + /// context. + std::size_t query(execution::occupancy_t) const BOOST_ASIO_NOEXCEPT; + + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator==(const basic_system_executor&, + const basic_system_executor&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator!=(const basic_system_executor&, + const basic_system_executor&) BOOST_ASIO_NOEXCEPT + { + return false; + } + + /// Oneway execution function. + template + void execute(BOOST_ASIO_MOVE_ARG(Function) f) const + { + this->do_execute(BOOST_ASIO_MOVE_CAST(Function)(f), Blocking()); + } + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Obtain the underlying execution context. system_context& context() const BOOST_ASIO_NOEXCEPT; @@ -65,8 +209,8 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template - void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const; /// Request the system executor to invoke the given function object. /** @@ -81,8 +225,8 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template - void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template + void post(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const; /// Request the system executor to invoke the given function object. /** @@ -97,30 +241,283 @@ public: * @param a An allocator that may be used by the executor to allocate the * internal storage needed for function invocation. */ - template - void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + template + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const; +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) - /// Compare two executors for equality. - /** - * System executors always compare equal. - */ - friend bool operator==(const system_executor&, - const system_executor&) BOOST_ASIO_NOEXCEPT +private: + template friend class basic_system_executor; + + // Constructor used by require(). + basic_system_executor(const Allocator& a) + : allocator_(a) { - return true; } - /// Compare two executors for inequality. - /** - * System executors always compare equal. - */ - friend bool operator!=(const system_executor&, - const system_executor&) BOOST_ASIO_NOEXCEPT + /// Execution helper implementation for the possibly blocking property. + template + void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, + execution::blocking_t::possibly_t) const; + + /// Execution helper implementation for the always blocking property. + template + void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, + execution::blocking_t::always_t) const; + + /// Execution helper implementation for the never blocking property. + template + void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, + execution::blocking_t::never_t) const; + + // The allocator used for execution functions. + Allocator allocator_; +}; + +/// An executor that uses arbitrary threads. +/** + * The system executor represents an execution context where functions are + * permitted to run on arbitrary threads. When the blocking.never property is + * established, the system executor will schedule the function to run on an + * unspecified system thread pool. When either blocking.possibly or + * blocking.always is established, the executor invokes the function + * immediately. + */ +typedef basic_system_executor > + system_executor; + +#if !defined(GENERATING_DOCUMENTATION) + +namespace execution { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct is_executor< + boost::asio::basic_system_executor + > : true_type +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +} // namespace execution +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member< + boost::asio::basic_system_executor, + Function + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + boost::asio::basic_system_executor, + boost::asio::execution::blocking_t::possibly_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::basic_system_executor< + boost::asio::execution::blocking_t::possibly_t, + Relationship, Allocator> result_type; +}; + +template +struct require_member< + boost::asio::basic_system_executor, + boost::asio::execution::blocking_t::always_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::basic_system_executor< + boost::asio::execution::blocking_t::always_t, + Relationship, Allocator> result_type; +}; + +template +struct require_member< + boost::asio::basic_system_executor, + boost::asio::execution::blocking_t::never_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::basic_system_executor< + boost::asio::execution::blocking_t::never_t, + Relationship, Allocator> result_type; +}; + +template +struct require_member< + boost::asio::basic_system_executor, + boost::asio::execution::relationship_t::fork_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::basic_system_executor result_type; +}; + +template +struct require_member< + boost::asio::basic_system_executor, + boost::asio::execution::relationship_t::continuation_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::basic_system_executor result_type; +}; + +template +struct require_member< + boost::asio::basic_system_executor, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::basic_system_executor > result_type; +}; + +template +struct require_member< + boost::asio::basic_system_executor, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef boost::asio::basic_system_executor result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +template +struct query_static_constexpr_member< + boost::asio::basic_system_executor, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::mapping_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::mapping_t::thread_t result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { - return false; + return result_type(); } }; +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member< + boost::asio::basic_system_executor, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::blocking_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::blocking_t result_type; +}; + +template +struct query_member< + boost::asio::basic_system_executor, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::relationship_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::execution::relationship_t result_type; +}; + +template +struct query_member< + boost::asio::basic_system_executor, + boost::asio::execution::context_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::system_context& result_type; +}; + +template +struct query_member< + boost::asio::basic_system_executor, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef Allocator result_type; +}; + +template +struct query_member< + boost::asio::basic_system_executor, + boost::asio::execution::allocator_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef Allocator result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + } // namespace asio } // namespace boost diff --git a/include/boost/asio/ts/netfwd.hpp b/include/boost/asio/ts/netfwd.hpp index 2a7d5a85..cdc0f536 100644 --- a/include/boost/asio/ts/netfwd.hpp +++ b/include/boost/asio/ts/netfwd.hpp @@ -40,7 +40,8 @@ class executor_binder; template class executor_work_guard; -class system_executor; +template +class basic_system_executor; class executor; diff --git a/test/system_executor.cpp b/test/system_executor.cpp index 2f286f43..a8f4f706 100644 --- a/test/system_executor.cpp +++ b/test/system_executor.cpp @@ -21,10 +21,150 @@ // Test that header file is self-contained. #include +#include +#include #include "unit_test.hpp" +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +using namespace boost::asio; + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif + +void increment(boost::asio::detail::atomic_count* count) +{ + ++(*count); +} + +void system_executor_query_test() +{ + BOOST_ASIO_CHECK( + &boost::asio::query(system_executor(), + boost::asio::execution::context) + != static_cast(0)); + + BOOST_ASIO_CHECK( + boost::asio::query(system_executor(), + boost::asio::execution::blocking) + == boost::asio::execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(system_executor(), + boost::asio::execution::blocking.possibly) + == boost::asio::execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(system_executor(), + boost::asio::execution::outstanding_work) + == boost::asio::execution::outstanding_work.untracked); + + BOOST_ASIO_CHECK( + boost::asio::query(system_executor(), + boost::asio::execution::outstanding_work.untracked) + == boost::asio::execution::outstanding_work.untracked); + + BOOST_ASIO_CHECK( + boost::asio::query(system_executor(), + boost::asio::execution::relationship) + == boost::asio::execution::relationship.fork); + + BOOST_ASIO_CHECK( + boost::asio::query(system_executor(), + boost::asio::execution::relationship.fork) + == boost::asio::execution::relationship.fork); + + BOOST_ASIO_CHECK( + boost::asio::query(system_executor(), + boost::asio::execution::bulk_guarantee) + == boost::asio::execution::bulk_guarantee.unsequenced); + + BOOST_ASIO_CHECK( + boost::asio::query(system_executor(), + boost::asio::execution::mapping) + == boost::asio::execution::mapping.thread); + + BOOST_ASIO_CHECK( + boost::asio::query(system_executor(), + boost::asio::execution::allocator) + == std::allocator()); +} + +void system_executor_execute_test() +{ + boost::asio::detail::atomic_count count(0); + + boost::asio::execution::execute(system_executor(), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(system_executor(), + boost::asio::execution::blocking.possibly), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(system_executor(), + boost::asio::execution::blocking.always), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(system_executor(), + boost::asio::execution::blocking.never), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(system_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(system_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.fork), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::require(system_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::prefer( + boost::asio::require(system_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + boost::asio::execution::allocator(std::allocator())), + bindns::bind(increment, &count)); + + boost::asio::execution::execute( + boost::asio::prefer( + boost::asio::require(system_executor(), + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + boost::asio::execution::allocator), + bindns::bind(increment, &count)); + + boost::asio::query(system_executor(), execution::context).join(); + + BOOST_ASIO_CHECK(count == 9); +} + BOOST_ASIO_TEST_SUITE ( "system_executor", - BOOST_ASIO_TEST_CASE(null_test) + BOOST_ASIO_TEST_CASE(system_executor_query_test) + BOOST_ASIO_TEST_CASE(system_executor_execute_test) ) From 0e0a38df5f65f2a8c1f7b72c77357215567819f3 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:14:51 +1000 Subject: [PATCH 67/90] Add standard executor support to post(), dispatch(), and defer(). --- include/boost/asio/defer.hpp | 5 +- include/boost/asio/detail/work_dispatcher.hpp | 69 ++++++++- include/boost/asio/dispatch.hpp | 5 +- include/boost/asio/impl/defer.hpp | 133 ++++++++++++++++-- include/boost/asio/impl/dispatch.hpp | 128 +++++++++++++++-- include/boost/asio/impl/post.hpp | 133 ++++++++++++++++-- include/boost/asio/post.hpp | 5 +- 7 files changed, 433 insertions(+), 45 deletions(-) diff --git a/include/boost/asio/defer.hpp b/include/boost/asio/defer.hpp index a21aeb92..7967f9dc 100644 --- a/include/boost/asio/defer.hpp +++ b/include/boost/asio/defer.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -101,7 +102,9 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), - typename enable_if::value>::type* = 0); + typename enable_if< + execution::is_executor::value || is_executor::value + >::type* = 0); /// Submits a completion token or function object for execution. /** diff --git a/include/boost/asio/detail/work_dispatcher.hpp b/include/boost/asio/detail/work_dispatcher.hpp index 3416ead2..700eceec 100644 --- a/include/boost/asio/detail/work_dispatcher.hpp +++ b/include/boost/asio/detail/work_dispatcher.hpp @@ -19,6 +19,11 @@ #include #include #include +#include +#include +#include +#include +#include #include @@ -26,13 +31,64 @@ namespace boost { namespace asio { namespace detail { -template +template class work_dispatcher { public: template - explicit work_dispatcher(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) - : work_((get_associated_executor)(handler)), + work_dispatcher(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + const Executor& handler_ex) + : handler_(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), + executor_(boost::asio::prefer(handler_ex, + execution::outstanding_work.tracked)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + work_dispatcher(const work_dispatcher& other) + : handler_(other.handler_), + executor_(other.executor_) + { + } + + work_dispatcher(work_dispatcher&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + executor_(BOOST_ASIO_MOVE_CAST(work_executor_type)(other.executor_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()() + { + execution::execute( + boost::asio::prefer(executor_, + execution::blocking.possibly, + execution::allocator((get_associated_allocator)(handler_))), + BOOST_ASIO_MOVE_CAST(Handler)(handler_)); + } + +private: + typedef typename decay< + typename prefer_result_type::type + >::type work_executor_type; + + Handler handler_; + work_executor_type executor_; +}; + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) + +template +class work_dispatcher::value>::type> +{ +public: + template + work_dispatcher(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + const Executor& handler_ex) + : work_(handler_ex), handler_(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)) { } @@ -45,8 +101,7 @@ public: } work_dispatcher(work_dispatcher&& other) - : work_(BOOST_ASIO_MOVE_CAST(executor_work_guard< - typename associated_executor::type>)(other.work_)), + : work_(BOOST_ASIO_MOVE_CAST(executor_work_guard)(other.work_)), handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)) { } @@ -62,10 +117,12 @@ public: } private: - executor_work_guard::type> work_; + executor_work_guard work_; Handler handler_; }; +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) + } // namespace detail } // namespace asio } // namespace boost diff --git a/include/boost/asio/dispatch.hpp b/include/boost/asio/dispatch.hpp index 77eefcae..bf278f13 100644 --- a/include/boost/asio/dispatch.hpp +++ b/include/boost/asio/dispatch.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -91,7 +92,9 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), - typename enable_if::value>::type* = 0); + typename enable_if< + execution::is_executor::value || is_executor::value + >::type* = 0); /// Submits a completion token or function object for execution. /** diff --git a/include/boost/asio/impl/defer.hpp b/include/boost/asio/impl/defer.hpp index 4db26d19..7821bdaf 100644 --- a/include/boost/asio/impl/defer.hpp +++ b/include/boost/asio/impl/defer.hpp @@ -19,6 +19,11 @@ #include #include #include +#include +#include +#include +#include +#include #include @@ -30,14 +35,47 @@ class initiate_defer { public: template - void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + execution::is_executor< + typename associated_executor< + typename decay::type + >::type + >::value + >::type* = 0) const { - typedef typename decay::type DecayedHandler; + typedef typename decay::type handler_t; - typename associated_executor::type ex( + typename associated_executor::type ex( (get_associated_executor)(handler)); - typename associated_allocator::type alloc( + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + execution::execute( + boost::asio::prefer( + boost::asio::require(ex, execution::blocking.never), + execution::relationship.continuation, + execution::allocator(alloc)), + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + !execution::is_executor< + typename associated_executor< + typename decay::type + >::type + >::value + >::type* = 0) const + { + typedef typename decay::type handler_t; + + typename associated_executor::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator::type alloc( (get_associated_allocator)(handler)); ex.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); @@ -61,18 +99,85 @@ public: } template - void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + execution::is_executor< + typename conditional::type + >::value + >::type* = 0) const { - typedef typename decay::type DecayedHandler; + typedef typename decay::type handler_t; - typename associated_allocator::type alloc( + typedef typename associated_executor< + handler_t, Executor>::type handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + typename associated_allocator::type alloc( (get_associated_allocator)(handler)); - ex_.defer(detail::work_dispatcher( - BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); + if (this->is_same_executor(ex_, handler_ex)) + { + execution::execute( + boost::asio::prefer( + boost::asio::require(ex_, execution::blocking.never), + execution::relationship.continuation, + execution::allocator(alloc)), + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); + } + else + { + execution::execute( + boost::asio::prefer( + boost::asio::require(ex_, execution::blocking.never), + execution::relationship.continuation, + execution::allocator(alloc)), + detail::work_dispatcher( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex)); + } + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + !execution::is_executor< + typename conditional::type + >::value + >::type* = 0) const + { + typedef typename decay::type handler_t; + + typedef typename associated_executor< + handler_t, Executor>::type handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + if (this->is_same_executor(ex_, handler_ex)) + { + ex_.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); + } + else + { + ex_.defer(detail::work_dispatcher( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), + handler_ex), alloc); + } } private: + template + bool is_same_executor(const T&, const U&) const BOOST_ASIO_NOEXCEPT + { + return false; + } + + template + bool is_same_executor(const T& a, const T& b) const BOOST_ASIO_NOEXCEPT + { + return a == b; + } + Executor ex_; }; @@ -90,7 +195,9 @@ template BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if::value>::type*) + typename enable_if< + execution::is_executor::value || is_executor::value + >::type*) { return async_initiate( detail::initiate_defer_with_executor(ex), token); @@ -103,8 +210,10 @@ inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( typename enable_if::value>::type*) { - return (defer)(ctx.get_executor(), - BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); + return async_initiate( + detail::initiate_defer_with_executor< + typename ExecutionContext::executor_type>( + ctx.get_executor()), token); } } // namespace asio diff --git a/include/boost/asio/impl/dispatch.hpp b/include/boost/asio/impl/dispatch.hpp index 8b0df469..e1642c1e 100644 --- a/include/boost/asio/impl/dispatch.hpp +++ b/include/boost/asio/impl/dispatch.hpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include @@ -30,14 +33,46 @@ class initiate_dispatch { public: template - void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + execution::is_executor< + typename associated_executor< + typename decay::type + >::type + >::value + >::type* = 0) const { - typedef typename decay::type DecayedHandler; + typedef typename decay::type handler_t; - typename associated_executor::type ex( + typename associated_executor::type ex( (get_associated_executor)(handler)); - typename associated_allocator::type alloc( + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + execution::execute( + boost::asio::prefer(ex, + execution::blocking.possibly, + execution::allocator(alloc)), + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + !execution::is_executor< + typename associated_executor< + typename decay::type + >::type + >::value + >::type* = 0) const + { + typedef typename decay::type handler_t; + + typename associated_executor::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator::type alloc( (get_associated_allocator)(handler)); ex.dispatch(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); @@ -61,18 +96,83 @@ public: } template - void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + execution::is_executor< + typename conditional::type + >::value + >::type* = 0) const { - typedef typename decay::type DecayedHandler; + typedef typename decay::type handler_t; - typename associated_allocator::type alloc( + typedef typename associated_executor< + handler_t, Executor>::type handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + typename associated_allocator::type alloc( (get_associated_allocator)(handler)); - ex_.dispatch(detail::work_dispatcher( - BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); + if (this->is_same_executor(ex_, handler_ex)) + { + execution::execute( + boost::asio::prefer(ex_, + execution::blocking.possibly, + execution::allocator(alloc)), + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); + } + else + { + execution::execute( + boost::asio::prefer(ex_, + execution::blocking.possibly, + execution::allocator(alloc)), + detail::work_dispatcher( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex)); + } + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + !execution::is_executor< + typename conditional::type + >::value + >::type* = 0) const + { + typedef typename decay::type handler_t; + + typedef typename associated_executor< + handler_t, Executor>::type handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + if (this->is_same_executor(ex_, handler_ex)) + { + ex_.dispatch(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); + } + else + { + ex_.dispatch(detail::work_dispatcher( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), + handler_ex), alloc); + } } private: + template + bool is_same_executor(const T&, const U&) const BOOST_ASIO_NOEXCEPT + { + return false; + } + + template + bool is_same_executor(const T& a, const T& b) const BOOST_ASIO_NOEXCEPT + { + return a == b; + } + Executor ex_; }; @@ -90,7 +190,9 @@ template BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if::value>::type*) + typename enable_if< + execution::is_executor::value || is_executor::value + >::type*) { return async_initiate( detail::initiate_dispatch_with_executor(ex), token); @@ -103,8 +205,10 @@ inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( typename enable_if::value>::type*) { - return (dispatch)(ctx.get_executor(), - BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); + return async_initiate( + detail::initiate_dispatch_with_executor< + typename ExecutionContext::executor_type>( + ctx.get_executor()), token); } } // namespace asio diff --git a/include/boost/asio/impl/post.hpp b/include/boost/asio/impl/post.hpp index ef7a739b..3a89a1c6 100644 --- a/include/boost/asio/impl/post.hpp +++ b/include/boost/asio/impl/post.hpp @@ -19,6 +19,11 @@ #include #include #include +#include +#include +#include +#include +#include #include @@ -30,14 +35,47 @@ class initiate_post { public: template - void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + execution::is_executor< + typename associated_executor< + typename decay::type + >::type + >::value + >::type* = 0) const { - typedef typename decay::type DecayedHandler; + typedef typename decay::type handler_t; - typename associated_executor::type ex( + typename associated_executor::type ex( (get_associated_executor)(handler)); - typename associated_allocator::type alloc( + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + execution::execute( + boost::asio::prefer( + boost::asio::require(ex, execution::blocking.never), + execution::relationship.fork, + execution::allocator(alloc)), + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + !execution::is_executor< + typename associated_executor< + typename decay::type + >::type + >::value + >::type* = 0) const + { + typedef typename decay::type handler_t; + + typename associated_executor::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator::type alloc( (get_associated_allocator)(handler)); ex.post(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); @@ -61,18 +99,85 @@ public: } template - void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + execution::is_executor< + typename conditional::type + >::value + >::type* = 0) const { - typedef typename decay::type DecayedHandler; + typedef typename decay::type handler_t; - typename associated_allocator::type alloc( + typedef typename associated_executor< + handler_t, Executor>::type handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + typename associated_allocator::type alloc( (get_associated_allocator)(handler)); - ex_.post(detail::work_dispatcher( - BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); + if (this->is_same_executor(ex_, handler_ex)) + { + execution::execute( + boost::asio::prefer( + boost::asio::require(ex_, execution::blocking.never), + execution::relationship.fork, + execution::allocator(alloc)), + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); + } + else + { + execution::execute( + boost::asio::prefer( + boost::asio::require(ex_, execution::blocking.never), + execution::relationship.fork, + execution::allocator(alloc)), + detail::work_dispatcher( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex)); + } + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + typename enable_if< + !execution::is_executor< + typename conditional::type + >::value + >::type* = 0) const + { + typedef typename decay::type handler_t; + + typedef typename associated_executor< + handler_t, Executor>::type handler_ex_t; + handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); + + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + if (this->is_same_executor(ex_, handler_ex)) + { + ex_.post(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); + } + else + { + ex_.post(detail::work_dispatcher( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), + handler_ex), alloc); + } } private: + template + bool is_same_executor(const T&, const U&) const BOOST_ASIO_NOEXCEPT + { + return false; + } + + template + bool is_same_executor(const T& a, const T& b) const BOOST_ASIO_NOEXCEPT + { + return a == b; + } + Executor ex_; }; @@ -90,7 +195,9 @@ template BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, - typename enable_if::value>::type*) + typename enable_if< + execution::is_executor::value || is_executor::value + >::type*) { return async_initiate( detail::initiate_post_with_executor(ex), token); @@ -103,8 +210,10 @@ inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( typename enable_if::value>::type*) { - return (post)(ctx.get_executor(), - BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); + return async_initiate( + detail::initiate_post_with_executor< + typename ExecutionContext::executor_type>( + ctx.get_executor()), token); } } // namespace asio diff --git a/include/boost/asio/post.hpp b/include/boost/asio/post.hpp index 8f08a65a..c4094924 100644 --- a/include/boost/asio/post.hpp +++ b/include/boost/asio/post.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -97,7 +98,9 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), - typename enable_if::value>::type* = 0); + typename enable_if< + execution::is_executor::value || is_executor::value + >::type* = 0); /// Submits a completion token or function object for execution. /** From bbe07663c0caa3d875e7185057d3d23c91b78860 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:15:54 +1000 Subject: [PATCH 68/90] Add standard executor support to async I/O operations. --- include/boost/asio/detail/handler_work.hpp | 88 ++++++++++++++++--- include/boost/asio/detail/io_object_impl.hpp | 24 ++++- include/boost/asio/windows/overlapped_ptr.hpp | 6 +- 3 files changed, 103 insertions(+), 15 deletions(-) diff --git a/include/boost/asio/detail/handler_work.hpp b/include/boost/asio/detail/handler_work.hpp index d398d776..a20a2e0b 100644 --- a/include/boost/asio/detail/handler_work.hpp +++ b/include/boost/asio/detail/handler_work.hpp @@ -19,6 +19,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include @@ -35,6 +42,66 @@ template class handler_work_base { +public: + explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT + : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + template + handler_work_base(const Executor& ex, + const OtherExecutor&) BOOST_ASIO_NOEXCEPT + : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT + : executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + bool owns_work() const BOOST_ASIO_NOEXCEPT + { + return true; + } + + template + void dispatch(Function& function, Handler& handler) + { + execution::execute( + boost::asio::prefer(executor_, + execution::blocking.possibly, + execution::allocator((get_associated_allocator)(handler))), + BOOST_ASIO_MOVE_CAST(Function)(function)); + } + +private: + typedef typename decay< + typename prefer_result_type::type + >::type executor_type; + + executor_type executor_; +}; + +template +class handler_work_base::value + && (!is_same::value + || !is_same::value) + >::type> +{ public: explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT : executor_(ex), @@ -89,9 +156,11 @@ public: return owns_work_; } - const Executor& get_executor() const BOOST_ASIO_NOEXCEPT + template + void dispatch(Function& function, Handler& handler) { - return executor_; + executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function), + boost::asio::get_associated_allocator(handler)); } private: @@ -177,9 +246,11 @@ public: return !!executor_; } - const Executor& get_executor() const BOOST_ASIO_NOEXCEPT + template + void dispatch(Function& function, Handler& handler) { - return executor_; + executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function), + boost::asio::get_associated_allocator(handler)); } private: @@ -214,15 +285,10 @@ public: } else { - handler_work_base::get_executor().dispatch( - BOOST_ASIO_MOVE_CAST(Function)(function), - boost::asio::get_associated_allocator(handler)); + handler_work_base::dispatch(function, handler); } } - -private: - // Disallow assignment. - handler_work& operator=(const handler_work&); }; } // namespace detail diff --git a/include/boost/asio/detail/io_object_impl.hpp b/include/boost/asio/detail/io_object_impl.hpp index 06287709..54a622d6 100644 --- a/include/boost/asio/detail/io_object_impl.hpp +++ b/include/boost/asio/detail/io_object_impl.hpp @@ -18,7 +18,10 @@ #include #include #include +#include +#include #include +#include #include @@ -42,7 +45,8 @@ public: // Construct an I/O object using an executor. explicit io_object_impl(const executor_type& ex) - : service_(&boost::asio::use_service(ex.context())), + : service_(&boost::asio::use_service( + io_object_impl::get_context(ex))), executor_(ex) { service_->construct(implementation_); @@ -72,7 +76,7 @@ public: template io_object_impl(io_object_impl&& other) : service_(&boost::asio::use_service( - other.get_executor().context())), + io_object_impl::get_context(other.get_executor()))), executor_(other.get_executor()) { service_->converting_move_construct(implementation_, @@ -134,6 +138,22 @@ public: } private: + // Helper function to get an executor's context. + template + static execution_context& get_context(const T& t, + typename enable_if::value>::type* = 0) + { + return boost::asio::query(t, execution::context); + } + + // Helper function to get an executor's context. + template + static execution_context& get_context(const T& t, + typename enable_if::value>::type* = 0) + { + return t.context(); + } + // Disallow copying and copy assignment. io_object_impl(const io_object_impl&); io_object_impl& operator=(const io_object_impl&); diff --git a/include/boost/asio/windows/overlapped_ptr.hpp b/include/boost/asio/windows/overlapped_ptr.hpp index f8e6407e..4dd487c6 100644 --- a/include/boost/asio/windows/overlapped_ptr.hpp +++ b/include/boost/asio/windows/overlapped_ptr.hpp @@ -65,7 +65,8 @@ public: explicit overlapped_ptr(const Executor& ex, BOOST_ASIO_MOVE_ARG(Handler) handler, typename enable_if< - is_executor::value + execution::is_executor::value + || is_executor::value >::type* = 0) : impl_(ex, BOOST_ASIO_MOVE_CAST(Handler)(handler)) { @@ -98,7 +99,8 @@ public: template void reset(const Executor& ex, BOOST_ASIO_MOVE_ARG(Handler) handler, typename enable_if< - is_executor::value + execution::is_executor::value + || is_executor::value >::type* = 0) { impl_.reset(ex, BOOST_ASIO_MOVE_CAST(Handler)(handler)); From 3fc1f87a2bf523a77fb341cae5e42d0011d33520 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:17:08 +1000 Subject: [PATCH 69/90] Add standard executor support to strand<>. --- .../detail/impl/strand_executor_service.hpp | 214 +++++++++++++++++- .../asio/detail/strand_executor_service.hpp | 26 ++- include/boost/asio/strand.hpp | 195 +++++++++++++++- test/strand.cpp | 213 +++++++++++++++++ 4 files changed, 636 insertions(+), 12 deletions(-) diff --git a/include/boost/asio/detail/impl/strand_executor_service.hpp b/include/boost/asio/detail/impl/strand_executor_service.hpp index a3ba5f20..2cf557fc 100644 --- a/include/boost/asio/detail/impl/strand_executor_service.hpp +++ b/include/boost/asio/detail/impl/strand_executor_service.hpp @@ -20,6 +20,9 @@ #include #include #include +#include +#include +#include #include @@ -27,8 +30,137 @@ namespace boost { namespace asio { namespace detail { +template +class strand_executor_service::allocator_binder +{ +public: + typedef Allocator allocator_type; + + allocator_binder(BOOST_ASIO_MOVE_ARG(F) f, const Allocator& a) + : f_(BOOST_ASIO_MOVE_CAST(F)(f)), + allocator_(a) + { + } + + allocator_binder(const allocator_binder& other) + : f_(other.f_), + allocator_(other.allocator_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + allocator_binder(allocator_binder&& other) + : f_(BOOST_ASIO_MOVE_CAST(F)(other.f_)), + allocator_(BOOST_ASIO_MOVE_CAST(allocator_type)(other.allocator_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } + + void operator()() + { + f_(); + } + +private: + F f_; + allocator_type allocator_; +}; + template -class strand_executor_service::invoker +class strand_executor_service::invoker::value + >::type> +{ +public: + invoker(const implementation_type& impl, Executor& ex) + : impl_(impl), + executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + invoker(const invoker& other) + : impl_(other.impl_), + executor_(other.executor_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + invoker(invoker&& other) + : impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)), + executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + struct on_invoker_exit + { + invoker* this_; + + ~on_invoker_exit() + { + this_->impl_->mutex_->lock(); + this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_); + bool more_handlers = this_->impl_->locked_ = + !this_->impl_->ready_queue_.empty(); + this_->impl_->mutex_->unlock(); + + if (more_handlers) + { + recycling_allocator allocator; + execution::execute( + boost::asio::prefer( + boost::asio::require(this_->executor_, + execution::blocking.never), + execution::allocator(allocator)), + BOOST_ASIO_MOVE_CAST(invoker)(*this_)); + } + } + }; + + void operator()() + { + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl_.get()); + + // Ensure the next handler, if any, is scheduled on block exit. + on_invoker_exit on_exit = { this }; + (void)on_exit; + + // Run all ready handlers. No lock is required since the ready queue is + // accessed only within the strand. + boost::system::error_code ec; + while (scheduler_operation* o = impl_->ready_queue_.front()) + { + impl_->ready_queue_.pop(); + o->complete(impl_.get(), ec, 0); + } + } + +private: + typedef typename decay< + typename prefer_result_type< + Executor, + execution::outstanding_work_t::tracked_t + >::type + >::type executor_type; + + implementation_type impl_; + executor_type executor_; +}; + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) + +template +class strand_executor_service::invoker::value + >::type> { public: invoker(const implementation_type& impl, Executor& ex) @@ -96,6 +228,68 @@ private: executor_work_guard work_; }; +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) + +template +inline void strand_executor_service::execute(const implementation_type& impl, + Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, + typename enable_if< + can_query >::value + >::type*) +{ + return strand_executor_service::execute(impl, ex, + BOOST_ASIO_MOVE_CAST(Function)(function), + boost::asio::query(ex, execution::allocator)); +} + +template +inline void strand_executor_service::execute(const implementation_type& impl, + Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, + typename enable_if< + !can_query >::value + >::type*) +{ + return strand_executor_service::execute(impl, ex, + BOOST_ASIO_MOVE_CAST(Function)(function), + std::allocator()); +} + +template +void strand_executor_service::execute(const implementation_type& impl, + Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay::type function_type; + + // If the executor is not never-blocking, and we are already in the strand, + // then the function can run immediately. + if (boost::asio::query(ex, execution::blocking) != execution::blocking.never + && call_stack::contains(impl.get())) + { + // Make a local, non-const copy of the function. + function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(function)); + + fenced_block b(fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a); + + BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "execute")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + { + execution::execute(ex, invoker(impl, ex)); + } +} + template void strand_executor_service::dispatch(const implementation_type& impl, Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) @@ -125,7 +319,11 @@ void strand_executor_service::dispatch(const implementation_type& impl, bool first = enqueue(impl, p.p); p.v = p.p = 0; if (first) - ex.dispatch(invoker(impl, ex), a); + { + boost::asio::dispatch(ex, + allocator_binder, Allocator>( + invoker(impl, ex), a)); + } } // Request invocation of the given function and return immediately. @@ -147,7 +345,11 @@ void strand_executor_service::post(const implementation_type& impl, bool first = enqueue(impl, p.p); p.v = p.p = 0; if (first) - ex.post(invoker(impl, ex), a); + { + boost::asio::post(ex, + allocator_binder, Allocator>( + invoker(impl, ex), a)); + } } // Request invocation of the given function and return immediately. @@ -169,7 +371,11 @@ void strand_executor_service::defer(const implementation_type& impl, bool first = enqueue(impl, p.p); p.v = p.p = 0; if (first) - ex.defer(invoker(impl, ex), a); + { + boost::asio::defer(ex, + allocator_binder, Allocator>( + invoker(impl, ex), a)); + } } } // namespace detail diff --git a/include/boost/asio/detail/strand_executor_service.hpp b/include/boost/asio/detail/strand_executor_service.hpp index d710927b..0feabeb2 100644 --- a/include/boost/asio/detail/strand_executor_service.hpp +++ b/include/boost/asio/detail/strand_executor_service.hpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -86,6 +88,27 @@ public: // Create a new strand_executor implementation. BOOST_ASIO_DECL implementation_type create_implementation(); + // Request invocation of the given function. + template + static void execute(const implementation_type& impl, Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, + typename enable_if< + can_query >::value + >::type* = 0); + + // Request invocation of the given function. + template + static void execute(const implementation_type& impl, Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, + typename enable_if< + !can_query >::value + >::type* = 0); + + // Request invocation of the given function. + template + static void execute(const implementation_type& impl, Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a); + // Request invocation of the given function. template static void dispatch(const implementation_type& impl, Executor& ex, @@ -107,7 +130,8 @@ public: private: friend class strand_impl; - template class invoker; + template class allocator_binder; + template class invoker; // Adds a function to the strand. Returns true if it acquires the lock. BOOST_ASIO_DECL static bool enqueue(const implementation_type& impl, diff --git a/include/boost/asio/strand.hpp b/include/boost/asio/strand.hpp index 6f4c5370..c2b9ed8b 100644 --- a/include/boost/asio/strand.hpp +++ b/include/boost/asio/strand.hpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include @@ -39,16 +41,14 @@ public: */ strand() : executor_(), - impl_(use_service( - executor_.context()).create_implementation()) + impl_(strand::create_implementation(executor_)) { } /// Construct a strand for the specified executor. explicit strand(const Executor& e) : executor_(e), - impl_(use_service( - executor_.context()).create_implementation()) + impl_(strand::create_implementation(executor_)) { } @@ -147,6 +147,51 @@ public: return executor_; } + /// Forward a query to the underlying executor. + template + typename enable_if< + can_query::value, + typename query_result_type::type + >::type query(const Property& p) const + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_query::value)) + { + return boost::asio::query(executor_, p); + } + + /// Forward a requirement to the underlying executor. + template + typename enable_if< + can_require::value, + strand::type + >::type> + >::type require(const Property& p) const + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_require::value)) + { + return strand::type + >::type>(boost::asio::require(executor_, p), impl_); + } + + /// Forward a preference to the underlying executor. + template + typename enable_if< + can_prefer::value, + strand::type + >::type> + >::type prefer(const Property& p) const + BOOST_ASIO_NOEXCEPT_IF(( + is_nothrow_prefer::value)) + { + return strand::type + >::type>(boost::asio::prefer(executor_, p), impl_); + } + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Obtain the underlying execution context. execution_context& context() const BOOST_ASIO_NOEXCEPT { @@ -170,7 +215,28 @@ public: { executor_.on_work_finished(); } +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the strand to execute the given function + * object on its underlying executor. The function object will be executed + * according to the properties of the underlying executor. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + */ + template + typename enable_if< + execution::can_execute::value + >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const + { + detail::strand_executor_service::execute(impl_, + executor_, BOOST_ASIO_MOVE_CAST(Function)(f)); + } + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Request the strand to invoke the given function object. /** * This function is used to ask the strand to execute the given function @@ -232,6 +298,7 @@ public: detail::strand_executor_service::defer(impl_, executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a); } +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Determine whether the strand is running in the current thread. /** @@ -267,9 +334,36 @@ public: #if defined(GENERATING_DOCUMENTATION) private: #endif // defined(GENERATING_DOCUMENTATION) - Executor executor_; typedef detail::strand_executor_service::implementation_type implementation_type; + + template + static implementation_type create_implementation(const InnerExecutor& ex, + typename enable_if< + can_query::value + >::type* = 0) + { + return use_service( + boost::asio::query(ex, execution::context)).create_implementation(); + } + + template + static implementation_type create_implementation(const InnerExecutor& ex, + typename enable_if< + !can_query::value + >::type* = 0) + { + return use_service( + ex.context()).create_implementation(); + } + + strand(const Executor& ex, const implementation_type& impl) + : executor_(ex), + impl_(impl) + { + } + + Executor executor_; implementation_type impl_; }; @@ -283,7 +377,9 @@ private: /// Create a @ref strand object for an executor. template inline strand make_strand(const Executor& ex, - typename enable_if::value>::type* = 0) + typename enable_if< + is_executor::value || execution::is_executor::value + >::type* = 0) { return strand(ex); } @@ -293,13 +389,98 @@ template inline strand make_strand(ExecutionContext& ctx, typename enable_if< - is_convertible::value>::type* = 0) + is_convertible::value + >::type* = 0) { return strand(ctx.get_executor()); } /*@}*/ +#if !defined(GENERATING_DOCUMENTATION) + +namespace execution { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct is_executor > : true_type +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +} // namespace execution +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member, Function> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +template +struct query_member, Property, + typename enable_if< + can_query::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_query::value)); + typedef typename query_result_type::type result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member, Property, + typename enable_if< + can_require::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_require::value)); + typedef strand::type + >::type> result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +template +struct prefer_member, Property, + typename enable_if< + can_prefer::value + >::type> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = + (is_nothrow_prefer::value)); + typedef strand::type + >::type> result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) + +} // namespace traits + +#endif // !defined(GENERATING_DOCUMENTATION) + } // namespace asio } // namespace boost diff --git a/test/strand.cpp b/test/strand.cpp index 66e97b90..4bfc9b2b 100644 --- a/test/strand.cpp +++ b/test/strand.cpp @@ -255,9 +255,222 @@ void strand_conversion_test() s3 = strand(s1); } +void strand_query_test() +{ + io_context ioc; + strand s1 = make_strand(ioc); + + BOOST_ASIO_CHECK( + &boost::asio::query(s1, boost::asio::execution::context) + == &ioc); + + BOOST_ASIO_CHECK( + boost::asio::query(s1, boost::asio::execution::blocking) + == boost::asio::execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(s1, boost::asio::execution::blocking.possibly) + == boost::asio::execution::blocking.possibly); + + BOOST_ASIO_CHECK( + boost::asio::query(s1, boost::asio::execution::outstanding_work) + == boost::asio::execution::outstanding_work.untracked); + + BOOST_ASIO_CHECK( + boost::asio::query(s1, boost::asio::execution::outstanding_work.untracked) + == boost::asio::execution::outstanding_work.untracked); + + BOOST_ASIO_CHECK( + boost::asio::query(s1, boost::asio::execution::relationship) + == boost::asio::execution::relationship.fork); + + BOOST_ASIO_CHECK( + boost::asio::query(s1, boost::asio::execution::relationship.fork) + == boost::asio::execution::relationship.fork); + + BOOST_ASIO_CHECK( + boost::asio::query(s1, boost::asio::execution::mapping) + == boost::asio::execution::mapping.thread); + + BOOST_ASIO_CHECK( + boost::asio::query(s1, boost::asio::execution::allocator) + == std::allocator()); +} + +void strand_execute_test() +{ + io_context ioc; + strand s1 = make_strand(ioc); + int count = 0; + + boost::asio::execution::execute(s1, bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::require(s1, boost::asio::execution::blocking.possibly), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::require(s1, boost::asio::execution::blocking.never), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + BOOST_ASIO_CHECK(!ioc.stopped()); + + boost::asio::execution::execute( + boost::asio::require(s1, + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.tracked), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::require(s1, + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::require(s1, + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.fork), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::require(s1, + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::prefer( + boost::asio::require(s1, + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + boost::asio::execution::allocator(std::allocator())), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::execution::execute( + boost::asio::prefer( + boost::asio::require(s1, + boost::asio::execution::blocking.never, + boost::asio::execution::outstanding_work.untracked, + boost::asio::execution::relationship.continuation), + boost::asio::execution::allocator), + bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); +} + BOOST_ASIO_TEST_SUITE ( "strand", BOOST_ASIO_TEST_CASE(strand_test) BOOST_ASIO_COMPILE_TEST_CASE(strand_conversion_test) + BOOST_ASIO_TEST_CASE(strand_query_test) + BOOST_ASIO_TEST_CASE(strand_execute_test) ) From 75c405d249cb3de6ee8e5754ab31bcc4d4972256 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:21:12 +1000 Subject: [PATCH 70/90] Add standard executor support to get_associated_executor. --- include/boost/asio/associated_executor.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/boost/asio/associated_executor.hpp b/include/boost/asio/associated_executor.hpp index 18544969..6c9d2c1a 100644 --- a/include/boost/asio/associated_executor.hpp +++ b/include/boost/asio/associated_executor.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -114,8 +115,9 @@ get_associated_executor(const T& t) BOOST_ASIO_NOEXCEPT template inline typename associated_executor::type get_associated_executor(const T& t, const Executor& ex, - typename enable_if::value>::type* = 0) BOOST_ASIO_NOEXCEPT + typename enable_if< + is_executor::value || execution::is_executor::value + >::type* = 0) BOOST_ASIO_NOEXCEPT { return associated_executor::get(t, ex); } From 20d2c5e806f32c993277eec46c4c20f65a435348 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:21:29 +1000 Subject: [PATCH 71/90] Add standard executor support to bind_executor. --- include/boost/asio/bind_executor.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/boost/asio/bind_executor.hpp b/include/boost/asio/bind_executor.hpp index 3a78ee17..89662438 100644 --- a/include/boost/asio/bind_executor.hpp +++ b/include/boost/asio/bind_executor.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -494,7 +495,9 @@ private: template inline executor_binder::type, Executor> bind_executor(const Executor& ex, BOOST_ASIO_MOVE_ARG(T) t, - typename enable_if::value>::type* = 0) + typename enable_if< + is_executor::value || execution::is_executor::value + >::type* = 0) { return executor_binder::type, Executor>( executor_arg_t(), ex, BOOST_ASIO_MOVE_CAST(T)(t)); From e3d6bcfac9da68e95a801389c9a7ad62ea338792 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:21:40 +1000 Subject: [PATCH 72/90] Add standard executor support to async_compose. --- include/boost/asio/impl/compose.hpp | 55 ++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/include/boost/asio/impl/compose.hpp b/include/boost/asio/impl/compose.hpp index 048ad310..a5288314 100644 --- a/include/boost/asio/impl/compose.hpp +++ b/include/boost/asio/impl/compose.hpp @@ -16,11 +16,14 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -32,6 +35,50 @@ namespace asio { namespace detail { + template + class composed_work_guard + { + public: + typedef typename decay< + typename prefer_result_type::type + >::type executor_type; + + composed_work_guard(const Executor& ex) + : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + void reset() + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_; + } + + private: + executor_type executor_; + }; + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) + + template + struct composed_work_guard::value + >::type> : executor_work_guard + { + composed_work_guard(const Executor& ex) + : executor_work_guard(ex) + { + } + }; + +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) + template struct composed_io_executors; @@ -159,7 +206,7 @@ namespace detail } typedef system_executor head_type; - executor_work_guard head_; + composed_work_guard head_; }; template @@ -178,7 +225,7 @@ namespace detail } typedef Head head_type; - executor_work_guard head_; + composed_work_guard head_; }; #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) @@ -201,7 +248,7 @@ namespace detail } typedef Head head_type; - executor_work_guard head_; + composed_work_guard head_; composed_work tail_; }; @@ -227,7 +274,7 @@ namespace detail } \ \ typedef Head head_type; \ - executor_work_guard head_; \ + composed_work_guard head_; \ composed_work tail_; \ }; \ /**/ From 0d9bbf613c75053c18736c3ba7b6c65f113f000d Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:21:55 +1000 Subject: [PATCH 73/90] Add standard executor support to co_spawn. --- include/boost/asio/co_spawn.hpp | 7 ++-- include/boost/asio/impl/co_spawn.hpp | 61 ++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/include/boost/asio/co_spawn.hpp b/include/boost/asio/co_spawn.hpp index b1923e59..a0553421 100644 --- a/include/boost/asio/co_spawn.hpp +++ b/include/boost/asio/co_spawn.hpp @@ -20,6 +20,7 @@ #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #include +#include #include #include @@ -106,7 +107,7 @@ co_spawn(const Executor& ex, awaitable a, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if< - is_executor::value + (is_executor::value || execution::is_executor::value) && is_convertible::value >::type* = 0); @@ -162,7 +163,7 @@ co_spawn(const Executor& ex, awaitable a, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if< - is_executor::value + (is_executor::value || execution::is_executor::value) && is_convertible::value >::type* = 0); @@ -372,7 +373,7 @@ co_spawn(const Executor& ex, F&& f, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if< - is_executor::value + is_executor::value || execution::is_executor::value >::type* = 0); /// Spawn a new coroutined-based thread of execution. diff --git a/include/boost/asio/impl/co_spawn.hpp b/include/boost/asio/impl/co_spawn.hpp index df5e0dc0..a2f95779 100644 --- a/include/boost/asio/impl/co_spawn.hpp +++ b/include/boost/asio/impl/co_spawn.hpp @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include #include #include @@ -27,12 +29,56 @@ namespace boost { namespace asio { namespace detail { +template +class co_spawn_work_guard +{ +public: + typedef typename decay< + typename prefer_result_type::type + >::type executor_type; + + co_spawn_work_guard(const Executor& ex) + : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_; + } + +private: + executor_type executor_; +}; + +template +struct co_spawn_work_guard::value + >::type> : executor_work_guard +{ + co_spawn_work_guard(const Executor& ex) + : executor_work_guard(ex) + { + } +}; + +template +inline co_spawn_work_guard +make_co_spawn_work_guard(const Executor& ex) +{ + return co_spawn_work_guard(ex); +} + template awaitable co_spawn_entry_point( awaitable*, Executor ex, F f, Handler handler) { - auto spawn_work = make_work_guard(ex); - auto handler_work = make_work_guard(handler, ex); + auto spawn_work = make_co_spawn_work_guard(ex); + auto handler_work = make_co_spawn_work_guard( + boost::asio::get_associated_executor(handler, ex)); (void) co_await (post)(spawn_work.get_executor(), use_awaitable_t{}); @@ -67,8 +113,9 @@ template awaitable co_spawn_entry_point( awaitable*, Executor ex, F f, Handler handler) { - auto spawn_work = make_work_guard(ex); - auto handler_work = make_work_guard(handler, ex); + auto spawn_work = make_co_spawn_work_guard(ex); + auto handler_work = make_co_spawn_work_guard( + boost::asio::get_associated_executor(handler, ex)); (void) co_await (post)(spawn_work.get_executor(), use_awaitable_t{__FILE__, __LINE__, "co_spawn_entry_point"}); @@ -149,7 +196,7 @@ inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( co_spawn(const Executor& ex, awaitable a, CompletionToken&& token, typename enable_if< - is_executor::value + (is_executor::value || execution::is_executor::value) && is_convertible::value >::type*) { @@ -166,7 +213,7 @@ inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( co_spawn(const Executor& ex, awaitable a, CompletionToken&& token, typename enable_if< - is_executor::value + (is_executor::value || execution::is_executor::value) && is_convertible::value >::type*) { @@ -217,7 +264,7 @@ inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, typename detail::awaitable_signature::type>::type) co_spawn(const Executor& ex, F&& f, CompletionToken&& token, typename enable_if< - is_executor::value + is_executor::value || execution::is_executor::value >::type*) { return async_initiate Date: Mon, 22 Jun 2020 23:22:08 +1000 Subject: [PATCH 74/90] Add standard executor support to use_future. --- include/boost/asio/impl/use_future.hpp | 144 ++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 5 deletions(-) diff --git a/include/boost/asio/impl/use_future.hpp b/include/boost/asio/impl/use_future.hpp index d4474482..73326766 100644 --- a/include/boost/asio/impl/use_future.hpp +++ b/include/boost/asio/impl/use_future.hpp @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -201,7 +203,7 @@ private: // An executor that adapts the system_executor to capture any exeption thrown // by a submitted function object and save it into a promise. -template +template class promise_executor { public: @@ -210,6 +212,32 @@ public: { } + static BOOST_ASIO_CONSTEXPR Blocking query(execution::blocking_t) + { + return Blocking(); + } + + promise_executor + require(execution::blocking_t::possibly_t) const + { + return promise_executor(p_); + } + + promise_executor + require(execution::blocking_t::never_t) const + { + return promise_executor(p_); + } + + template + void execute(BOOST_ASIO_MOVE_ARG(F) f) const + { + execution::execute( + boost::asio::require(system_executor(), Blocking()), + promise_invoker(p_, BOOST_ASIO_MOVE_CAST(F)(f))); + } + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) execution_context& context() const BOOST_ASIO_NOEXCEPT { return system_executor().context(); @@ -237,6 +265,7 @@ public: system_executor().defer( promise_invoker(p_, BOOST_ASIO_MOVE_CAST(F)(f)), a); } +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) friend bool operator==(const promise_executor& a, const promise_executor& b) BOOST_ASIO_NOEXCEPT @@ -608,6 +637,27 @@ private: Allocator allocator_; }; +template +struct promise_function_wrapper +{ + explicit promise_function_wrapper(Function& f) + : function_(BOOST_ASIO_MOVE_CAST(Function)(f)) + { + } + + explicit promise_function_wrapper(const Function& f) + : function_(f) + { + } + + void operator()() + { + function_(); + } + + Function function_; +}; + #if !defined(BOOST_ASIO_NO_DEPRECATED) template @@ -616,7 +666,7 @@ inline void asio_handler_invoke(Function& f, { typename promise_handler::executor_type ex(h->get_executor()); - ex.dispatch(BOOST_ASIO_MOVE_CAST(Function)(f), std::allocator()); + boost::asio::dispatch(ex, promise_function_wrapper(f)); } template @@ -625,7 +675,7 @@ inline void asio_handler_invoke(const Function& f, { typename promise_handler::executor_type ex(h->get_executor()); - ex.dispatch(f, std::allocator()); + boost::asio::dispatch(ex, promise_function_wrapper(f)); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) @@ -733,7 +783,7 @@ inline void asio_handler_invoke(Function& f, { typename packaged_handler::executor_type ex(h->get_executor()); - ex.dispatch(BOOST_ASIO_MOVE_CAST(Function)(f), std::allocator()); + boost::asio::dispatch(ex, promise_function_wrapper(f)); } template ::executor_type ex(h->get_executor()); - ex.dispatch(f, std::allocator()); + boost::asio::dispatch(ex, promise_function_wrapper(f)); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) @@ -887,6 +937,90 @@ public: #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +namespace execution { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +template +struct is_executor< + boost::asio::detail::promise_executor > : true_type +{ +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT) + +} // namespace execution +namespace traits { + +#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +template +struct execute_member< + boost::asio::detail::promise_executor, Function> +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); + typedef void result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_TRAIT) + +template +struct query_static_constexpr_member< + boost::asio::detail::promise_executor, + Property, + typename boost::asio::enable_if< + boost::asio::is_convertible< + Property, + boost::asio::execution::blocking_t + >::value + >::type + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef Blocking result_type; + + static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT + { + return Blocking(); + } +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_TRAIT) + +#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +template +struct require_member< + boost::asio::detail::promise_executor, + execution::blocking_t::possibly_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::detail::promise_executor result_type; +}; + +template +struct require_member< + boost::asio::detail::promise_executor, + execution::blocking_t::never_t + > +{ + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); + BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); + typedef boost::asio::detail::promise_executor result_type; +}; + +#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) + +} // namespace traits + #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio From 166e773815da78689c7653d4bbb33542674ac922 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:22:18 +1000 Subject: [PATCH 75/90] Add standard executor support to executor_work_guard. --- include/boost/asio/executor_work_guard.hpp | 130 +++++++++++++++++++-- include/boost/asio/ts/netfwd.hpp | 7 +- 2 files changed, 127 insertions(+), 10 deletions(-) diff --git a/include/boost/asio/executor_work_guard.hpp b/include/boost/asio/executor_work_guard.hpp index 18f64e02..3c3ef19c 100644 --- a/include/boost/asio/executor_work_guard.hpp +++ b/include/boost/asio/executor_work_guard.hpp @@ -1,6 +1,6 @@ // // executor_work_guard.hpp -// ~~~~~~~~~~~~~~~~~ +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -25,9 +26,21 @@ namespace boost { namespace asio { +#if !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL) +#define BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL + +template +class executor_work_guard; + +#endif // !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL) + /// An object of type @c executor_work_guard controls ownership of executor work /// within a scope. +#if defined(GENERATING_DOCUMENTATION) template +#else // defined(GENERATING_DOCUMENTATION) +template +#endif // defined(GENERATING_DOCUMENTATION) class executor_work_guard { public: @@ -109,10 +122,102 @@ private: bool owns_; }; +#if !defined(GENERATING_DOCUMENTATION) + +template +class executor_work_guard::value && execution::is_executor::value + >::type> +{ +public: + typedef Executor executor_type; + + explicit executor_work_guard(const executor_type& e) BOOST_ASIO_NOEXCEPT + : executor_(e), + owns_(true) + { + new (&work_) work_type(boost::asio::prefer(executor_, + execution::outstanding_work.tracked)); + } + + executor_work_guard(const executor_work_guard& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_), + owns_(other.owns_) + { + if (owns_) + { + new (&work_) work_type(boost::asio::prefer(executor_, + execution::outstanding_work.tracked)); + } + } + +#if defined(BOOST_ASIO_HAS_MOVE) + executor_work_guard(executor_work_guard&& other) BOOST_ASIO_NOEXCEPT + : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), + owns_(other.owns_) + { + if (owns_) + { + new (&work_) work_type( + BOOST_ASIO_MOVE_CAST(work_type)( + *static_cast( + static_cast(&other.work_)))); + other.owns_ = false; + } + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + ~executor_work_guard() + { + if (owns_) + static_cast(static_cast(&work_))->~work_type(); + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_; + } + + bool owns_work() const BOOST_ASIO_NOEXCEPT + { + return owns_; + } + + void reset() BOOST_ASIO_NOEXCEPT + { + if (owns_) + { + static_cast(static_cast(&work_))->~work_type(); + owns_ = false; + } + } + +private: + // Disallow assignment. + executor_work_guard& operator=(const executor_work_guard&); + + typedef typename decay< + typename prefer_result_type< + const executor_type&, + execution::outstanding_work_t::tracked_t + >::type + >::type work_type; + + executor_type executor_; + typename aligned_storage::value>::type work_; + bool owns_; +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + /// Create an @ref executor_work_guard object. template inline executor_work_guard make_work_guard(const Executor& ex, - typename enable_if::value>::type* = 0) + typename enable_if< + is_executor::value || execution::is_executor::value + >::type* = 0) { return executor_work_guard(ex); } @@ -122,7 +227,8 @@ template inline executor_work_guard make_work_guard(ExecutionContext& ctx, typename enable_if< - is_convertible::value>::type* = 0) + is_convertible::value + >::type* = 0) { return executor_work_guard( ctx.get_executor()); @@ -132,8 +238,10 @@ make_work_guard(ExecutionContext& ctx, template inline executor_work_guard::type> make_work_guard(const T& t, - typename enable_if::value && - !is_convertible::value>::type* = 0) + typename enable_if< + !is_executor::value && !execution::is_executor::value + && !is_convertible::value>::type* = 0) { return executor_work_guard::type>( associated_executor::get(t)); @@ -143,7 +251,9 @@ make_work_guard(const T& t, template inline executor_work_guard::type> make_work_guard(const T& t, const Executor& ex, - typename enable_if::value>::type* = 0) + typename enable_if< + is_executor::value || execution::is_executor::value + >::type* = 0) { return executor_work_guard::type>( associated_executor::get(t, ex)); @@ -154,9 +264,11 @@ template inline executor_work_guard::type> make_work_guard(const T& t, ExecutionContext& ctx, - typename enable_if::value && - !is_convertible::value && - is_convertible::value>::type* = 0) + typename enable_if< + !is_executor::value && !execution::is_executor::value + && !is_convertible::value + && is_convertible::value + >::type* = 0) { return executor_work_guard::type>( diff --git a/include/boost/asio/ts/netfwd.hpp b/include/boost/asio/ts/netfwd.hpp index cdc0f536..625e70e0 100644 --- a/include/boost/asio/ts/netfwd.hpp +++ b/include/boost/asio/ts/netfwd.hpp @@ -37,9 +37,14 @@ class execution_context; template class executor_binder; -template +#if !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL) +#define BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL + +template class executor_work_guard; +#endif // !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL) + template class basic_system_executor; From 50ab1cb65228a8a6ca8491069dfee8d2518872e8 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:22:30 +1000 Subject: [PATCH 76/90] Add standard executor support to spawn. --- include/boost/asio/impl/spawn.hpp | 8 ++++++-- include/boost/asio/spawn.hpp | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/boost/asio/impl/spawn.hpp b/include/boost/asio/impl/spawn.hpp index 59e1a237..1c5706e7 100644 --- a/include/boost/asio/impl/spawn.hpp +++ b/include/boost/asio/impl/spawn.hpp @@ -420,7 +420,9 @@ template void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes, - typename enable_if::type>::value && + typename enable_if< + !is_executor::type>::value && + !execution::is_executor::type>::value && !is_convertible::value>::type*) { typedef typename decay::type handler_type; @@ -471,7 +473,9 @@ template inline void spawn(const Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes, - typename enable_if::value>::type*) + typename enable_if< + is_executor::value || execution::is_executor::value + >::type*) { boost::asio::spawn(boost::asio::strand(ex), BOOST_ASIO_MOVE_CAST(Function)(function), attributes); diff --git a/include/boost/asio/spawn.hpp b/include/boost/asio/spawn.hpp index 21cb3cfc..0e18dd8c 100644 --- a/include/boost/asio/spawn.hpp +++ b/include/boost/asio/spawn.hpp @@ -226,7 +226,9 @@ void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes(), - typename enable_if::type>::value && + typename enable_if< + !is_executor::type>::value && + !execution::is_executor::type>::value && !is_convertible::value>::type* = 0); /// Start a new stackful coroutine, inheriting the execution context of another. @@ -267,7 +269,9 @@ void spawn(const Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes(), - typename enable_if::value>::type* = 0); + typename enable_if< + is_executor::value || execution::is_executor::value + >::type* = 0); /// Start a new stackful coroutine that executes on a given strand. /** From 9557f87ae40f10e3ede05670c6d30b999cc91158 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:22:46 +1000 Subject: [PATCH 77/90] Increase emulated variadic template support to 8 parameters. --- .../boost/asio/detail/variadic_templates.hpp | 102 +++++++++++++++++- include/boost/asio/impl/compose.hpp | 27 +++++ 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/include/boost/asio/detail/variadic_templates.hpp b/include/boost/asio/detail/variadic_templates.hpp index 790ece07..4408a816 100644 --- a/include/boost/asio/detail/variadic_templates.hpp +++ b/include/boost/asio/detail/variadic_templates.hpp @@ -31,6 +31,15 @@ typename T1, typename T2, typename T3, typename T4 # define BOOST_ASIO_VARIADIC_TPARAMS_5 \ typename T1, typename T2, typename T3, typename T4, typename T5 +# define BOOST_ASIO_VARIADIC_TPARAMS_6 \ + typename T1, typename T2, typename T3, typename T4, typename T5, \ + typename T6 +# define BOOST_ASIO_VARIADIC_TPARAMS_7 \ + typename T1, typename T2, typename T3, typename T4, typename T5, \ + typename T6, typename T7 +# define BOOST_ASIO_VARIADIC_TPARAMS_8 \ + typename T1, typename T2, typename T3, typename T4, typename T5, \ + typename T6, typename T7, typename T8 # define BOOST_ASIO_VARIADIC_TARGS(n) BOOST_ASIO_VARIADIC_TARGS_##n @@ -39,6 +48,9 @@ # define BOOST_ASIO_VARIADIC_TARGS_3 T1, T2, T3 # define BOOST_ASIO_VARIADIC_TARGS_4 T1, T2, T3, T4 # define BOOST_ASIO_VARIADIC_TARGS_5 T1, T2, T3, T4, T5 +# define BOOST_ASIO_VARIADIC_TARGS_6 T1, T2, T3, T4, T5, T6 +# define BOOST_ASIO_VARIADIC_TARGS_7 T1, T2, T3, T4, T5, T6, T7 +# define BOOST_ASIO_VARIADIC_TARGS_8 T1, T2, T3, T4, T5, T6, T7, T8 # define BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n) \ BOOST_ASIO_VARIADIC_BYVAL_PARAMS_##n @@ -48,6 +60,12 @@ # define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_3 T1 x1, T2 x2, T3 x3 # define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4 # define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_6 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \ + T6 x6 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_7 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \ + T6 x6, T7 x7 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_8 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \ + T6 x6, T7 x7, T8 x8 # define BOOST_ASIO_VARIADIC_BYVAL_ARGS(n) \ BOOST_ASIO_VARIADIC_BYVAL_ARGS_##n @@ -57,6 +75,9 @@ # define BOOST_ASIO_VARIADIC_BYVAL_ARGS_3 x1, x2, x3 # define BOOST_ASIO_VARIADIC_BYVAL_ARGS_4 x1, x2, x3, x4 # define BOOST_ASIO_VARIADIC_BYVAL_ARGS_5 x1, x2, x3, x4, x5 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_6 x1, x2, x3, x4, x5, x6 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_7 x1, x2, x3, x4, x5, x6, x7 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_8 x1, x2, x3, x4, x5, x6, x7, x8 # define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n) \ BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_##n @@ -71,6 +92,15 @@ const T1& x1, const T2& x2, const T3& x3, const T4& x4 # define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_5 \ const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5 +# define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_6 \ + const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \ + const T6& x6 +# define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_7 \ + const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \ + const T6& x6, const T7& x7 +# define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_8 \ + const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \ + const T6& x6, const T7& x7, const T8& x8 # define BOOST_ASIO_VARIADIC_MOVE_PARAMS(n) \ BOOST_ASIO_VARIADIC_MOVE_PARAMS_##n @@ -89,6 +119,20 @@ BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \ BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4, \ BOOST_ASIO_MOVE_ARG(T5) x5 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_6 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \ + BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4, \ + BOOST_ASIO_MOVE_ARG(T5) x5, BOOST_ASIO_MOVE_ARG(T6) x6 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_7 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \ + BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4, \ + BOOST_ASIO_MOVE_ARG(T5) x5, BOOST_ASIO_MOVE_ARG(T6) x6, \ + BOOST_ASIO_MOVE_ARG(T7) x7 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_8 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \ + BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4, \ + BOOST_ASIO_MOVE_ARG(T5) x5, BOOST_ASIO_MOVE_ARG(T6) x6, \ + BOOST_ASIO_MOVE_ARG(T7) x7, BOOST_ASIO_MOVE_ARG(T8) x8 # define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n) \ BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_##n @@ -107,6 +151,20 @@ BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4), \ BOOST_ASIO_MOVE_ARG(T5) +# define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_6 \ + BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ + BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4), \ + BOOST_ASIO_MOVE_ARG(T5), BOOST_ASIO_MOVE_ARG(T6) +# define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_7 \ + BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ + BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4), \ + BOOST_ASIO_MOVE_ARG(T5), BOOST_ASIO_MOVE_ARG(T6), \ + BOOST_ASIO_MOVE_ARG(T7) +# define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_8 \ + BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ + BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4), \ + BOOST_ASIO_MOVE_ARG(T5), BOOST_ASIO_MOVE_ARG(T6), \ + BOOST_ASIO_MOVE_ARG(T7), BOOST_ASIO_MOVE_ARG(T8) # define BOOST_ASIO_VARIADIC_MOVE_ARGS(n) \ BOOST_ASIO_VARIADIC_MOVE_ARGS_##n @@ -125,6 +183,20 @@ BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \ BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4), \ BOOST_ASIO_MOVE_CAST(T5)(x5) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_6 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \ + BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4), \ + BOOST_ASIO_MOVE_CAST(T5)(x5), BOOST_ASIO_MOVE_CAST(T6)(x6) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_7 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \ + BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4), \ + BOOST_ASIO_MOVE_CAST(T5)(x5), BOOST_ASIO_MOVE_CAST(T6)(x6), \ + BOOST_ASIO_MOVE_CAST(T7)(x7) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_8 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \ + BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4), \ + BOOST_ASIO_MOVE_CAST(T5)(x5), BOOST_ASIO_MOVE_CAST(T6)(x6), \ + BOOST_ASIO_MOVE_CAST(T7)(x7), BOOST_ASIO_MOVE_CAST(T8)(x8) # define BOOST_ASIO_VARIADIC_MOVE_DECLVAL(n) \ BOOST_ASIO_VARIADIC_MOVE_DECLVAL_##n @@ -143,6 +215,20 @@ declval(), declval(), \ declval(), declval(), \ declval() +# define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_6 \ + declval(), declval(), \ + declval(), declval(), \ + declval(), declval() +# define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_7 \ + declval(), declval(), \ + declval(), declval(), \ + declval(), declval(), \ + declval() +# define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_8 \ + declval(), declval(), \ + declval(), declval(), \ + declval(), declval(), \ + declval(), declval() # define BOOST_ASIO_VARIADIC_DECAY(n) \ BOOST_ASIO_VARIADIC_DECAY_##n @@ -161,8 +247,22 @@ typename decay::type, typename decay::type, \ typename decay::type, typename decay::type, \ typename decay::type +# define BOOST_ASIO_VARIADIC_DECAY_6 \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type +# define BOOST_ASIO_VARIADIC_DECAY_7 \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type +# define BOOST_ASIO_VARIADIC_DECAY_8 \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type -# define BOOST_ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5) +# define BOOST_ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) #endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) diff --git a/include/boost/asio/impl/compose.hpp b/include/boost/asio/impl/compose.hpp index a5288314..62ae2a9d 100644 --- a/include/boost/asio/impl/compose.hpp +++ b/include/boost/asio/impl/compose.hpp @@ -564,6 +564,30 @@ async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T3)(x3)), \ detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T4)(x4)), \ detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T5)(x5)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_6 \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T1)(x1)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T2)(x2)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T3)(x3)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T4)(x4)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T5)(x5)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T6)(x6)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_7 \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T1)(x1)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T2)(x2)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T3)(x3)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T4)(x4)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T5)(x5)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T6)(x6)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T7)(x7)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_8 \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T1)(x1)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T2)(x2)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T3)(x3)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T4)(x4)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T5)(x5)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T6)(x6)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T7)(x7)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T8)(x8)) #define BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \ template Date: Mon, 22 Jun 2020 23:22:59 +1000 Subject: [PATCH 78/90] Use an any_executor<> as the polymorphic executor for I/O objects. The asio::any_io_executor type alias has been added as the default runtime-polymorphic executor for all I/O objects. This type alias points to the execution::any_executor<> template with a set of supportable properties specified for use with I/O. If required for backward compatibility, BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT can be defined. This changes the asio::any_io_executor type alias to point to the Networking TS-based runtime-polymorphic asio::executor class instead. --- include/boost/asio/any_io_executor.hpp | 73 +++++++++++++++++++ include/boost/asio/awaitable.hpp | 4 +- include/boost/asio/basic_datagram_socket.hpp | 2 +- include/boost/asio/basic_deadline_timer.hpp | 4 +- include/boost/asio/basic_raw_socket.hpp | 2 +- .../boost/asio/basic_seq_packet_socket.hpp | 2 +- include/boost/asio/basic_serial_port.hpp | 4 +- include/boost/asio/basic_signal_set.hpp | 4 +- include/boost/asio/basic_socket.hpp | 4 +- include/boost/asio/basic_socket_acceptor.hpp | 4 +- include/boost/asio/basic_stream_socket.hpp | 2 +- include/boost/asio/basic_waitable_timer.hpp | 4 +- include/boost/asio/ip/basic_resolver.hpp | 4 +- include/boost/asio/posix/basic_descriptor.hpp | 4 +- .../asio/posix/basic_stream_descriptor.hpp | 2 +- include/boost/asio/spawn.hpp | 4 +- include/boost/asio/ts/netfwd.hpp | 45 +++++++++++- include/boost/asio/use_awaitable.hpp | 2 +- .../asio/windows/basic_object_handle.hpp | 4 +- .../asio/windows/basic_overlapped_handle.hpp | 4 +- .../windows/basic_random_access_handle.hpp | 2 +- .../asio/windows/basic_stream_handle.hpp | 2 +- 22 files changed, 148 insertions(+), 34 deletions(-) create mode 100644 include/boost/asio/any_io_executor.hpp diff --git a/include/boost/asio/any_io_executor.hpp b/include/boost/asio/any_io_executor.hpp new file mode 100644 index 00000000..1be8fb6c --- /dev/null +++ b/include/boost/asio/any_io_executor.hpp @@ -0,0 +1,73 @@ +// +// any_io_executor.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_ANY_IO_EXECUTOR_HPP +#define BOOST_ASIO_ANY_IO_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include +#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +# include +# include +#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#include + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +typedef executor any_io_executor; + +#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +/// Polymorphic executor type for use with I/O objects. +/** + * The @c any_io_executor type is a polymorphic executor that supports the set + * of properties required by I/O objects. It is defined as the + * execution::any_executor class template parameterised as follows: + * @code execution::any_executor< + * execution::context_as_t, + * execution::blocking_t::never_t, + * execution::prefer_only, + * execution::prefer_only, + * execution::prefer_only, + * execution::prefer_only, + * execution::prefer_only + * > @endcode + */ +#if defined(GENERATING_DOCUMENTATION) +typedef execution::any_executor<...> any_io_executor; +#else // defined(GENERATING_DOCUMENTATION) +typedef execution::any_executor< + execution::context_as_t, + execution::blocking_t::never_t, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + > any_io_executor; +#endif // defined(GENERATING_DOCUMENTATION) + +#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_ANY_IO_EXECUTOR_HPP diff --git a/include/boost/asio/awaitable.hpp b/include/boost/asio/awaitable.hpp index 9578bc42..55fbe4cb 100644 --- a/include/boost/asio/awaitable.hpp +++ b/include/boost/asio/awaitable.hpp @@ -25,7 +25,7 @@ # include #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) -#include +#include #include @@ -47,7 +47,7 @@ template class awaitable_frame; } // namespace detail /// The return type of a coroutine or asynchronous operation. -template +template class awaitable { public: diff --git a/include/boost/asio/basic_datagram_socket.hpp b/include/boost/asio/basic_datagram_socket.hpp index b436fc9e..98a6dd63 100644 --- a/include/boost/asio/basic_datagram_socket.hpp +++ b/include/boost/asio/basic_datagram_socket.hpp @@ -33,7 +33,7 @@ namespace asio { #define BOOST_ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL // Forward declaration with defaulted arguments. -template +template class basic_datagram_socket; #endif // !defined(BOOST_ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) diff --git a/include/boost/asio/basic_deadline_timer.hpp b/include/boost/asio/basic_deadline_timer.hpp index 0a0f5b19..33730364 100644 --- a/include/boost/asio/basic_deadline_timer.hpp +++ b/include/boost/asio/basic_deadline_timer.hpp @@ -21,6 +21,7 @@ || defined(GENERATING_DOCUMENTATION) #include +#include #include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include #include @@ -126,7 +126,7 @@ namespace asio { */ template , - typename Executor = executor> + typename Executor = any_io_executor> class basic_deadline_timer { public: diff --git a/include/boost/asio/basic_raw_socket.hpp b/include/boost/asio/basic_raw_socket.hpp index d86fabd1..7f620620 100644 --- a/include/boost/asio/basic_raw_socket.hpp +++ b/include/boost/asio/basic_raw_socket.hpp @@ -33,7 +33,7 @@ namespace asio { #define BOOST_ASIO_BASIC_RAW_SOCKET_FWD_DECL // Forward declaration with defaulted arguments. -template +template class basic_raw_socket; #endif // !defined(BOOST_ASIO_BASIC_RAW_SOCKET_FWD_DECL) diff --git a/include/boost/asio/basic_seq_packet_socket.hpp b/include/boost/asio/basic_seq_packet_socket.hpp index cc005b0b..97fb5617 100644 --- a/include/boost/asio/basic_seq_packet_socket.hpp +++ b/include/boost/asio/basic_seq_packet_socket.hpp @@ -31,7 +31,7 @@ namespace asio { #define BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL // Forward declaration with defaulted arguments. -template +template class basic_seq_packet_socket; #endif // !defined(BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL) diff --git a/include/boost/asio/basic_serial_port.hpp b/include/boost/asio/basic_serial_port.hpp index 7163c37a..3fd33706 100644 --- a/include/boost/asio/basic_serial_port.hpp +++ b/include/boost/asio/basic_serial_port.hpp @@ -22,6 +22,7 @@ || defined(GENERATING_DOCUMENTATION) #include +#include #include #include #include @@ -30,7 +31,6 @@ #include #include #include -#include #include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -56,7 +56,7 @@ namespace asio { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template +template class basic_serial_port : public serial_port_base { diff --git a/include/boost/asio/basic_signal_set.hpp b/include/boost/asio/basic_signal_set.hpp index 8584b243..194d29a9 100644 --- a/include/boost/asio/basic_signal_set.hpp +++ b/include/boost/asio/basic_signal_set.hpp @@ -17,6 +17,7 @@ #include +#include #include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include namespace boost { namespace asio { @@ -91,7 +91,7 @@ namespace asio { * that any signals registered using signal_set objects are unblocked in at * least one thread. */ -template +template class basic_signal_set { public: diff --git a/include/boost/asio/basic_socket.hpp b/include/boost/asio/basic_socket.hpp index 4a00c404..1a349e49 100644 --- a/include/boost/asio/basic_socket.hpp +++ b/include/boost/asio/basic_socket.hpp @@ -15,6 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include #include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include #include @@ -49,7 +49,7 @@ namespace asio { #define BOOST_ASIO_BASIC_SOCKET_FWD_DECL // Forward declaration with defaulted arguments. -template +template class basic_socket; #endif // !defined(BOOST_ASIO_BASIC_SOCKET_FWD_DECL) diff --git a/include/boost/asio/basic_socket_acceptor.hpp b/include/boost/asio/basic_socket_acceptor.hpp index c55e3aaa..e3894aaf 100644 --- a/include/boost/asio/basic_socket_acceptor.hpp +++ b/include/boost/asio/basic_socket_acceptor.hpp @@ -16,6 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include #if defined(BOOST_ASIO_WINDOWS_RUNTIME) @@ -48,7 +48,7 @@ namespace asio { #define BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL // Forward declaration with defaulted arguments. -template +template class basic_socket_acceptor; #endif // !defined(BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) diff --git a/include/boost/asio/basic_stream_socket.hpp b/include/boost/asio/basic_stream_socket.hpp index 0afa3abb..91934e16 100644 --- a/include/boost/asio/basic_stream_socket.hpp +++ b/include/boost/asio/basic_stream_socket.hpp @@ -33,7 +33,7 @@ namespace asio { #define BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL // Forward declaration with defaulted arguments. -template +template class basic_stream_socket; #endif // !defined(BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL) diff --git a/include/boost/asio/basic_waitable_timer.hpp b/include/boost/asio/basic_waitable_timer.hpp index 86273745..2bab2192 100644 --- a/include/boost/asio/basic_waitable_timer.hpp +++ b/include/boost/asio/basic_waitable_timer.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include #if defined(BOOST_ASIO_HAS_MOVE) @@ -42,7 +42,7 @@ namespace asio { // Forward declaration with defaulted arguments. template , - typename Executor = executor> + typename Executor = any_io_executor> class basic_waitable_timer; #endif // !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) diff --git a/include/boost/asio/ip/basic_resolver.hpp b/include/boost/asio/ip/basic_resolver.hpp index 48fae095..ce0f9985 100644 --- a/include/boost/asio/ip/basic_resolver.hpp +++ b/include/boost/asio/ip/basic_resolver.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -25,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -50,7 +50,7 @@ namespace ip { #define BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL // Forward declaration with defaulted arguments. -template +template class basic_resolver; #endif // !defined(BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL) diff --git a/include/boost/asio/posix/basic_descriptor.hpp b/include/boost/asio/posix/basic_descriptor.hpp index 83faf3b3..ad71f90a 100644 --- a/include/boost/asio/posix/basic_descriptor.hpp +++ b/include/boost/asio/posix/basic_descriptor.hpp @@ -20,6 +20,7 @@ #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) +#include #include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include #if defined(BOOST_ASIO_HAS_MOVE) @@ -50,7 +50,7 @@ namespace posix { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template +template class basic_descriptor : public descriptor_base { diff --git a/include/boost/asio/posix/basic_stream_descriptor.hpp b/include/boost/asio/posix/basic_stream_descriptor.hpp index 7c375df7..cdce1c5d 100644 --- a/include/boost/asio/posix/basic_stream_descriptor.hpp +++ b/include/boost/asio/posix/basic_stream_descriptor.hpp @@ -37,7 +37,7 @@ namespace posix { * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ -template +template class basic_stream_descriptor : public basic_descriptor { diff --git a/include/boost/asio/spawn.hpp b/include/boost/asio/spawn.hpp index 0e18dd8c..a3064373 100644 --- a/include/boost/asio/spawn.hpp +++ b/include/boost/asio/spawn.hpp @@ -17,11 +17,11 @@ #include #include +#include #include #include #include #include -#include #include #include #include @@ -152,7 +152,7 @@ private: typedef basic_yield_context yield_context; #else // defined(GENERATING_DOCUMENTATION) typedef basic_yield_context< - executor_binder > yield_context; + executor_binder > yield_context; #endif // defined(GENERATING_DOCUMENTATION) /** diff --git a/include/boost/asio/ts/netfwd.hpp b/include/boost/asio/ts/netfwd.hpp index 625e70e0..309f9e33 100644 --- a/include/boost/asio/ts/netfwd.hpp +++ b/include/boost/asio/ts/netfwd.hpp @@ -48,8 +48,12 @@ class executor_work_guard; template class basic_system_executor; +#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + class executor; +#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + template class strand; @@ -65,6 +69,8 @@ struct time_traits; #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + #if !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) #define BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL @@ -75,8 +81,6 @@ class basic_waitable_timer; #endif // !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) -#if defined(BOOST_ASIO_HAS_CHRONO) - typedef basic_waitable_timer system_timer; typedef basic_waitable_timer steady_timer; @@ -84,8 +88,19 @@ typedef basic_waitable_timer steady_timer; typedef basic_waitable_timer high_resolution_timer; +#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +template +class basic_waitable_timer; + +#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +#if defined(BOOST_ASIO_HAS_CHRONO) + #endif // defined(BOOST_ASIO_HAS_CHRONO) +#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + #if !defined(BOOST_ASIO_BASIC_SOCKET_FWD_DECL) #define BOOST_ASIO_BASIC_SOCKET_FWD_DECL @@ -119,6 +134,23 @@ class basic_socket_acceptor; #endif // !defined(BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) +#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +template +class basic_socket; + +template +class basic_datagram_socket; + +// Forward declaration with defaulted arguments. +template +class basic_stream_socket; + +template +class basic_socket_acceptor; + +#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + #if !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) #define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL @@ -188,6 +220,8 @@ class basic_resolver_entry; template class basic_resolver_results; +#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + #if !defined(BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL) #define BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL @@ -196,6 +230,13 @@ class basic_resolver; #endif // !defined(BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL) +#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +template +class basic_resolver; + +#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + class tcp; class udp; diff --git a/include/boost/asio/use_awaitable.hpp b/include/boost/asio/use_awaitable.hpp index a522f74f..724f42b2 100644 --- a/include/boost/asio/use_awaitable.hpp +++ b/include/boost/asio/use_awaitable.hpp @@ -50,7 +50,7 @@ namespace asio { * the asynchronous operation completes, and the result of the operation is * returned. */ -template +template struct use_awaitable_t { /// Default constructor. diff --git a/include/boost/asio/windows/basic_object_handle.hpp b/include/boost/asio/windows/basic_object_handle.hpp index f03d1fb3..6c3d9309 100644 --- a/include/boost/asio/windows/basic_object_handle.hpp +++ b/include/boost/asio/windows/basic_object_handle.hpp @@ -21,13 +21,13 @@ #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include #include #include #include #include #include #include -#include #if defined(BOOST_ASIO_HAS_MOVE) # include @@ -48,7 +48,7 @@ namespace windows { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template +template class basic_object_handle { public: diff --git a/include/boost/asio/windows/basic_overlapped_handle.hpp b/include/boost/asio/windows/basic_overlapped_handle.hpp index 78d27aae..928c4855 100644 --- a/include/boost/asio/windows/basic_overlapped_handle.hpp +++ b/include/boost/asio/windows/basic_overlapped_handle.hpp @@ -22,13 +22,13 @@ || defined(GENERATING_DOCUMENTATION) #include +#include #include #include #include #include #include #include -#include #if defined(BOOST_ASIO_HAS_MOVE) # include @@ -51,7 +51,7 @@ namespace windows { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template +template class basic_overlapped_handle { public: diff --git a/include/boost/asio/windows/basic_random_access_handle.hpp b/include/boost/asio/windows/basic_random_access_handle.hpp index 1677d50e..2afa0bdd 100644 --- a/include/boost/asio/windows/basic_random_access_handle.hpp +++ b/include/boost/asio/windows/basic_random_access_handle.hpp @@ -36,7 +36,7 @@ namespace windows { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template +template class basic_random_access_handle : public basic_overlapped_handle { diff --git a/include/boost/asio/windows/basic_stream_handle.hpp b/include/boost/asio/windows/basic_stream_handle.hpp index 32ac165e..9ed81a62 100644 --- a/include/boost/asio/windows/basic_stream_handle.hpp +++ b/include/boost/asio/windows/basic_stream_handle.hpp @@ -39,7 +39,7 @@ namespace windows { * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ -template +template class basic_stream_handle : public basic_overlapped_handle { From fefe9a992e9b7fddf0a1f86e8b35d1ff686cc307 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:24:33 +1000 Subject: [PATCH 79/90] Use properties to track outstanding work against an io_context. When using standard executors, work is tracked by requiring (or preferring) an executor with the execution::outstanding_work.tracked property. This replaces executor_work_guard and make_work_guard() with code of the form asio::io_context io_context; auto work = asio::require(io_context.get_executor(), asio::execution::outstanding_work.tracked); To explicitly reset work, store the returned work-tracking executor in an any_io_executor object: asio::any_io_executor work = asio::require(io_context.get_executor(), asio::execution::outstanding_work.tracked); and then assign an empty executor into the object when done: work = asio::any_io_executor(); --- .../cpp03/http/server2/io_context_pool.cpp | 3 +- .../cpp03/http/server2/io_context_pool.hpp | 6 ++-- example/cpp03/services/logger_service.hpp | 14 ++++---- example/cpp11/futures/daytime_client.cpp | 3 +- example/cpp11/operations/composed_6.cpp | 10 +++--- example/cpp14/operations/composed_6.cpp | 10 +++--- include/boost/asio/io_context.hpp | 36 ++++++++++++++----- 7 files changed, 51 insertions(+), 31 deletions(-) diff --git a/example/cpp03/http/server2/io_context_pool.cpp b/example/cpp03/http/server2/io_context_pool.cpp index 427c2260..ef63bcc6 100644 --- a/example/cpp03/http/server2/io_context_pool.cpp +++ b/example/cpp03/http/server2/io_context_pool.cpp @@ -29,7 +29,8 @@ io_context_pool::io_context_pool(std::size_t pool_size) { io_context_ptr io_context(new boost::asio::io_context); io_contexts_.push_back(io_context); - work_.push_back(boost::asio::make_work_guard(*io_context)); + work_.push_back(boost::asio::require(io_context->get_executor(), + boost::asio::execution::outstanding_work.tracked)); } } diff --git a/example/cpp03/http/server2/io_context_pool.hpp b/example/cpp03/http/server2/io_context_pool.hpp index 86bd5b45..6a046730 100644 --- a/example/cpp03/http/server2/io_context_pool.hpp +++ b/example/cpp03/http/server2/io_context_pool.hpp @@ -39,14 +39,12 @@ public: private: typedef boost::shared_ptr io_context_ptr; - typedef boost::asio::executor_work_guard< - boost::asio::io_context::executor_type> io_context_work; /// The pool of io_contexts. std::vector io_contexts_; - /// The work that keeps the io_contexts running. - std::list work_; + /// The work-tracking executors that keep the io_contexts running. + std::list work_; /// The next io_context to use for a connection. std::size_t next_io_context_; diff --git a/example/cpp03/services/logger_service.hpp b/example/cpp03/services/logger_service.hpp index 4f439c5e..4db34efc 100644 --- a/example/cpp03/services/logger_service.hpp +++ b/example/cpp03/services/logger_service.hpp @@ -45,7 +45,8 @@ public: logger_service(boost::asio::execution_context& context) : boost::asio::execution_context::service(context), work_io_context_(), - work_(boost::asio::make_work_guard(work_io_context_)), + work_(boost::asio::require(work_io_context_.get_executor(), + boost::asio::execution::outstanding_work.tracked)), work_thread_(new boost::thread( boost::bind(&boost::asio::io_context::run, &work_io_context_))) { @@ -56,7 +57,7 @@ public: { /// Indicate that we have finished with the private io_context. Its /// io_context::run() function will exit once all other work has completed. - work_.reset(); + work_ = boost::asio::any_io_executor(); if (work_thread_) work_thread_->join(); } @@ -128,11 +129,10 @@ private: /// Private io_context used for performing logging operations. boost::asio::io_context work_io_context_; - /// Work for the private io_context to perform. If we do not give the - /// io_context some work to do then the io_context::run() function will exit - /// immediately. - boost::asio::executor_work_guard< - boost::asio::io_context::executor_type> work_; + /// A work-tracking executor giving work for the private io_context to + /// perform. If we do not give the io_context some work to do then the + /// io_context::run() function will exit immediately. + boost::asio::any_io_executor work_; /// Thread used for running the work io_context's run loop. boost::scoped_ptr work_thread_; diff --git a/example/cpp11/futures/daytime_client.cpp b/example/cpp11/futures/daytime_client.cpp index 7f787ed0..282993e6 100644 --- a/example/cpp11/futures/daytime_client.cpp +++ b/example/cpp11/futures/daytime_client.cpp @@ -77,7 +77,8 @@ int main(int argc, char* argv[]) // We run the io_context off in its own thread so that it operates // completely asynchronously with respect to the rest of the program. boost::asio::io_context io_context; - auto work = boost::asio::make_work_guard(io_context); + auto work = boost::asio::require(io_context.get_executor(), + boost::asio::execution::outstanding_work.tracked); std::thread thread([&io_context](){ io_context.run(); }); get_daytime(io_context, argv[1]); diff --git a/example/cpp11/operations/composed_6.cpp b/example/cpp11/operations/composed_6.cpp index d3a51fc7..ec126cdf 100644 --- a/example/cpp11/operations/composed_6.cpp +++ b/example/cpp11/operations/composed_6.cpp @@ -97,7 +97,9 @@ struct async_write_message_initiation // As our composed operation performs multiple underlying I/O operations, // we should maintain a work object against the I/O executor. This tells // the I/O executor that there is still more work to come in the future. - boost::asio::executor_work_guard io_work_; + typename std::decay(), + boost::asio::execution::outstanding_work.tracked))>::type io_work_; // The user-supplied completion handler, called once only on completion // of the entire composed operation. @@ -134,9 +136,6 @@ struct async_write_message_initiation // This point is reached only on completion of the entire composed // operation. - // We no longer have any future work coming for the I/O executor. - io_work_.reset(); - // Deallocate the encoded message before calling the user-supplied // completion handler. encoded_message_.reset(); @@ -187,7 +186,8 @@ struct async_write_message_initiation socket, std::move(encoded_message), repeat_count, std::move(delay_timer), intermediate_completion_handler::starting, - boost::asio::make_work_guard(socket.get_executor()), + boost::asio::prefer(socket.get_executor(), + boost::asio::execution::outstanding_work.tracked), std::forward(completion_handler)}); } }; diff --git a/example/cpp14/operations/composed_6.cpp b/example/cpp14/operations/composed_6.cpp index 8b6d0119..cdfb71a8 100644 --- a/example/cpp14/operations/composed_6.cpp +++ b/example/cpp14/operations/composed_6.cpp @@ -108,7 +108,9 @@ auto async_write_messages(tcp::socket& socket, // As our composed operation performs multiple underlying I/O operations, // we should maintain a work object against the I/O executor. This tells // the I/O executor that there is still more work to come in the future. - boost::asio::executor_work_guard io_work_; + typename std::decay(), + boost::asio::execution::outstanding_work.tracked))>::type io_work_; // The user-supplied completion handler, called once only on completion // of the entire composed operation. @@ -145,9 +147,6 @@ auto async_write_messages(tcp::socket& socket, // This point is reached only on completion of the entire composed // operation. - // We no longer have any future work coming for the I/O executor. - io_work_.reset(); - // Deallocate the encoded message before calling the user-supplied // completion handler. encoded_message_.reset(); @@ -198,7 +197,8 @@ auto async_write_messages(tcp::socket& socket, socket, std::move(encoded_message), repeat_count, std::move(delay_timer), intermediate_completion_handler::starting, - boost::asio::make_work_guard(socket.get_executor()), + boost::asio::prefer(socket.get_executor(), + boost::asio::execution::outstanding_work.tracked), std::forward(completion_handler)}); }; diff --git a/include/boost/asio/io_context.hpp b/include/boost/asio/io_context.hpp index 621f3dfe..ffa34068 100644 --- a/include/boost/asio/io_context.hpp +++ b/include/boost/asio/io_context.hpp @@ -161,12 +161,30 @@ namespace detail { * returning when there is no more work to do. For example, the io_context may * be being run in a background thread that is launched prior to the * application's asynchronous operations. The run() call may be kept running by - * creating an object of type - * boost::asio::executor_work_guard: + * creating an executor that tracks work against the io_context: * * @code boost::asio::io_context io_context; - * boost::asio::executor_work_guard - * = boost::asio::make_work_guard(io_context); + * auto work = boost::asio::require(io_context.get_executor(), + * boost::asio::execution::outstanding_work.tracked); + * ... @endcode + * + * If using C++03, which lacks automatic variable type deduction, you may + * compute the return type of the require call: + * + * @code boost::asio::io_context io_context; + * typename boost::asio::require_result_type< + * boost::asio::io_context::executor_type, + * boost::asio::exeution::outstanding_work_t::tracked_t> + * work = boost::asio::require(io_context.get_executor(), + * boost::asio::execution::outstanding_work.tracked); + * ... @endcode + * + * or store the result in the type-erasing executor wrapper, any_io_executor: + * + * @code boost::asio::io_context io_context; + * boost::asio::any_io_executor work + * = boost::asio::require(io_context.get_executor(), + * boost::asio::execution::outstanding_work.tracked); * ... @endcode * * To effect a shutdown, the application will then need to call the io_context @@ -175,13 +193,15 @@ namespace detail { * permitting ready handlers to be dispatched. * * Alternatively, if the application requires that all operations and handlers - * be allowed to finish normally, the work object may be explicitly reset. + * be allowed to finish normally, store the work-tracking executor in an + * any_io_executor object, so that it may be explicitly reset. * * @code boost::asio::io_context io_context; - * boost::asio::executor_work_guard - * = boost::asio::make_work_guard(io_context); + * boost::asio::any_io_executor work + * = boost::asio::require(io_context.get_executor(), + * boost::asio::execution::outstanding_work.tracked); * ... - * work.reset(); // Allow run() to exit. @endcode + * work = boost::asio::any_io_executor(); // Allow run() to exit. @endcode */ class io_context : public execution_context From e4877fe03dd0fc344a2d386985fa157d2f984d24 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:25:08 +1000 Subject: [PATCH 80/90] Use properties to obtain an executor's execution context. Rather than using a context() member function, query the executor's execution::context_t property to obtain its associated execution context: asio::execution_context& context = asio::query(my_io_executor, asio::execution::context); --- example/cpp03/services/basic_logger.hpp | 6 ------ example/cpp03/services/daytime_client.cpp | 8 ++++++-- example/cpp03/timeouts/blocking_token_tcp_client.cpp | 3 ++- example/cpp11/timeouts/blocking_token_tcp_client.cpp | 3 ++- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/example/cpp03/services/basic_logger.hpp b/example/cpp03/services/basic_logger.hpp index d7cc4257..bf865f2e 100644 --- a/example/cpp03/services/basic_logger.hpp +++ b/example/cpp03/services/basic_logger.hpp @@ -52,12 +52,6 @@ public: service_.destroy(impl_); } - /// Get the io_context associated with the object. - boost::asio::io_context& get_io_context() - { - return service_.get_io_context(); - } - /// Set the output file for all logger instances. void use_file(const std::string& file) { diff --git a/example/cpp03/services/daytime_client.cpp b/example/cpp03/services/daytime_client.cpp index 59a0a626..f792d57c 100644 --- a/example/cpp03/services/daytime_client.cpp +++ b/example/cpp03/services/daytime_client.cpp @@ -30,7 +30,9 @@ void read_handler(const boost::system::error_code& e, } else { - services::logger logger(s->get_executor().context(), "read_handler"); + boost::asio::execution_context& context = boost::asio::query( + s->get_executor(), boost::asio::execution::context); + services::logger logger(context, "read_handler"); std::string msg = "Read error: "; msg += e.message(); @@ -40,7 +42,9 @@ void read_handler(const boost::system::error_code& e, void connect_handler(const boost::system::error_code& e, tcp::socket* s) { - services::logger logger(s->get_executor().context(), "connect_handler"); + boost::asio::execution_context& context = boost::asio::query( + s->get_executor(), boost::asio::execution::context); + services::logger logger(context, "connect_handler"); if (!e) { diff --git a/example/cpp03/timeouts/blocking_token_tcp_client.cpp b/example/cpp03/timeouts/blocking_token_tcp_client.cpp index effb491c..d415bbfa 100644 --- a/example/cpp03/timeouts/blocking_token_tcp_client.cpp +++ b/example/cpp03/timeouts/blocking_token_tcp_client.cpp @@ -98,7 +98,8 @@ public: // use this function to run the io_context until the operation is complete. return_type get() { - boost::asio::io_context& io_context = socket_.get_executor().context(); + boost::asio::io_context& io_context = boost::asio::query( + socket_.get_executor(), boost::asio::execution::context); // Restart the io_context, as it may have been left in the "stopped" state // by a previous operation. diff --git a/example/cpp11/timeouts/blocking_token_tcp_client.cpp b/example/cpp11/timeouts/blocking_token_tcp_client.cpp index 031275f7..592d03e8 100644 --- a/example/cpp11/timeouts/blocking_token_tcp_client.cpp +++ b/example/cpp11/timeouts/blocking_token_tcp_client.cpp @@ -98,7 +98,8 @@ public: // use this function to run the io_context until the operation is complete. return_type get() { - boost::asio::io_context& io_context = socket_.get_executor().context(); + boost::asio::io_context& io_context = boost::asio::query( + socket_.get_executor(), boost::asio::execution::context); // Restart the io_context, as it may have been left in the "stopped" state // by a previous operation. From 307690de7fb8ba4d12b08be208e109c2f179141f Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:25:30 +1000 Subject: [PATCH 81/90] Disable asio::executor if BOOST_ASIO_NO_TS_EXECUTORS is defined. --- example/cpp03/nonblocking/third_party_lib.cpp | 4 ++-- example/cpp11/executors/actor.cpp | 12 ++++++------ example/cpp14/executors/actor.cpp | 16 ++++++++++------ include/boost/asio/executor.hpp | 5 +++++ include/boost/asio/impl/executor.hpp | 5 +++++ include/boost/asio/impl/executor.ipp | 5 +++++ 6 files changed, 33 insertions(+), 14 deletions(-) diff --git a/example/cpp03/nonblocking/third_party_lib.cpp b/example/cpp03/nonblocking/third_party_lib.cpp index 86b11c6d..30de7dbc 100644 --- a/example/cpp03/nonblocking/third_party_lib.cpp +++ b/example/cpp03/nonblocking/third_party_lib.cpp @@ -83,7 +83,7 @@ class connection public: typedef boost::shared_ptr pointer; - static pointer create(const boost::asio::executor& ex) + static pointer create(const boost::asio::any_io_executor& ex) { return pointer(new connection(ex)); } @@ -102,7 +102,7 @@ public: } private: - connection(const boost::asio::executor& ex) + connection(const boost::asio::any_io_executor& ex) : socket_(ex), session_impl_(socket_), read_in_progress_(false), diff --git a/example/cpp11/executors/actor.cpp b/example/cpp11/executors/actor.cpp index 2e3311d4..81dc0584 100644 --- a/example/cpp11/executors/actor.cpp +++ b/example/cpp11/executors/actor.cpp @@ -1,5 +1,5 @@ +#include #include -#include #include #include #include @@ -10,8 +10,8 @@ #include #include +using boost::asio::any_io_executor; using boost::asio::defer; -using boost::asio::executor; using boost::asio::post; using boost::asio::strand; using boost::asio::system_executor; @@ -106,7 +106,7 @@ public: protected: // Construct the actor to use the specified executor for all message handlers. - actor(executor e) + actor(any_io_executor e) : executor_(std::move(e)) { } @@ -124,7 +124,7 @@ protected: template void deregister_handler(void (Actor::* mf)(Message, actor_address)) { - const std::type_info& id = typeid(message_handler); + const std::type_info& id = typeid(Message); for (auto iter = handlers_.begin(); iter != handlers_.end(); ++iter) { if ((*iter)->message_id() == id) @@ -171,7 +171,7 @@ private: // All messages associated with a single actor object should be processed // non-concurrently. We use a strand to ensure non-concurrent execution even // if the underlying executor may use multiple threads. - strand executor_; + strand executor_; std::vector> handlers_; }; @@ -221,7 +221,7 @@ using boost::asio::thread_pool; class member : public actor { public: - explicit member(executor e) + explicit member(any_io_executor e) : actor(std::move(e)) { register_handler(&member::init_handler); diff --git a/example/cpp14/executors/actor.cpp b/example/cpp14/executors/actor.cpp index 7046e7ba..92056996 100644 --- a/example/cpp14/executors/actor.cpp +++ b/example/cpp14/executors/actor.cpp @@ -1,4 +1,8 @@ -#include +#include +#include +#include +#include +#include #include #include #include @@ -6,8 +10,8 @@ #include #include +using boost::asio::any_io_executor; using boost::asio::defer; -using boost::asio::executor; using boost::asio::post; using boost::asio::strand; using boost::asio::system_executor; @@ -94,7 +98,7 @@ public: { // Execute the message handler in the context of the target's executor. post(to->executor_, - [=, msg=std::move(msg)] + [=, msg=std::move(msg)]() mutable { to->call_handler(std::move(msg), from); }); @@ -102,7 +106,7 @@ public: protected: // Construct the actor to use the specified executor for all message handlers. - actor(executor e) + actor(any_io_executor e) : executor_(std::move(e)) { } @@ -166,7 +170,7 @@ private: // All messages associated with a single actor object should be processed // non-concurrently. We use a strand to ensure non-concurrent execution even // if the underlying executor may use multiple threads. - strand executor_; + strand executor_; std::vector> handlers_; }; @@ -216,7 +220,7 @@ using boost::asio::thread_pool; class member : public actor { public: - explicit member(executor e) + explicit member(any_io_executor e) : actor(std::move(e)) { register_handler(&member::init_handler); diff --git a/include/boost/asio/executor.hpp b/include/boost/asio/executor.hpp index d3c8268c..4f259cef 100644 --- a/include/boost/asio/executor.hpp +++ b/include/boost/asio/executor.hpp @@ -16,6 +16,9 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) + #include #include #include @@ -341,4 +344,6 @@ BOOST_ASIO_USES_ALLOCATOR(boost::asio::executor) # include #endif // defined(BOOST_ASIO_HEADER_ONLY) +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) + #endif // BOOST_ASIO_EXECUTOR_HPP diff --git a/include/boost/asio/impl/executor.hpp b/include/boost/asio/impl/executor.hpp index 7a3a097d..261ca263 100644 --- a/include/boost/asio/impl/executor.hpp +++ b/include/boost/asio/impl/executor.hpp @@ -16,6 +16,9 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) + #include #include #include @@ -295,4 +298,6 @@ const Executor* executor::target() const BOOST_ASIO_NOEXCEPT #include +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) + #endif // BOOST_ASIO_IMPL_EXECUTOR_HPP diff --git a/include/boost/asio/impl/executor.ipp b/include/boost/asio/impl/executor.ipp index 7b02ef2e..340578d6 100644 --- a/include/boost/asio/impl/executor.ipp +++ b/include/boost/asio/impl/executor.ipp @@ -16,6 +16,9 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) + #include #include @@ -37,4 +40,6 @@ const char* bad_executor::what() const BOOST_ASIO_NOEXCEPT_OR_NOTHROW #include +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) + #endif // BOOST_ASIO_IMPL_EXECUTOR_IPP From bb547e1a4468228bf3f903519a9b90f5e65ec1ca Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:26:01 +1000 Subject: [PATCH 82/90] Disable io_context::strand if BOOST_ASIO_NO_TS_EXECUTORS is defined. --- include/boost/asio/io_context.hpp | 4 +++- include/boost/asio/io_context_strand.hpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/boost/asio/io_context.hpp b/include/boost/asio/io_context.hpp index ffa34068..5719014a 100644 --- a/include/boost/asio/io_context.hpp +++ b/include/boost/asio/io_context.hpp @@ -229,9 +229,11 @@ public: class service; -#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_EXTENSIONS) \ + && !defined(BOOST_ASIO_NO_TS_EXECUTORS) class strand; #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + // && !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// The type used to count the number of handlers executed by the context. typedef std::size_t count_type; diff --git a/include/boost/asio/io_context_strand.hpp b/include/boost/asio/io_context_strand.hpp index b1725b44..5480919f 100644 --- a/include/boost/asio/io_context_strand.hpp +++ b/include/boost/asio/io_context_strand.hpp @@ -17,7 +17,8 @@ #include -#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_EXTENSIONS) \ + && !defined(BOOST_ASIO_NO_TS_EXECUTORS) #include #include @@ -372,5 +373,6 @@ private: #include #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + // && !defined(BOOST_ASIO_NO_TS_EXECUTORS) #endif // BOOST_ASIO_IO_CONTEXT_STRAND_HPP From 242b3ee482f029d565eacd5eaa42c889b31a3d2b Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:26:23 +1000 Subject: [PATCH 83/90] Disable executor_work_guard if BOOST_ASIO_NO_TS_EXECUTORS is defined. --- include/boost/asio/executor_work_guard.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/boost/asio/executor_work_guard.hpp b/include/boost/asio/executor_work_guard.hpp index 3c3ef19c..be78a9ef 100644 --- a/include/boost/asio/executor_work_guard.hpp +++ b/include/boost/asio/executor_work_guard.hpp @@ -16,6 +16,9 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include + +#if !defined(BOOST_ASIO_NO_TS_EXECUTORS) + #include #include #include @@ -281,4 +284,6 @@ make_work_guard(const T& t, ExecutionContext& ctx, #include +#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) + #endif // BOOST_ASIO_EXECUTOR_WORK_GUARD_HPP From d98c116eb7056f1afb8a1085a106dca9ebf5d244 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:26:49 +1000 Subject: [PATCH 84/90] Update executor examples to use standard executor form. --- example/cpp11/executors/bank_account_1.cpp | 44 ++++--- example/cpp11/executors/bank_account_2.cpp | 40 ++++--- example/cpp11/executors/fork_join.cpp | 80 ++++--------- example/cpp11/executors/pipeline.cpp | 35 ++---- .../cpp11/executors/priority_scheduler.cpp | 36 +----- example/cpp14/executors/async_1.cpp | 41 ++++--- example/cpp14/executors/async_2.cpp | 61 ++++++---- example/cpp14/executors/bank_account_1.cpp | 44 ++++--- example/cpp14/executors/bank_account_2.cpp | 39 ++++--- example/cpp14/executors/fork_join.cpp | 79 ++++--------- example/cpp14/executors/pipeline.cpp | 88 +++++++------- .../cpp14/executors/priority_scheduler.cpp | 108 ++++++++++-------- 12 files changed, 314 insertions(+), 381 deletions(-) diff --git a/example/cpp11/executors/bank_account_1.cpp b/example/cpp11/executors/bank_account_1.cpp index 35b659be..1e5d7304 100644 --- a/example/cpp11/executors/bank_account_1.cpp +++ b/example/cpp11/executors/bank_account_1.cpp @@ -1,9 +1,9 @@ -#include -#include +#include +#include #include -using boost::asio::post; -using boost::asio::thread_pool; +using boost::asio::static_thread_pool; +namespace execution = boost::asio::execution; // Traditional active object pattern. // Member functions do not block. @@ -11,37 +11,43 @@ using boost::asio::thread_pool; class bank_account { int balance_ = 0; - mutable thread_pool pool_{1}; + mutable static_thread_pool pool_{1}; public: void deposit(int amount) { - post(pool_, [=] - { - balance_ += amount; - }); + execution::execute( + pool_.executor(), + [this, amount] + { + balance_ += amount; + }); } void withdraw(int amount) { - post(pool_, [=] - { - if (balance_ >= amount) - balance_ -= amount; - }); + execution::execute( + pool_.executor(), + [this, amount] + { + if (balance_ >= amount) + balance_ -= amount; + }); } void print_balance() const { - post(pool_, [=] - { - std::cout << "balance = " << balance_ << "\n"; - }); + execution::execute( + pool_.executor(), + [this] + { + std::cout << "balance = " << balance_ << "\n"; + }); } ~bank_account() { - pool_.join(); + pool_.wait(); } }; diff --git a/example/cpp11/executors/bank_account_2.cpp b/example/cpp11/executors/bank_account_2.cpp index aebff764..b012d2fb 100644 --- a/example/cpp11/executors/bank_account_2.cpp +++ b/example/cpp11/executors/bank_account_2.cpp @@ -1,11 +1,9 @@ -#include -#include -#include +#include +#include #include -using boost::asio::post; -using boost::asio::thread_pool; -using boost::asio::use_future; +using boost::asio::static_thread_pool; +namespace execution = boost::asio::execution; // Traditional active object pattern. // Member functions block until operation is finished. @@ -13,35 +11,43 @@ using boost::asio::use_future; class bank_account { int balance_ = 0; - mutable thread_pool pool_{1}; + mutable static_thread_pool pool_{1}; public: void deposit(int amount) { - post(pool_, - use_future([=] + execution::execute( + boost::asio::require(pool_.executor(), + execution::blocking.always), + [this, amount] { balance_ += amount; - })).get(); + }); } void withdraw(int amount) { - post(pool_, - use_future([=] + execution::execute( + boost::asio::require(pool_.executor(), + execution::blocking.always), + [this, amount] { if (balance_ >= amount) balance_ -= amount; - })).get(); + }); } int balance() const { - return post(pool_, - use_future([=] + int result = 0; + execution::execute( + boost::asio::require(pool_.executor(), + execution::blocking.always), + [this, &result] { - return balance_; - })).get(); + result = balance_; + }); + return result; } }; diff --git a/example/cpp11/executors/fork_join.cpp b/example/cpp11/executors/fork_join.cpp index 98926d53..24a338e8 100644 --- a/example/cpp11/executors/fork_join.cpp +++ b/example/cpp11/executors/fork_join.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include +#include +#include #include #include #include @@ -8,14 +8,13 @@ #include #include -using boost::asio::dispatch; -using boost::asio::execution_context; -using boost::asio::thread_pool; +using boost::asio::static_thread_pool; +namespace execution = boost::asio::execution; // A fixed-size thread pool used to implement fork/join semantics. Functions // are scheduled using a simple FIFO queue. Implementing work stealing, or // using a queue based on atomic operations, are left as tasks for the reader. -class fork_join_pool : public execution_context +class fork_join_pool { public: // The constructor starts a thread pool with the specified number of threads. @@ -23,7 +22,7 @@ public: // Additional threads may temporarily be added to the pool if they join a // fork_executor. explicit fork_join_pool( - std::size_t thread_count = std::thread::hardware_concurrency() * 2) + std::size_t thread_count = std::max(std::thread::hardware_concurrency(), 1u) * 2) : use_count_(1), threads_(thread_count) { @@ -33,7 +32,9 @@ public: // it is time to shut down, i.e. the use count is zero. for (thread_count_ = 0; thread_count_ < thread_count; ++thread_count_) { - dispatch(threads_, [&] + execution::execute( + threads_.executor(), + [this] { std::unique_lock lock(mutex_); while (use_count_ > 0) @@ -45,7 +46,7 @@ public: catch (...) { stop_threads(); - threads_.join(); + threads_.wait(); throw; } } @@ -54,7 +55,7 @@ public: ~fork_join_pool() { stop_threads(); - threads_.join(); + threads_.wait(); } private: @@ -118,7 +119,7 @@ private: // Dispatch a function, executing it immediately if the queue is already // loaded. Otherwise adds the function to the queue and wakes a thread. - void do_dispatch(std::shared_ptr p, + void do_execute(std::shared_ptr p, const std::shared_ptr& work_count) { std::unique_lock lock(mutex_); @@ -136,16 +137,6 @@ private: } } - // Add a function to the queue and wake a thread. - void do_post(std::shared_ptr p, - const std::shared_ptr& work_count) - { - std::lock_guard lock(mutex_); - queue_.push(p); - do_work_started(work_count); - condition_.notify_one(); - } - // Ask all threads to shut down. void stop_threads() { @@ -159,7 +150,7 @@ private: std::queue> queue_; std::size_t use_count_; std::size_t thread_count_; - thread_pool threads_; + static_thread_pool threads_; }; // A class that satisfies the Executor requirements. Every function or piece of @@ -173,45 +164,16 @@ public: { } - fork_join_pool& context() const noexcept + fork_join_pool& query(execution::context_t) const noexcept { return context_; } - void on_work_started() const noexcept + template + void execute(Func f) const { - std::lock_guard lock(context_.mutex_); - context_.do_work_started(work_count_); - } - - void on_work_finished() const noexcept - { - std::lock_guard lock(context_.mutex_); - context_.do_work_finished(work_count_); - } - - template - void dispatch(Func&& f, const Alloc& a) const - { - auto p(std::allocate_shared>( - typename std::allocator_traits::template rebind_alloc(a), - std::move(f), work_count_)); - context_.do_dispatch(p, work_count_); - } - - template - void post(Func f, const Alloc& a) const - { - auto p(std::allocate_shared>( - typename std::allocator_traits::template rebind_alloc(a), - std::move(f), work_count_)); - context_.do_post(p, work_count_); - } - - template - void defer(Func&& f, const Alloc& a) const - { - post(std::forward(f), a); + auto p(std::make_shared>(std::move(f), work_count_)); + context_.do_execute(p, work_count_); } friend bool operator==(const fork_executor& a, @@ -290,8 +252,8 @@ void fork_join_sort(Iterator begin, Iterator end) { fork_executor fork(pool); join_guard join(fork); - dispatch(fork, [=]{ fork_join_sort(begin, begin + n / 2); }); - dispatch(fork, [=]{ fork_join_sort(begin + n / 2, end); }); + execution::execute(fork, [=]{ fork_join_sort(begin, begin + n / 2); }); + execution::execute(fork, [=]{ fork_join_sort(begin + n / 2, end); }); } std::inplace_merge(begin, begin + n / 2, end); } diff --git a/example/cpp11/executors/pipeline.cpp b/example/cpp11/executors/pipeline.cpp index 9c2a778f..2c23dec7 100644 --- a/example/cpp11/executors/pipeline.cpp +++ b/example/cpp11/executors/pipeline.cpp @@ -20,9 +20,10 @@ using boost::asio::post; using boost::asio::system_executor; using boost::asio::use_future; using boost::asio::use_service; +namespace execution = boost::asio::execution; // An executor that launches a new thread for each function submitted to it. -// This class satisfies the Executor requirements. +// This class satisfies the executor requirements. class thread_executor { private: @@ -55,40 +56,28 @@ private: }; public: - execution_context& context() const noexcept + execution_context& query(execution::context_t) const { - return system_executor().context(); + return boost::asio::query(system_executor(), execution::context); } - void on_work_started() const noexcept + execution::blocking_t query(execution::blocking_t) const { - // This executor doesn't count work. + return execution::blocking.never; } - void on_work_finished() const noexcept + thread_executor require(execution::blocking_t::never_t) const { - // This executor doesn't count work. + return *this; } - template - void dispatch(Func&& f, const Alloc& a) const + template + void execute(Func f) const { - post(std::forward(f), a); - } - - template - void post(Func f, const Alloc&) const - { - thread_bag& bag = use_service(context()); + thread_bag& bag = use_service(query(execution::context)); bag.add_thread(std::thread(std::move(f))); } - template - void defer(Func&& f, const Alloc& a) const - { - post(std::forward(f), a); - } - friend bool operator==(const thread_executor&, const thread_executor&) noexcept { @@ -292,7 +281,7 @@ void writer(queue_back in) int main() { - thread_pool pool; + thread_pool pool(1); auto f = pipeline(reader, filter, bind_executor(pool, upper), writer); f.wait(); diff --git a/example/cpp11/executors/priority_scheduler.cpp b/example/cpp11/executors/priority_scheduler.cpp index 7c9bc80d..c73861bf 100644 --- a/example/cpp11/executors/priority_scheduler.cpp +++ b/example/cpp11/executors/priority_scheduler.cpp @@ -8,6 +8,7 @@ using boost::asio::dispatch; using boost::asio::execution_context; +namespace execution = boost::asio::execution; class priority_scheduler : public execution_context { @@ -21,47 +22,20 @@ public: { } - priority_scheduler& context() const noexcept + priority_scheduler& query(execution::context_t) const noexcept { return context_; } - void on_work_started() const noexcept + template + void execute(Func f) const { - // This executor doesn't count work. Instead, the scheduler simply runs - // until explicitly stopped. - } - - void on_work_finished() const noexcept - { - // This executor doesn't count work. Instead, the scheduler simply runs - // until explicitly stopped. - } - - template - void dispatch(Func&& f, const Alloc& a) const - { - post(std::forward(f), a); - } - - template - void post(Func f, const Alloc& a) const - { - auto p(std::allocate_shared>( - typename std::allocator_traits< - Alloc>::template rebind_alloc(a), - priority_, std::move(f))); + auto p(std::make_shared>(priority_, std::move(f))); std::lock_guard lock(context_.mutex_); context_.queue_.push(p); context_.condition_.notify_one(); } - template - void defer(Func&& f, const Alloc& a) const - { - post(std::forward(f), a); - } - friend bool operator==(const executor_type& a, const executor_type& b) noexcept { diff --git a/example/cpp14/executors/async_1.cpp b/example/cpp14/executors/async_1.cpp index db72563a..407b8c7f 100644 --- a/example/cpp14/executors/async_1.cpp +++ b/example/cpp14/executors/async_1.cpp @@ -1,29 +1,35 @@ -#include -#include +#include +#include +#include +#include #include #include using boost::asio::bind_executor; -using boost::asio::dispatch; -using boost::asio::make_work_guard; -using boost::asio::post; -using boost::asio::thread_pool; +using boost::asio::get_associated_executor; +using boost::asio::static_thread_pool; +namespace execution = boost::asio::execution; // A function to asynchronously read a single line from an input stream. -template -void async_getline(std::istream& is, Handler handler) +template +void async_getline(IoExecutor io_ex, std::istream& is, Handler handler) { - // Create executor_work for the handler's associated executor. - auto work = make_work_guard(handler); + // Track work for the handler's associated executor. + auto work_ex = boost::asio::prefer( + get_associated_executor(handler, io_ex), + execution::outstanding_work.tracked); // Post a function object to do the work asynchronously. - post([&is, work, handler=std::move(handler)]() mutable + execution::execute( + boost::asio::require(io_ex, execution::blocking.never), + [&is, work_ex, handler=std::move(handler)]() mutable { std::string line; std::getline(is, line); // Pass the result to the handler, via the associated executor. - dispatch(work.get_executor(), + execution::execute( + boost::asio::prefer(work_ex, execution::blocking.possibly), [line=std::move(line), handler=std::move(handler)]() mutable { handler(std::move(line)); @@ -33,15 +39,18 @@ void async_getline(std::istream& is, Handler handler) int main() { - thread_pool pool; + static_thread_pool io_pool(1); + static_thread_pool completion_pool(1); std::cout << "Enter a line: "; - async_getline(std::cin, - bind_executor(pool, [](std::string line) + async_getline(io_pool.executor(), std::cin, + bind_executor(completion_pool.executor(), + [](std::string line) { std::cout << "Line: " << line << "\n"; })); - pool.join(); + io_pool.wait(); + completion_pool.wait(); } diff --git a/example/cpp14/executors/async_2.cpp b/example/cpp14/executors/async_2.cpp index 6f40a902..1987c3b5 100644 --- a/example/cpp14/executors/async_2.cpp +++ b/example/cpp14/executors/async_2.cpp @@ -1,30 +1,35 @@ -#include -#include +#include +#include +#include +#include #include #include using boost::asio::bind_executor; -using boost::asio::dispatch; using boost::asio::get_associated_executor; -using boost::asio::make_work_guard; -using boost::asio::post; -using boost::asio::thread_pool; +using boost::asio::static_thread_pool; +namespace execution = boost::asio::execution; // A function to asynchronously read a single line from an input stream. -template -void async_getline(std::istream& is, Handler handler) +template +void async_getline(IoExecutor io_ex, std::istream& is, Handler handler) { - // Create executor_work for the handler's associated executor. - auto work = make_work_guard(handler); + // Track work for the handler's associated executor. + auto work_ex = boost::asio::prefer( + get_associated_executor(handler, io_ex), + execution::outstanding_work.tracked); // Post a function object to do the work asynchronously. - post([&is, work, handler=std::move(handler)]() mutable + execution::execute( + boost::asio::require(io_ex, execution::blocking.never), + [&is, work_ex, handler=std::move(handler)]() mutable { std::string line; std::getline(is, line); // Pass the result to the handler, via the associated executor. - dispatch(work.get_executor(), + execution::execute( + boost::asio::prefer(work_ex, execution::blocking.possibly), [line=std::move(line), handler=std::move(handler)]() mutable { handler(std::move(line)); @@ -33,36 +38,44 @@ void async_getline(std::istream& is, Handler handler) } // A function to asynchronously read multiple lines from an input stream. -template -void async_getlines(std::istream& is, std::string init, Handler handler) +template +void async_getlines(IoExecutor io_ex, std::istream& is, std::string init, Handler handler) { - // Get the final handler's associated executor. - auto ex = get_associated_executor(handler); + // Track work for the I/O executor. + auto io_work_ex = boost::asio::prefer(io_ex, + execution::outstanding_work.tracked); + + // Track work for the handler's associated executor. + auto handler_work_ex = boost::asio::prefer( + get_associated_executor(handler, io_ex), + execution::outstanding_work.tracked); // Use the associated executor for each operation in the composition. - async_getline(is, - bind_executor(ex, - [&is, lines=std::move(init), handler=std::move(handler)] + async_getline(io_work_ex, is, + bind_executor(handler_work_ex, + [io_work_ex, &is, lines=std::move(init), handler=std::move(handler)] (std::string line) mutable { if (line.empty()) handler(lines); else - async_getlines(is, lines + line + "\n", std::move(handler)); + async_getlines(io_work_ex, is, lines + line + "\n", std::move(handler)); })); } int main() { - thread_pool pool; + static_thread_pool io_pool(1); + static_thread_pool completion_pool(1); std::cout << "Enter text, terminating with a blank line:\n"; - async_getlines(std::cin, "", - bind_executor(pool, [](std::string lines) + async_getlines(io_pool.executor(), std::cin, "", + bind_executor(completion_pool.executor(), [](std::string lines) { std::cout << "Lines:\n" << lines << "\n"; })); - pool.join(); + io_pool.wait(); + completion_pool.wait(); } diff --git a/example/cpp14/executors/bank_account_1.cpp b/example/cpp14/executors/bank_account_1.cpp index 6464b48d..1e5d7304 100644 --- a/example/cpp14/executors/bank_account_1.cpp +++ b/example/cpp14/executors/bank_account_1.cpp @@ -1,9 +1,9 @@ -#include -#include +#include +#include #include -using boost::asio::post; -using boost::asio::thread_pool; +using boost::asio::static_thread_pool; +namespace execution = boost::asio::execution; // Traditional active object pattern. // Member functions do not block. @@ -11,37 +11,43 @@ using boost::asio::thread_pool; class bank_account { int balance_ = 0; - mutable thread_pool pool_{1}; + mutable static_thread_pool pool_{1}; public: void deposit(int amount) { - post(pool_, [=] - { - balance_ += amount; - }); + execution::execute( + pool_.executor(), + [this, amount] + { + balance_ += amount; + }); } void withdraw(int amount) { - post(pool_, [=] - { - if (balance_ >= amount) - balance_ -= amount; - }); + execution::execute( + pool_.executor(), + [this, amount] + { + if (balance_ >= amount) + balance_ -= amount; + }); } void print_balance() const { - post(pool_, [=] - { - std::cout << "balance = " << balance_ << "\n"; - }); + execution::execute( + pool_.executor(), + [this] + { + std::cout << "balance = " << balance_ << "\n"; + }); } ~bank_account() { - pool_.join(); + pool_.wait(); } }; diff --git a/example/cpp14/executors/bank_account_2.cpp b/example/cpp14/executors/bank_account_2.cpp index 8de9a3cc..b012d2fb 100644 --- a/example/cpp14/executors/bank_account_2.cpp +++ b/example/cpp14/executors/bank_account_2.cpp @@ -1,10 +1,9 @@ -#include -#include +#include +#include #include -using boost::asio::post; -using boost::asio::thread_pool; -using boost::asio::use_future; +using boost::asio::static_thread_pool; +namespace execution = boost::asio::execution; // Traditional active object pattern. // Member functions block until operation is finished. @@ -12,35 +11,43 @@ using boost::asio::use_future; class bank_account { int balance_ = 0; - mutable thread_pool pool_{1}; + mutable static_thread_pool pool_{1}; public: void deposit(int amount) { - post(pool_, - use_future([=] + execution::execute( + boost::asio::require(pool_.executor(), + execution::blocking.always), + [this, amount] { balance_ += amount; - })).get(); + }); } void withdraw(int amount) { - post(pool_, - use_future([=] + execution::execute( + boost::asio::require(pool_.executor(), + execution::blocking.always), + [this, amount] { if (balance_ >= amount) balance_ -= amount; - })).get(); + }); } int balance() const { - return post(pool_, - use_future([=] + int result = 0; + execution::execute( + boost::asio::require(pool_.executor(), + execution::blocking.always), + [this, &result] { - return balance_; - })).get(); + result = balance_; + }); + return result; } }; diff --git a/example/cpp14/executors/fork_join.cpp b/example/cpp14/executors/fork_join.cpp index 2d9b4f7b..24a338e8 100644 --- a/example/cpp14/executors/fork_join.cpp +++ b/example/cpp14/executors/fork_join.cpp @@ -1,5 +1,6 @@ -#include -#include +#include +#include +#include #include #include #include @@ -7,14 +8,13 @@ #include #include -using boost::asio::dispatch; -using boost::asio::execution_context; -using boost::asio::thread_pool; +using boost::asio::static_thread_pool; +namespace execution = boost::asio::execution; // A fixed-size thread pool used to implement fork/join semantics. Functions // are scheduled using a simple FIFO queue. Implementing work stealing, or // using a queue based on atomic operations, are left as tasks for the reader. -class fork_join_pool : public execution_context +class fork_join_pool { public: // The constructor starts a thread pool with the specified number of threads. @@ -22,7 +22,7 @@ public: // Additional threads may temporarily be added to the pool if they join a // fork_executor. explicit fork_join_pool( - std::size_t thread_count = std::thread::hardware_concurrency() * 2) + std::size_t thread_count = std::max(std::thread::hardware_concurrency(), 1u) * 2) : use_count_(1), threads_(thread_count) { @@ -32,7 +32,9 @@ public: // it is time to shut down, i.e. the use count is zero. for (thread_count_ = 0; thread_count_ < thread_count; ++thread_count_) { - dispatch(threads_, [&] + execution::execute( + threads_.executor(), + [this] { std::unique_lock lock(mutex_); while (use_count_ > 0) @@ -44,7 +46,7 @@ public: catch (...) { stop_threads(); - threads_.join(); + threads_.wait(); throw; } } @@ -53,7 +55,7 @@ public: ~fork_join_pool() { stop_threads(); - threads_.join(); + threads_.wait(); } private: @@ -117,7 +119,7 @@ private: // Dispatch a function, executing it immediately if the queue is already // loaded. Otherwise adds the function to the queue and wakes a thread. - void do_dispatch(std::shared_ptr p, + void do_execute(std::shared_ptr p, const std::shared_ptr& work_count) { std::unique_lock lock(mutex_); @@ -135,16 +137,6 @@ private: } } - // Add a function to the queue and wake a thread. - void do_post(std::shared_ptr p, - const std::shared_ptr& work_count) - { - std::lock_guard lock(mutex_); - queue_.push(p); - do_work_started(work_count); - condition_.notify_one(); - } - // Ask all threads to shut down. void stop_threads() { @@ -158,7 +150,7 @@ private: std::queue> queue_; std::size_t use_count_; std::size_t thread_count_; - thread_pool threads_; + static_thread_pool threads_; }; // A class that satisfies the Executor requirements. Every function or piece of @@ -172,45 +164,16 @@ public: { } - fork_join_pool& context() const noexcept + fork_join_pool& query(execution::context_t) const noexcept { return context_; } - void on_work_started() const noexcept + template + void execute(Func f) const { - std::lock_guard lock(context_.mutex_); - context_.do_work_started(work_count_); - } - - void on_work_finished() const noexcept - { - std::lock_guard lock(context_.mutex_); - context_.do_work_finished(work_count_); - } - - template - void dispatch(Func&& f, const Alloc& a) const - { - auto p(std::allocate_shared>( - typename std::allocator_traits::template rebind_alloc(a), - std::move(f), work_count_)); - context_.do_dispatch(p, work_count_); - } - - template - void post(Func f, const Alloc& a) const - { - auto p(std::allocate_shared>( - typename std::allocator_traits::template rebind_alloc(a), - std::move(f), work_count_)); - context_.do_post(p, work_count_); - } - - template - void defer(Func&& f, const Alloc& a) const - { - post(std::forward(f), a); + auto p(std::make_shared>(std::move(f), work_count_)); + context_.do_execute(p, work_count_); } friend bool operator==(const fork_executor& a, @@ -289,8 +252,8 @@ void fork_join_sort(Iterator begin, Iterator end) { fork_executor fork(pool); join_guard join(fork); - dispatch(fork, [=]{ fork_join_sort(begin, begin + n / 2); }); - dispatch(fork, [=]{ fork_join_sort(begin + n / 2, end); }); + execution::execute(fork, [=]{ fork_join_sort(begin, begin + n / 2); }); + execution::execute(fork, [=]{ fork_join_sort(begin + n / 2, end); }); } std::inplace_merge(begin, begin + n / 2, end); } diff --git a/example/cpp14/executors/pipeline.cpp b/example/cpp14/executors/pipeline.cpp index bd837083..83e1ee49 100644 --- a/example/cpp14/executors/pipeline.cpp +++ b/example/cpp14/executors/pipeline.cpp @@ -1,4 +1,6 @@ -#include +#include +#include +#include #include #include #include @@ -8,29 +10,19 @@ #include #include -using boost::asio::execution_context; using boost::asio::executor_binder; using boost::asio::get_associated_executor; -using boost::asio::post; -using boost::asio::system_executor; -using boost::asio::use_future; -using boost::asio::use_service; +namespace execution = boost::asio::execution; // An executor that launches a new thread for each function submitted to it. -// This class satisfies the Executor requirements. +// This class satisfies the executor requirements. class thread_executor { private: - // Service to track all threads started through a thread_executor. - class thread_bag : public execution_context::service + // Singleton execution context that manages threads launched by the new_thread_executor. + class thread_bag { - public: - typedef thread_bag key_type; - - explicit thread_bag(execution_context& ctx) - : execution_context::service(ctx) - { - } + friend class thread_executor; void add_thread(std::thread&& t) { @@ -38,8 +30,9 @@ private: threads_.push_back(std::move(t)); } - private: - virtual void shutdown() + thread_bag() = default; + + ~thread_bag() { for (auto& t : threads_) t.join(); @@ -50,40 +43,24 @@ private: }; public: - execution_context& context() const noexcept + static thread_bag& query(execution::context_t) { - return system_executor().context(); + static thread_bag threads; + return threads; } - void on_work_started() const noexcept + static constexpr auto query(execution::blocking_t) { - // This executor doesn't count work. + return execution::blocking.never; } - void on_work_finished() const noexcept + template + void execute(Func f) const { - // This executor doesn't count work. - } - - template - void dispatch(Func&& f, const Alloc& a) const - { - post(std::forward(f), a); - } - - template - void post(Func f, const Alloc&) const - { - thread_bag& bag = use_service(context()); + thread_bag& bag = query(execution::context); bag.add_thread(std::thread(std::move(f))); } - template - void defer(Func&& f, const Alloc& a) const - { - post(std::forward(f), a); - } - friend bool operator==(const thread_executor&, const thread_executor&) noexcept { @@ -186,7 +163,16 @@ std::future pipeline(queue_back in, F f) // Run the function, and as we're the last stage return a future so that the // caller can wait for the pipeline to finish. - return post(ex, use_future([in, f = std::move(f)]() mutable { f(in); })); + std::packaged_task task( + [in, f = std::move(f)]() mutable + { + f(in); + }); + std::future fut = task.get_future(); + execution::execute( + boost::asio::require(ex, execution::blocking.never), + std::move(task)); + return fut; } // Launch an intermediate stage in a pipeline. @@ -205,7 +191,9 @@ std::future pipeline(queue_back in, F f, Tail... t) auto ex = get_associated_executor(f, thread_executor()); // Run the function. - post(ex, [in, out, f = std::move(f)]() mutable + execution::execute( + boost::asio::require(ex, execution::blocking.never), + [in, out, f = std::move(f)]() mutable { f(in, out); out.stop(); @@ -231,7 +219,9 @@ std::future pipeline(F f, Tail... t) auto ex = get_associated_executor(f, thread_executor()); // Run the function. - post(ex, [out, f = std::move(f)]() mutable + execution::execute( + boost::asio::require(ex, execution::blocking.never), + [out, f = std::move(f)]() mutable { f(out); out.stop(); @@ -243,12 +233,12 @@ std::future pipeline(F f, Tail... t) //------------------------------------------------------------------------------ -#include +#include #include #include using boost::asio::bind_executor; -using boost::asio::thread_pool; +using boost::asio::static_thread_pool; void reader(queue_front out) { @@ -287,8 +277,8 @@ void writer(queue_back in) int main() { - thread_pool pool; + static_thread_pool pool(1); - auto f = pipeline(reader, filter, bind_executor(pool, upper), writer); + auto f = pipeline(reader, filter, bind_executor(pool.executor(), upper), writer); f.wait(); } diff --git a/example/cpp14/executors/priority_scheduler.cpp b/example/cpp14/executors/priority_scheduler.cpp index f1185319..b0c890e4 100644 --- a/example/cpp14/executors/priority_scheduler.cpp +++ b/example/cpp14/executors/priority_scheduler.cpp @@ -1,66 +1,74 @@ -#include +#include #include #include #include #include #include -using boost::asio::dispatch; -using boost::asio::execution_context; +namespace execution = boost::asio::execution; -class priority_scheduler : public execution_context +namespace custom_props { + + struct priority + { + template + static constexpr bool is_applicable_property_v = + execution::is_executor::value; + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + + using polymorphic_query_result_type = int; + + int value() const { return value_; } + + int value_ = 1; + }; + + constexpr priority low_priority{0}; + constexpr priority normal_priority{1}; + constexpr priority high_priority{2}; + +} // namespace custom_props + +class priority_scheduler { public: // A class that satisfies the Executor requirements. class executor_type { public: - executor_type(priority_scheduler& ctx, int pri) noexcept - : context_(ctx), priority_(pri) + executor_type(priority_scheduler& ctx) noexcept + : context_(ctx), priority_(custom_props::normal_priority.value()) { } - priority_scheduler& context() const noexcept + priority_scheduler& query(execution::context_t) const noexcept { return context_; } - void on_work_started() const noexcept + int query(custom_props::priority) const noexcept { - // This executor doesn't count work. Instead, the scheduler simply runs - // until explicitly stopped. + return priority_; } - void on_work_finished() const noexcept + executor_type require(custom_props::priority pri) const { - // This executor doesn't count work. Instead, the scheduler simply runs - // until explicitly stopped. + executor_type new_ex(*this); + new_ex.priority_ = pri.value(); + return new_ex; } - template - void dispatch(Func&& f, const Alloc& a) const + template + void execute(Func f) const { - post(std::forward(f), a); - } - - template - void post(Func f, const Alloc& a) const - { - auto p(std::allocate_shared>( - typename std::allocator_traits< - Alloc>::template rebind_alloc(a), - priority_, std::move(f))); + auto p(std::make_shared>(priority_, std::move(f))); std::lock_guard lock(context_.mutex_); context_.queue_.push(p); context_.condition_.notify_one(); } - template - void defer(Func&& f, const Alloc& a) const - { - post(std::forward(f), a); - } - friend bool operator==(const executor_type& a, const executor_type& b) noexcept { @@ -78,15 +86,9 @@ public: int priority_; }; - ~priority_scheduler() noexcept + executor_type executor() noexcept { - shutdown(); - destroy(); - } - - executor_type get_executor(int pri = 0) noexcept - { - return executor_type(*const_cast(this), pri); + return executor_type(*const_cast(this)); } void run() @@ -158,16 +160,22 @@ private: int main() { priority_scheduler sched; - auto low = sched.get_executor(0); - auto med = sched.get_executor(1); - auto high = sched.get_executor(2); - dispatch(low, []{ std::cout << "1\n"; }); - dispatch(low, []{ std::cout << "11\n"; }); - dispatch(med, []{ std::cout << "2\n"; }); - dispatch(med, []{ std::cout << "22\n"; }); - dispatch(high, []{ std::cout << "3\n"; }); - dispatch(high, []{ std::cout << "33\n"; }); - dispatch(high, []{ std::cout << "333\n"; }); - dispatch(sched.get_executor(-1), [&]{ sched.stop(); }); + auto ex = sched.executor(); + auto prefer_low = boost::asio::prefer(ex, custom_props::low_priority); + auto low = boost::asio::require(ex, custom_props::low_priority); + auto med = boost::asio::require(ex, custom_props::normal_priority); + auto high = boost::asio::require(ex, custom_props::high_priority); + execution::any_executor poly_high(high); + execution::execute(prefer_low, []{ std::cout << "1\n"; }); + execution::execute(low, []{ std::cout << "11\n"; }); + execution::execute(low, []{ std::cout << "111\n"; }); + execution::execute(med, []{ std::cout << "2\n"; }); + execution::execute(med, []{ std::cout << "22\n"; }); + execution::execute(high, []{ std::cout << "3\n"; }); + execution::execute(high, []{ std::cout << "33\n"; }); + execution::execute(high, []{ std::cout << "333\n"; }); + execution::execute(poly_high, []{ std::cout << "3333\n"; }); + execution::execute(boost::asio::require(ex, custom_props::priority{-1}), [&]{ sched.stop(); }); sched.run(); + std::cout << "polymorphic query result = " << boost::asio::query(poly_high, custom_props::priority{}) << "\n"; } From c55037795c7a4a3a59c02ffe6af0122afa5e2425 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:31:09 +1000 Subject: [PATCH 85/90] Documentation generation tweaks for new execution facilities. --- doc/reference.dox | 4 +++- doc/reference.xsl | 58 ++++++++++++++++++++++++++++++++++++++++++++--- doc/tutorial.xsl | 7 ++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/doc/reference.dox b/doc/reference.dox index 6db85872..a77ccdf1 100644 --- a/doc/reference.dox +++ b/doc/reference.dox @@ -81,6 +81,7 @@ INPUT = ./../../../boost/asio.hpp \ ./../../../boost/asio/posix \ ./../../../boost/asio/ssl \ ./../../../boost/asio/windows \ + ./../../../boost/asio/execution \ ./noncopyable_dox.txt \ ./std_exception_dox.txt FILE_PATTERNS = @@ -221,7 +222,8 @@ PREDEFINED = GENERATING_DOCUMENTATION \ BOOST_ASIO_MUTABLE_BUFFER=mutable_buffer \ BOOST_ASIO_SYNC_OP_VOID=void \ BOOST_ASIO_STRING_VIEW_PARAM=string_view \ - BOOST_ASIO_UNUSED_VARIABLE= + BOOST_ASIO_UNUSED_VARIABLE= \ + BOOST_ASIO_UNSPECIFIED(e)=unspecified EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- diff --git a/doc/reference.xsl b/doc/reference.xsl index d74a4da3..8e8a7ca6 100644 --- a/doc/reference.xsl +++ b/doc/reference.xsl @@ -110,7 +110,8 @@ not(contains(compoundname, 'std_allocator_void')) and not(contains(compoundname, 'thread_function')) and not(contains(compoundname, 'context_impl')) and - not(contains(compoundname, 'initiate_'))"> + not(contains(compoundname, 'initiate_')) and + not(contains(compoundname, '_is_deprecated'))"> @@ -124,7 +125,8 @@ not(contains(name, 'std_allocator_void')) and not(contains(name, 'thread_function')) and not(contains(name, 'io_context_impl')) and - not(contains(name, 'initiate_'))"> + not(contains(name, 'initiate_')) and + not(contains(name, '_is_deprecated'))"> @@ -133,6 +135,7 @@ [endsect] + @@ -214,7 +217,11 @@ + + + query__static + + + + + + ['Convenience header: ] + + [^boost/asio/execution.hpp] + [^boost/asio/ssl.hpp] @@ -909,6 +925,7 @@ + @@ -958,6 +975,7 @@ + @@ -1008,6 +1026,7 @@ + @@ -1219,6 +1238,7 @@ + @@ -1362,7 +1382,7 @@ typedef ; - + @@ -1407,6 +1427,14 @@ + + + template <typename T> + + + + template <typename U> + static @@ -1495,6 +1523,12 @@ + + + + + + @@ -1582,6 +1616,12 @@ + + + + + + @@ -1594,6 +1634,12 @@ + + + + + + @@ -1603,6 +1649,9 @@ + + + @@ -1627,6 +1676,9 @@ + + + diff --git a/doc/tutorial.xsl b/doc/tutorial.xsl index 232de794..6dd9a745 100644 --- a/doc/tutorial.xsl +++ b/doc/tutorial.xsl @@ -66,6 +66,7 @@ [endsect] + @@ -121,6 +122,12 @@ select="concat(substring-before($name, '>'), '_gt_', substring-after($name, '>'))"/> + + + + + Date: Mon, 22 Jun 2020 23:31:59 +1000 Subject: [PATCH 86/90] Add new executor type requirements. --- doc/requirements/Executor.qbk | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/doc/requirements/Executor.qbk b/doc/requirements/Executor.qbk index d2bf64c0..e1ff1214 100644 --- a/doc/requirements/Executor.qbk +++ b/doc/requirements/Executor.qbk @@ -7,6 +7,78 @@ [section:Executor1 Executor requirements] +[heading Standard executors] + +An executor is defined by the following concept: + + template + concept executor = + invocable&> + && constructible_from, F> + && move_constructible> + && copy_constructible + && is_nothrow_copy_constructible_v + && equality_comparable + && + requires(const E& e, invocable_archetype f) + { + execution::execute(e, static_cast(f)); + }; + +Neither an executor's equality comparison nor `swap` operation shall exit via +an exception. + +None of an executor type's copy constructor, destructor, equality comparison, +`swap` function, `execute` function, or associated `query` functions shall +introduce data races as a result of concurrent invocations of those functions +from different threads. + +For any two (possibly const) values `x1` and `x2` of some executor type `X`, +`x1 == x2` shall return `true` only if `boost::asio::query(x1,p) == boost::asio::query(x2,p)` +for every property `p` where both `boost::asio::query(x1,p)` and `boost::asio::query(x2,p)` +are well-formed and result in a non-void type that is `equality_comparable` +(C++Std [equalitycomparable]). [inline_note The above requirements imply that `x1 +== x2` returns `true` if `x1` and `x2` can be interchanged with identical +effects. An executor may conceptually contain additional properties which are +not exposed by a named property type that can be observed via `boost::asio::query`; in +this case, it is up to the concrete executor implementation to decide if these +properties affect equality. Returning `false` does not necessarily imply that +the effects are not identical.] + +An executor type's destructor shall not block pending completion of the +submitted function objects. [inline_note The ability to wait for completion of +submitted function objects may be provided by the associated execution +context.] + +In addition to the above requirements, types `E` and `F` model `executor_of` +only if they satisfy the requirements of the Table below. + +Let: + +* `e` denotes a (possibly const) executor object of type `E`, + +* `cf` denotes the function object `DECAY_COPY(std::forward(f))` + +* `f` denotes a function of type `F&&` invocable as `cf()` and where + `decay_t` models `move_constructible`. + +The expression `execution::execute(e, f)`: + +* Evaluates `DECAY_COPY(std::forward(f))` on the calling thread to create + `cf` that will be invoked at most once by an execution agent. + +* May block pending completion of this invocation. Synchronizes with + [intro.multithread] the invocation of `f`. + +* Shall not propagate any exception thrown by the function object or any other + function submitted to the executor. + +[inline_note The treatment of exceptions thrown by one-way submitted functions +is implementation-defined. The forward progress guarantee of the associated +execution agent(s) is implementation-defined.] + +[heading Networking TS-style executors] + The library describes a standard set of requirements for ['executors]. A type meeting the `Executor` requirements embodies a set of rules for determining how submitted function objects are to be executed. From 93eb9610146b512fe4afd1f905ee4287a8ed50a7 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Jun 2020 23:36:08 +1000 Subject: [PATCH 87/90] Add new execution facilities to quick reference. --- doc/quickref.xml | 145 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 5 deletions(-) diff --git a/doc/quickref.xml b/doc/quickref.xml index cf478be2..3228079a 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -9,6 +9,135 @@ --> + + + + + + + + + Properties + + + Execution + + + + + + + Customisation Points + + prefer + query + require + require_concept + + Traits + + can_prefer + can_query + can_require + can_require_concept + is_nothrow_prefer + is_nothrow_query + is_nothrow_require + is_nothrow_require_concept + prefer_result_type + query_result_type + require_result_type + require_concept_result_type + + + + Concepts + + Executor + + Customisation Points + + execution::execute + + Class Templates + + execution::any_executor + + Classes + + execution::bad_executor + execution::invocable_archetype + + Traits + + execution::is_executor + execution::can_execute + + + + Properties + + execution::allocator_t + execution::blocking_t + execution::blocking_t::possibly_t + execution::blocking_t::always_t + execution::blocking_t::never_t + execution::blocking_adaptation_t + execution::blocking_adaptation_t::disallowed_t + execution::blocking_adaptation_t::allowed_t + execution::bulk_guarantee_t + execution::bulk_guarantee_t::unsequenced_t + execution::bulk_guarantee_t::sequenced_t + execution::bulk_guarantee_t::parallel_t + execution::context_t + execution::context_as_t + execution::mapping_t + execution::mapping_t::thread_t + execution::mapping_t::new_thread_t + execution::mapping_t::other_t + execution::occupancy_t + execution::outstanding_work_t + execution::outstanding_work_t::untracked_t + execution::outstanding_work_t::tracked_t + execution::prefer_only + execution::relationship_t + execution::relationship_t::fork_t + execution::relationship_t::continuation_t + + + + Property Objects + + execution::allocator + execution::blocking + execution::blocking.possibly + execution::blocking.always + execution::blocking.never + execution::blocking_adaptation + execution::blocking_adaptation.disallowed + execution::blocking_adaptation.allowed + execution::bulk_guarantee + execution::bulk_guarantee.unsequenced + execution::bulk_guarantee.sequenced + execution::bulk_guarantee.parallel + execution::context + execution::context_as + execution::mapping + execution::mapping.thread + execution::mapping.new_thread + execution::mapping.other + execution::occupancy + execution::outstanding_work + execution::outstanding_work.untracked + execution::outstanding_work.tracked + execution::relationship + execution::relationship.fork + execution::relationship.continuation + + + + + @@ -26,6 +155,7 @@ Classes + any_io_executor bad_executor coroutine detached_t @@ -36,16 +166,18 @@ executor_arg_t invalid_service_owner io_context - io_context::executor_type + io_context::executor_type io_context::service io_context::strand io_context::work (deprecated) + multiple_exceptions service_already_exists + static_thread_pool system_context system_executor this_coro::executor_t thread_pool - thread_pool::executor_type + thread_pool::executor_type yield_context @@ -53,9 +185,9 @@ Free Functions add_service - asio_handler_allocate - asio_handler_deallocate - asio_handler_invoke + asio_handler_allocate (deprecated) + asio_handler_deallocate (deprecated) + asio_handler_invoke (deprecated) asio_handler_is_continuation async_compose async_initiate @@ -80,11 +212,14 @@ async_completion awaitable basic_io_object + basic_system_executor basic_yield_context executor_binder executor_work_guard + io_context::basic_executor_type redirect_error_t strand + thread_pool::basic_executor_type use_awaitable_t use_future_t From c4adb6ff02cb59f8d5a819e98ebb570e6621f89d Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Tue, 23 Jun 2020 11:29:09 +1000 Subject: [PATCH 88/90] Regenerate documentation. --- doc/reference.qbk | 11198 +++++++++++++++++++++++++++++++++++++++++--- doc/tutorial.qbk | 28 +- 2 files changed, 10668 insertions(+), 558 deletions(-) diff --git a/doc/reference.qbk b/doc/reference.qbk index 86c50785..8b9182fc 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -64,13 +64,138 @@ +[section:any_io_executor any_io_executor] + +[indexterm1 boost_asio.indexterm.any_io_executor..any_io_executor] +Polymorphic executor type for use with I/O objects. + + + typedef execution::any_executor<...> any_io_executor; + + +[heading Member Functions] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.execution__any_executor.any_executor [*any_executor]]] + [Default constructor. + [hr] + Copy constructor. + [hr] + Move constructor. + [hr] + Construct to point to the same target as another any_executor. + [hr] + Construct a polymorphic wrapper for the specified executor. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor.context [*context]]] + [Obtain the underlying execution context. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor.execute [*execute]]] + [Execute the function on the target executor. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor.operator_bool [*operator bool]]] + [Determine whether the wrapper has a target executor. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor.operator_eq_ [*operator=]]] + [Assignment operator. + [hr] + Move assignment operator. + [hr] + Assignment operator to create a polymorphic wrapper for the specified executor. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor.prefer [*prefer]]] + [Obtain a polymorphic wrapper with the specified property. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor.query [*query]]] + [Obtain the value associated with the specified property. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor.require [*require]]] + [Obtain a polymorphic wrapper with the specified property. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor.target [*target]]] + [Get a pointer to the target executor. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor.target_type [*target_type]]] + [Get the type of the target executor. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor._any_executor [*~any_executor]]] + [Destructor. ] + ] + +] + +[heading Related Functions] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.execution__any_executor.operator_not__eq_ [*operator!=]]] + [Inequality operator. ] + ] + + [ + [[link boost_asio.reference.execution__any_executor.operator_eq__eq_ [*operator==]]] + [Equality operator. ] + ] + +] + + +The `any_io_executor` type is a polymorphic executor that supports the set of properties required by I/O objects. It is defined as the [link boost_asio.reference.execution__any_executor `execution::any_executor`] class template parameterised as follows: + + execution::any_executor< + execution::context_as_t, + execution::blocking_t::never_t, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only, + execution::prefer_only + > + + + + +[heading Requirements] + +['Header: ][^boost/asio/any_io_executor.hpp] + +['Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + [section:asio_handler_allocate asio_handler_allocate] [indexterm1 boost_asio.indexterm.asio_handler_allocate..asio_handler_allocate] -Default allocation function for handlers. +(Deprecated: Use the [link boost_asio.reference.associated_allocator `associated_allocator`] trait.) Default allocation function for handlers. - void * asio_handler_allocate( + asio_handler_allocate_is_deprecated asio_handler_allocate( std::size_t size, ... ); @@ -126,7 +251,7 @@ All temporary objects associated with a handler will be deallocated before the u Default deallocation function for handlers. - void asio_handler_deallocate( + asio_handler_deallocate_is_deprecated asio_handler_deallocate( void * pointer, std::size_t size, ... ); @@ -152,14 +277,14 @@ The default implementation of these allocation hooks uses `operator new` and `op [section:asio_handler_invoke asio_handler_invoke] [indexterm1 boost_asio.indexterm.asio_handler_invoke..asio_handler_invoke] -Default invoke function for handlers. +(Deprecated: Use the [link boost_asio.reference.associated_executor `associated_executor`] trait.) Default invoke function for handlers. Default handler invocation hook used for non-const function objects. template< typename Function> - void ``[link boost_asio.reference.asio_handler_invoke.overload1 asio_handler_invoke]``( + asio_handler_invoke_is_deprecated ``[link boost_asio.reference.asio_handler_invoke.overload1 asio_handler_invoke]``( Function & function, ... ); `` [''''»''' [link boost_asio.reference.asio_handler_invoke.overload1 more...]]`` @@ -168,7 +293,7 @@ Default handler invocation hook used for const function objects. template< typename Function> - void ``[link boost_asio.reference.asio_handler_invoke.overload2 asio_handler_invoke]``( + asio_handler_invoke_is_deprecated ``[link boost_asio.reference.asio_handler_invoke.overload2 asio_handler_invoke]``( const Function & function, ... ); `` [''''»''' [link boost_asio.reference.asio_handler_invoke.overload2 more...]]`` @@ -219,7 +344,7 @@ Default handler invocation hook used for non-const function objects. template< typename Function> - void asio_handler_invoke( + asio_handler_invoke_is_deprecated asio_handler_invoke( Function & function, ... ); @@ -237,7 +362,7 @@ Default handler invocation hook used for const function objects. template< typename Function> - void asio_handler_invoke( + asio_handler_invoke_is_deprecated asio_handler_invoke( const Function & function, ... ); @@ -5439,7 +5564,7 @@ The return type of a coroutine or asynchronous operation. template< typename T, - typename ``[link boost_asio.reference.Executor1 Executor]`` = executor> + typename ``[link boost_asio.reference.Executor1 Executor]`` = any_io_executor> class awaitable @@ -12431,7 +12556,7 @@ Provides waitable timer functionality. template< typename Time, typename ``[link boost_asio.reference.TimeTraits TimeTraits]`` = boost::asio::time_traits