From f41363c60c7aee9fbf6a106450b73b9280ecdd1f Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 15 Feb 2019 15:16:51 -0800 Subject: [PATCH] Add async_op_base::invoke --- CHANGELOG.md | 1 + doc/qbk/quickref.xml | 4 ++ .../beast/_experimental/test/handler.hpp | 45 ++++++++-------- .../boost/beast/_experimental/test/stream.hpp | 4 +- include/boost/beast/core/async_op_base.hpp | 48 +++++++++++++++-- .../boost/beast/core/dynamic_buffer_ref.hpp | 2 +- include/boost/beast/http/basic_parser.hpp | 4 +- test/beast/core/async_op_base.cpp | 51 +++++++++++++++---- test/beast/core/test_handler.hpp | 4 +- 9 files changed, 122 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ece7708..f62d9eea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Version 215: * Examples use bind_front_handler * Add experimental test/handler.hpp * Rename to async_op_base::invoke_now +* Add async_op_base::invoke -------------------------------------------------------------------------------- diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml index efcca5f3..941c7255 100644 --- a/doc/qbk/quickref.xml +++ b/doc/qbk/quickref.xml @@ -357,6 +357,7 @@ ssl_stream http::icy_stream test::fail_count + test::handler 🞲 test::stream @@ -364,6 +365,9 @@ Functions test::connect + test::any_handler 🞲 + test::fail_handler 🞲 + test::success_handler 🞲 diff --git a/include/boost/beast/_experimental/test/handler.hpp b/include/boost/beast/_experimental/test/handler.hpp index a2cb7e79..de889f95 100644 --- a/include/boost/beast/_experimental/test/handler.hpp +++ b/include/boost/beast/_experimental/test/handler.hpp @@ -19,8 +19,17 @@ namespace boost { namespace beast { namespace test { -namespace detail { +/** A CompletionHandler used for testing. + This completion handler is used by tests to ensure correctness + of behavior. It is designed as a single type to reduce template + instantiations, with configurable settings through constructor + arguments. Typically this type will be used in type lists and + not instantiated directly; instances of this class are returned + by the helper functions listed below. + + @see @ref success_handler, @ref fail_handler, @ref any_handler +*/ class handler { boost::optional ec_; @@ -61,6 +70,14 @@ public: pass_ = true; } + void + operator()() + { + BEAST_EXPECT(! pass_); // can't call twice + BEAST_EXPECT(! ec_); + pass_ = true; + } + template::value>::type> @@ -73,8 +90,6 @@ public: } }; -} // detail - /** Return a test CompletionHandler which requires success. The returned handler can be invoked with any signature whose @@ -86,14 +101,10 @@ public: @li The handler is invoked with a non-successful error code. */ inline -#if BOOST_BEAST_DOXYGEN -__implementation_defined__ -#else -detail::handler -#endif +handler success_handler() noexcept { - return detail::handler(error_code{}); + return handler(error_code{}); } /** Return a test CompletionHandler which requires invocation. @@ -104,14 +115,10 @@ success_handler() noexcept @li The handler is destroyed without being invoked. */ inline -#if BOOST_BEAST_DOXYGEN -__implementation_defined__ -#else -detail::handler -#endif +handler any_handler() noexcept { - return detail::handler(boost::none); + return handler(boost::none); } /** Return a test CompletionHandler which requires a specific error code. @@ -127,14 +134,10 @@ any_handler() noexcept @param ec The error code to specify. */ inline -#if BOOST_BEAST_DOXYGEN -__implementation_defined__ -#else -detail::handler -#endif +handler fail_handler(error_code ec) noexcept { - return detail::handler(ec); + return handler(ec); } } // test diff --git a/include/boost/beast/_experimental/test/stream.hpp b/include/boost/beast/_experimental/test/stream.hpp index d8095f66..4869c0e1 100644 --- a/include/boost/beast/_experimental/test/stream.hpp +++ b/include/boost/beast/_experimental/test/stream.hpp @@ -61,8 +61,8 @@ namespace test { To facilitate testing, these streams support some additional features: - @li The input area, represented by a @ref flat_buffer, may - be directly accessed by the caller to inspect the contents + @li The input area, represented by a @ref basic_flat_buffer, + may be directly accessed by the caller to inspect the contents before or after the remote endpoint writes data. This allows a unit test to verify that the received data matches. diff --git a/include/boost/beast/core/async_op_base.hpp b/include/boost/beast/core/async_op_base.hpp index 201445cc..f33fb350 100644 --- a/include/boost/beast/core/async_op_base.hpp +++ b/include/boost/beast/core/async_op_base.hpp @@ -11,14 +11,17 @@ #define BOOST_BEAST_CORE_ASYNC_OP_BASE_HPP #include +#include #include #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -314,15 +317,54 @@ public: return std::move(h_); } - /** Invoke the final completion handler. + /** Invoke the final completion handler, maybe using post. This invokes the final completion handler with the specified - arguments forwarded. It is undefined to call this member - function more than once. + arguments forwarded. It is undefined to call either of + @ref invoke or @ref invoke_now more than once. Any temporary objects allocated with @ref allocate_stable will be automatically destroyed before the final completion handler is invoked. + + @param is_continuation If this value is `false`, then the + handler will be submitted to the executor using `net::post`. + Otherwise the handler will be invoked as if by calling + @ref invoke_now. + + @param args A list of optional parameters to invoke the handler + with. The completion handler must be invocable with the parameter + list, or else a compilation error will result. + */ + template + void + invoke(bool is_continuation, Args&&... args) + { + this->before_invoke_hook(); + wg1_.reset(); + if(! is_continuation) + net::post(net::bind_executor( + wg1_.get_executor(), + beast::bind_front_handler( + std::move(h_), + std::forward(args)...))); + else + h_(std::forward(args)...); + } + + /** Invoke the final completion handler. + + This invokes the final completion handler with the specified + arguments forwarded. It is undefined to call either of + @ref invoke or @ref invoke_now more than once. + + Any temporary objects allocated with @ref allocate_stable will + be automatically destroyed before the final completion handler + is invoked. + + @param args A list of optional parameters to invoke the handler + with. The completion handler must be invocable with the parameter + list, or else a compilation error will result. */ template void diff --git a/include/boost/beast/core/dynamic_buffer_ref.hpp b/include/boost/beast/core/dynamic_buffer_ref.hpp index 523b1329..7763e3c0 100644 --- a/include/boost/beast/core/dynamic_buffer_ref.hpp +++ b/include/boost/beast/core/dynamic_buffer_ref.hpp @@ -110,7 +110,7 @@ public: @par Example This function reads a line of text from a stream into a - @ref flat_buffer, using the net function `async_read_until`. The + @ref basic_flat_buffer, using the net function `async_read_until`. @code template std::size_t read_line (SyncReadStream& stream, flat_buffer& buffer) diff --git a/include/boost/beast/http/basic_parser.hpp b/include/boost/beast/http/basic_parser.hpp index cf17a90f..0f687ff5 100644 --- a/include/boost/beast/http/basic_parser.hpp +++ b/include/boost/beast/http/basic_parser.hpp @@ -38,10 +38,10 @@ namespace http { fields. The parser is optimized for the case where the input buffer sequence consists of a single contiguous buffer. The - @ref flat_buffer class is provided, which guarantees + @ref basic_flat_buffer class is provided, which guarantees that the input sequence of the stream buffer will be represented by exactly one contiguous buffer. To ensure the optimum performance - of the parser, use @ref flat_buffer with HTTP algorithms + of the parser, use @ref basic_flat_buffer with HTTP algorithms such as @ref read, @ref read_some, @ref async_read, and @ref async_read_some. Alternatively, the caller may use custom techniques to ensure that the structured portion of the HTTP message (header or chunk header) diff --git a/test/beast/core/async_op_base.cpp b/test/beast/core/async_op_base.cpp index 9993dbb8..c5abdcd7 100644 --- a/test/beast/core/async_op_base.cpp +++ b/test/beast/core/async_op_base.cpp @@ -13,6 +13,7 @@ #include "test_handler.hpp" #include +#include #include #include #include @@ -419,13 +420,28 @@ public: // invocation { - bool invoked = false; + net::io_context ioc; async_op_base< - final_handler, + test::handler, + net::io_context::executor_type> op( + test::any_handler(), ioc.get_executor()); + op.invoke(true); + } + { + net::io_context ioc; + async_op_base< + test::handler, + net::io_context::executor_type> op( + test::any_handler(), ioc.get_executor()); + op.invoke(false); + ioc.run(); + } + { + async_op_base< + test::handler, simple_executor> op( - final_handler{invoked}, {}); - op.invoke(); - BEAST_EXPECT(invoked); + test::any_handler(), {}); + op.invoke_now(); } // legacy hooks @@ -478,13 +494,28 @@ public: // invocation { - bool invoked = false; + net::io_context ioc; stable_async_op_base< - final_handler, + test::handler, + net::io_context::executor_type> op( + test::any_handler(), ioc.get_executor()); + op.invoke(true); + } + { + net::io_context ioc; + stable_async_op_base< + test::handler, + net::io_context::executor_type> op( + test::any_handler(), ioc.get_executor()); + op.invoke(false); + ioc.run(); + } + { + stable_async_op_base< + test::handler, simple_executor> op( - final_handler{invoked}, {}); - op.invoke(); - BEAST_EXPECT(invoked); + test::any_handler(), {}); + op.invoke_now(); } // legacy hooks diff --git a/test/beast/core/test_handler.hpp b/test/beast/core/test_handler.hpp index 19faa735..40d98346 100644 --- a/test/beast/core/test_handler.hpp +++ b/test/beast/core/test_handler.hpp @@ -7,8 +7,8 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_TEST_HANDLER_HPP -#define BOOST_BEAST_TEST_HANDLER_HPP +#ifndef BOOST_BEAST_TEST_HANDLER_XXX_HPP +#define BOOST_BEAST_TEST_HANDLER_XXX_HPP #include #include