From 3599ccb09a2268df4c4cb5d285f5f928fe9d4740 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Wed, 9 Jan 2019 16:11:15 -0800 Subject: [PATCH] Add tests for async_op_base --- CHANGELOG.md | 1 + .../_experimental/core/impl/flat_stream.hpp | 4 +- .../_experimental/http/impl/icy_stream.hpp | 4 +- include/boost/beast/core/async_op_base.hpp | 207 ++++++------ .../boost/beast/core/detail/async_op_base.hpp | 11 +- include/boost/beast/core/detail/impl/read.hpp | 10 +- .../beast/core/impl/basic_stream_socket.hpp | 8 +- .../beast/core/impl/buffered_read_stream.hpp | 2 +- .../boost/beast/http/impl/file_body_win32.ipp | 6 +- include/boost/beast/http/impl/read.ipp | 4 +- include/boost/beast/http/impl/write.ipp | 12 +- include/boost/beast/websocket/impl/accept.ipp | 8 +- include/boost/beast/websocket/impl/close.ipp | 4 +- .../boost/beast/websocket/impl/handshake.ipp | 4 +- include/boost/beast/websocket/impl/ping.ipp | 4 +- include/boost/beast/websocket/impl/read.ipp | 8 +- .../boost/beast/websocket/impl/teardown.ipp | 8 +- include/boost/beast/websocket/impl/write.ipp | 6 +- test/beast/core/CMakeLists.txt | 5 +- test/beast/core/async_op_base.cpp | 319 ++++++++++-------- test/beast/core/test_handler.hpp | 125 ++++++- 21 files changed, 454 insertions(+), 306 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 813eee6e..c679e9a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Version 202 * Use async_op_base * async_op_base is a public interface * Add tests for bind_back_handler +* Add tests for async_op_base -------------------------------------------------------------------------------- diff --git a/include/boost/beast/_experimental/core/impl/flat_stream.hpp b/include/boost/beast/_experimental/core/impl/flat_stream.hpp index b83b9266..8a15a309 100644 --- a/include/boost/beast/_experimental/core/impl/flat_stream.hpp +++ b/include/boost/beast/_experimental/core/impl/flat_stream.hpp @@ -61,8 +61,8 @@ public: Handler_&& h) : async_op_base>( - s.get_executor(), - std::forward(h)) + std::forward(h), + s.get_executor()) , s_(s) , b_(b) , p_(nullptr, deleter{alloc_type{}}) diff --git a/include/boost/beast/_experimental/http/impl/icy_stream.hpp b/include/boost/beast/_experimental/http/impl/icy_stream.hpp index 25e024b2..34501c3c 100644 --- a/include/boost/beast/_experimental/http/impl/icy_stream.hpp +++ b/include/boost/beast/_experimental/http/impl/icy_stream.hpp @@ -151,9 +151,9 @@ public: Handler_&& h, icy_stream& s, MutableBufferSequence const& b) - : beast::stable_async_op_base>( - s.get_executor(), std::forward(h)) + std::forward(h), s.get_executor()) , d_(beast::allocate_stable(*this, s, b)) { (*this)({}, 0); diff --git a/include/boost/beast/core/async_op_base.hpp b/include/boost/beast/core/async_op_base.hpp index 391f662d..d916608c 100644 --- a/include/boost/beast/core/async_op_base.hpp +++ b/include/boost/beast/core/async_op_base.hpp @@ -91,7 +91,7 @@ namespace beast { AsyncReadStream& stream, net::mutable_buffer buffer, handler_type& handler) - : base_type(stream.get_executor(), std::move(handler)) + : base_type(std::move(handler), stream.get_executor()) , stream_(stream) , buffer_(buffer) , total_bytes_transferred_(0) @@ -197,6 +197,56 @@ class async_op_base } public: + /** Constructor + + @param handler The final completion handler. The type of this + object must meet the requirements of CompletionHandler. + + @param ex1 The executor associated with the implied I/O object + target of the operation. The implementation shall maintain an + executor work guard for the lifetime of the operation, or until + the final completion handler is invoked, whichever is shorter. + + @param alloc The allocator to be associated with objects + derived from this class. If `Allocator` is default-constructible, + this parameter is optional and may be omitted. + */ +#if BOOST_BEAST_DOXYGEN + template + async_op_base( + Handler&& handler, + Executor1 const& ex1, + Allocator const& alloc = Allocator()); +#else + template< + class Handler_, + class = typename std::enable_if< + ! std::is_same::type, + async_op_base + >::value>::type + > + async_op_base( + Handler_&& handler, + Executor1 const& ex1) + : h_(std::forward(handler)) + , wg_(ex1) + { + } + + template + async_op_base( + Handler_&& handler, + Executor1 const& ex1, + Allocator const& alloc) + : boost::empty_value( + boost::empty_init_t{}, alloc) + , h_(std::forward(handler)) + , wg_(ex1) + { + } +#endif + /// Move Constructor async_op_base(async_op_base&& other) = default; @@ -264,56 +314,6 @@ public: return std::move(h_); } -protected: - /** Constructor - - @param handler The final completion handler. The type of this - object must meet the requirements of CompletionHandler. - - @param ex1 The executor associated with the implied I/O object - target of the operation. The implementation shall maintain an - executor work guard for the lifetime of the operation, or until - the final completion handler is invoked, whichever is shorter. - - @param alloc The allocator to be associated with objects - derived from this class. If `Allocator` is default-constructible, - this parameter is optional and may be omitted. - */ -#if BOOST_BEAST_DOXYGEN - template - async_op_base( - Executor1 const& ex1, - Handler&& handler, - Allocator const& alloc = Allocator()); -#else - template< - class Handler_, - class = typename std::enable_if< - ! std::is_same::type, - async_op_base - >::value>::type - > - async_op_base( - Executor1 const& ex1, - Handler_&& handler) - : h_(std::forward(handler)) - , wg_(ex1) - { - } - - template - async_op_base( - Executor1 const& ex1, - Handler_&& handler, - Allocator const& alloc) - : boost::empty_value(alloc) - , h_(std::forward(handler)) - , wg_(ex1) - { - } -#endif - /** Invoke the final completion handler. This invokes the final completion handler with the specified @@ -334,7 +334,6 @@ protected: } #if ! BOOST_BEAST_DOXYGEN -public: template< class Handler_, class Executor1_, @@ -480,7 +479,7 @@ public: enum { starting, waiting, writing } state_; op(AsyncWriteStream& stream, std::size_t repeats, std::string message, handler_type& handler) - : base_type(stream.get_executor(), std::move(handler)) + : base_type(std::move(handler), stream.get_executor()) , stream_(stream) , repeats_(repeats) , state_(starting) @@ -570,15 +569,6 @@ class stable_async_op_base } public: - /// Move Constructor - stable_async_op_base(stable_async_op_base&& other) - : async_op_base( - std::move(other)) - , list_(boost::exchange(other.list_, nullptr)) - { - } - -protected: /** Constructor @param handler The final completion handler. The type of this @@ -609,26 +599,34 @@ protected: >::value>::type > stable_async_op_base( - Executor1 const& ex1, - Handler_&& handler) + Handler_&& handler, + Executor1 const& ex1) : async_op_base< Handler, Executor1, Allocator>( - ex1, std::forward(handler)) + std::forward(handler), ex1) { } template stable_async_op_base( - Executor1 const& ex1, Handler_&& handler, + Executor1 const& ex1, Allocator const& alloc) : async_op_base< Handler, Executor1, Allocator>( - ex1, std::forward(handler)) + std::forward(handler), ex1, alloc) { } #endif + /// Move Constructor + stable_async_op_base(stable_async_op_base&& other) + : async_op_base( + std::move(other)) + , list_(boost::exchange(other.list_, nullptr)) + { + } + /** Destructor If the completion handler was not invoked, then any @@ -676,6 +674,40 @@ void asio_handler_invoke( } #endif +namespace detail { + +template +struct allocate_stable_state final + : stable_base + , boost::empty_value +{ + State value; + + template + explicit + allocate_stable_state( + Allocator const& alloc, + Args&&... args) + : boost::empty_value( + boost::empty_init_t{}, alloc) + , value{std::forward(args)...} + { + } + + void destroy() override + { + using A = typename allocator_traits< + Allocator>::template rebind_alloc< + allocate_stable_state>; + + A a(this->get()); + detail::allocator_traits::destroy(a, this); + detail::allocator_traits::deallocate(a, this, 1); + } +}; + +} // detail + /** Allocate a temporary object to hold stable asynchronous operation state. The object will be destroyed just before the completion @@ -695,44 +727,19 @@ allocate_stable( Handler, Executor1, Allocator>& base, Args&&... args) { - struct state; - using allocator_type = typename stable_async_op_base< Handler, Executor1, Allocator>::allocator_type; using A = typename detail::allocator_traits< - allocator_type>::template rebind_alloc; - - struct state final - : detail::stable_base - , boost::empty_value - { - State value; - - explicit - state( - allocator_type const& alloc, - detail::stable_base*& list, - Args&&... args) - : detail::stable_base(list) - , boost::empty_value( - boost::empty_init_t{}, alloc) - , value{std::forward(args)...} - { - } - - void destroy() override - { - A a(this->get()); - detail::allocator_traits::destroy(a, this); - detail::allocator_traits::deallocate(a, this, 1); - } - }; + allocator_type>::template rebind_alloc< + detail::allocate_stable_state< + State, allocator_type>>; struct deleter { allocator_type alloc; - state* ptr; + detail::allocate_stable_state< + State, allocator_type>* ptr; ~deleter() { @@ -748,9 +755,9 @@ allocate_stable( deleter d{base.get_allocator(), nullptr}; d.ptr = detail::allocator_traits::allocate(a, 1); detail::allocator_traits::construct(a, d.ptr, - d.alloc, - base.list_, - std::forward(args)...); + d.alloc, std::forward(args)...); + d.ptr->next_ = base.list_; + base.list_ = d.ptr; return boost::exchange(d.ptr, nullptr)->value; } diff --git a/include/boost/beast/core/detail/async_op_base.hpp b/include/boost/beast/core/detail/async_op_base.hpp index f35e9c76..4d23cd92 100644 --- a/include/boost/beast/core/detail/async_op_base.hpp +++ b/include/boost/beast/core/detail/async_op_base.hpp @@ -30,14 +30,13 @@ struct stable_base } } + stable_base* next_ = nullptr; + protected: - stable_base* next_; - virtual void destroy() = 0; + stable_base() = default; virtual ~stable_base() = default; - explicit stable_base(stable_base*& list) - : next_(boost::exchange(list, this)) - { - } + + virtual void destroy() = 0; }; } // detail diff --git a/include/boost/beast/core/detail/impl/read.hpp b/include/boost/beast/core/detail/impl/read.hpp index a35fc4a8..31941f53 100644 --- a/include/boost/beast/core/detail/impl/read.hpp +++ b/include/boost/beast/core/detail/impl/read.hpp @@ -18,9 +18,6 @@ #include #include -// REMOVE -#define BOOST_BEAST_ENABLE_NON_BLOCKING - namespace boost { namespace beast { namespace detail { @@ -56,9 +53,10 @@ public: DynamicBuffer& b, Condition cond, Handler_&& h) - : async_op_base< - Handler, get_executor_type>( - s.get_executor(), std::forward(h)) + : async_op_base>( + std::forward(h), + s.get_executor()) , s_(s) , b_(b) , cond_(cond) diff --git a/include/boost/beast/core/impl/basic_stream_socket.hpp b/include/boost/beast/core/impl/basic_stream_socket.hpp index 96da2c3c..806de4bd 100644 --- a/include/boost/beast/core/impl/basic_stream_socket.hpp +++ b/include/boost/beast/core/impl/basic_stream_socket.hpp @@ -107,7 +107,7 @@ public: Buffers const& b, Handler_&& h) : async_op_base( - s.get_executor(), std::forward(h)) + std::forward(h), s.get_executor()) , impl_(*s.impl_) , pg_(impl_.read_pending) , b_(b) @@ -224,7 +224,7 @@ public: Buffers const& b, Handler_&& h) : async_op_base( - s.get_executor(), std::forward(h)) + std::forward(h), s.get_executor()) , impl_(*s.impl_) , pg_(impl_.write_pending) , b_(b) @@ -350,7 +350,7 @@ public: Condition cond, Handler_&& h) : async_op_base( - s.get_executor(), std::forward(h)) + std::forward(h), s.get_executor()) , impl_(*s.impl_) , pg0_(impl_.read_pending) , pg1_(impl_.write_pending) @@ -377,7 +377,7 @@ public: Condition cond, Handler_&& h) : async_op_base( - s.get_executor(), std::forward(h)) + std::forward(h), s.get_executor()) , impl_(*s.impl_) , pg0_(impl_.read_pending) , pg1_(impl_.write_pending) diff --git a/include/boost/beast/core/impl/buffered_read_stream.hpp b/include/boost/beast/core/impl/buffered_read_stream.hpp index 320b3856..b91613f4 100644 --- a/include/boost/beast/core/impl/buffered_read_stream.hpp +++ b/include/boost/beast/core/impl/buffered_read_stream.hpp @@ -44,7 +44,7 @@ public: MutableBufferSequence const& b) : async_op_base< Handler, detail::get_executor_type>( - s.get_executor(), std::forward(h)) + std::forward(h), s.get_executor()) , s_(s) , b_(b) { diff --git a/include/boost/beast/http/impl/file_body_win32.ipp b/include/boost/beast/http/impl/file_body_win32.ipp index a23bad68..15dfd2cf 100644 --- a/include/boost/beast/http/impl/file_body_win32.ipp +++ b/include/boost/beast/http/impl/file_body_win32.ipp @@ -350,11 +350,11 @@ public: net::basic_stream_socket& s, serializer,Fields>& sr) - : beast::async_op_base< + : async_op_base< Handler, typename net::basic_stream_socket< Protocol>::executor_type>( - s.get_executor(), - std::forward(h)) + std::forward(h), + s.get_executor()) , sock_(s) , sr_(sr) { diff --git a/include/boost/beast/http/impl/read.ipp b/include/boost/beast/http/impl/read.ipp index 272a7c40..1d465f39 100644 --- a/include/boost/beast/http/impl/read.ipp +++ b/include/boost/beast/http/impl/read.ipp @@ -184,9 +184,9 @@ public: DynamicBuffer& b, message_type& m, Handler_&& h) - : beast::stable_async_op_base< + : stable_async_op_base< Handler, beast::detail::get_executor_type>( - s.get_executor(), std::forward(h)) + std::forward(h), s.get_executor()) , d_(beast::allocate_stable( *this, s, m)) { diff --git a/include/boost/beast/http/impl/write.ipp b/include/boost/beast/http/impl/write.ipp index adcf00d3..4833d3fc 100644 --- a/include/boost/beast/http/impl/write.ipp +++ b/include/boost/beast/http/impl/write.ipp @@ -72,9 +72,9 @@ public: Handler_&& h, Stream& s, serializer& sr) - : beast::async_op_base< + : async_op_base< Handler, beast::detail::get_executor_type>( - s.get_executor(), std::forward(h)) + std::forward(h), s.get_executor()) , s_(s) , sr_(sr) { @@ -168,9 +168,9 @@ public: Handler_&& h, Stream& s, serializer& sr) - : beast::async_op_base< + : async_op_base< Handler, beast::detail::get_executor_type>( - s.get_executor(), std::forward(h)) + std::forward(h), s.get_executor()) , s_(s) , sr_(sr) { @@ -229,9 +229,9 @@ public: Stream& s, Handler_&& h, Args&&... args) - : beast::stable_async_op_base< + : stable_async_op_base< Handler, beast::detail::get_executor_type>( - s.get_executor(), std::forward(h)) + std::forward(h), s.get_executor()) , s_(s) , sr_(beast::allocate_stable< serializer>( diff --git a/include/boost/beast/websocket/impl/accept.ipp b/include/boost/beast/websocket/impl/accept.ipp index b98168bc..2f8fada6 100644 --- a/include/boost/beast/websocket/impl/accept.ipp +++ b/include/boost/beast/websocket/impl/accept.ipp @@ -68,9 +68,9 @@ public: Handler_&& h, stream& ws, Args&&... args) - : beast::stable_async_op_base< + : stable_async_op_base< Handler, beast::detail::get_executor_type>( - ws.get_executor(), std::forward(h)) + std::forward(h), ws.get_executor()) , d_(beast::allocate_stable( *this, ws, std::forward(args)...)) { @@ -136,9 +136,9 @@ public: Handler_&& h, stream& ws, Args&&... args) - : beast::stable_async_op_base< + : stable_async_op_base< Handler, beast::detail::get_executor_type>( - ws.get_executor(), std::forward(h)) + std::forward(h), ws.get_executor()) , d_(beast::allocate_stable( *this, ws, std::forward(args)...)) { diff --git a/include/boost/beast/websocket/impl/close.ipp b/include/boost/beast/websocket/impl/close.ipp index 4066106d..8e4d927d 100644 --- a/include/boost/beast/websocket/impl/close.ipp +++ b/include/boost/beast/websocket/impl/close.ipp @@ -67,9 +67,9 @@ public: Handler_&& h, stream& ws, close_reason const& cr) - : beast::stable_async_op_base< + : stable_async_op_base< Handler, beast::detail::get_executor_type>( - ws.get_executor(), std::forward(h)) + std::forward(h), ws.get_executor()) , d_(beast::allocate_stable( *this, ws, cr)) { diff --git a/include/boost/beast/websocket/impl/handshake.ipp b/include/boost/beast/websocket/impl/handshake.ipp index 5d1764ad..884e1107 100644 --- a/include/boost/beast/websocket/impl/handshake.ipp +++ b/include/boost/beast/websocket/impl/handshake.ipp @@ -71,9 +71,9 @@ public: handshake_op( Handler_&& h, stream& ws, Args&&... args) - : beast::stable_async_op_base>( - ws.get_executor(), std::forward(h)) + std::forward(h), ws.get_executor()) , d_(beast::allocate_stable( *this, ws, std::forward(args)...)) { diff --git a/include/boost/beast/websocket/impl/ping.ipp b/include/boost/beast/websocket/impl/ping.ipp index 6c575ac8..1a9a5f64 100644 --- a/include/boost/beast/websocket/impl/ping.ipp +++ b/include/boost/beast/websocket/impl/ping.ipp @@ -66,9 +66,9 @@ public: stream& ws, detail::opcode op, ping_data const& payload) - : beast::stable_async_op_base< + : stable_async_op_base< Handler, beast::detail::get_executor_type>( - ws.get_executor(), std::forward(h)) + std::forward(h), ws.get_executor()) , d_(beast::allocate_stable( *this, ws, op, payload)) { diff --git a/include/boost/beast/websocket/impl/read.ipp b/include/boost/beast/websocket/impl/read.ipp index b5f4f39e..fb2b3345 100644 --- a/include/boost/beast/websocket/impl/read.ipp +++ b/include/boost/beast/websocket/impl/read.ipp @@ -98,9 +98,9 @@ public: Handler_&& h, stream& ws, MutableBufferSequence const& bs) - : beast::async_op_base< + : async_op_base< Handler, beast::detail::get_executor_type>( - ws.get_executor(), std::forward(h)) + std::forward(h), ws.get_executor()) , ws_(ws) , bs_(bs) , cb_(bs) @@ -690,9 +690,9 @@ public: DynamicBuffer& b, std::size_t limit, bool some) - : beast::async_op_base< + : async_op_base< Handler, beast::detail::get_executor_type>( - ws.get_executor(), std::forward(h)) + std::forward(h), ws.get_executor()) , ws_(ws) , b_(b) , limit_(limit ? limit : ( diff --git a/include/boost/beast/websocket/impl/teardown.ipp b/include/boost/beast/websocket/impl/teardown.ipp index fe8ab645..ff014169 100644 --- a/include/boost/beast/websocket/impl/teardown.ipp +++ b/include/boost/beast/websocket/impl/teardown.ipp @@ -43,10 +43,10 @@ public: Handler_&& h, socket_type& s, role_type role) - : beast::async_op_base< - Handler, beast::detail::get_executor_type< - net::ip::tcp::socket>>(s.get_executor(), - std::forward(h)) + : async_op_base>( + std::forward(h), s.get_executor()) , s_(s) , role_(role) { diff --git a/include/boost/beast/websocket/impl/write.ipp b/include/boost/beast/websocket/impl/write.ipp index caf5c95b..b2750927 100644 --- a/include/boost/beast/websocket/impl/write.ipp +++ b/include/boost/beast/websocket/impl/write.ipp @@ -161,9 +161,9 @@ public: stream& ws, bool fin, Buffers const& bs) - : beast::async_op_base< - Handler, beast::detail::get_executor_type>( - ws.get_executor(), std::forward(h)) + : beast::async_op_base>( + std::forward(h), ws.get_executor()) , ws_(ws) , cb_(bs) , fin_(fin) diff --git a/test/beast/core/CMakeLists.txt b/test/beast/core/CMakeLists.txt index 6fd539cd..cac9f85e 100644 --- a/test/beast/core/CMakeLists.txt +++ b/test/beast/core/CMakeLists.txt @@ -16,6 +16,9 @@ add_executable (tests-beast-core ${EXTRAS_FILES} ${TEST_MAIN} Jamfile + buffer_test.hpp + file_test.hpp + test_handler.hpp _detail_base64.cpp _detail_buffer.cpp _detail_clamp.cpp @@ -25,8 +28,6 @@ add_executable (tests-beast-core _detail_variant.cpp _detail_varint.cpp async_op_base.cpp - buffer_test.hpp - file_test.hpp basic_stream_socket.cpp bind_handler.cpp buffer_traits.cpp diff --git a/test/beast/core/async_op_base.cpp b/test/beast/core/async_op_base.cpp index 81086d51..b612fc97 100644 --- a/test/beast/core/async_op_base.cpp +++ b/test/beast/core/async_op_base.cpp @@ -10,6 +10,8 @@ // Test that header file is self-contained. #include +#include "test_handler.hpp" + #include #include #include @@ -19,6 +21,7 @@ #include #include #include +#include //------------------------------------------------------------------------------ @@ -104,61 +107,6 @@ struct handler { }; -struct legacy_handler -{ - bool invoked = false; - struct executor - { - void* context() { return nullptr; } - void on_work_started() {} - void on_work_finished() {} - template void dispatch(F&&) {} - template void post(F&&) {} - template void defer(F&&) {} - }; - - executor - get_executor() const noexcept - { - return {}; - }; -}; - -template -void -asio_handler_invoke( - Function&& f, - legacy_handler* p) -{ - p->invoked = true; - f(); -} - -void* -asio_handler_allocate( - std::size_t, - legacy_handler* p) -{ - p->invoked = true; - return nullptr; -} - -void -asio_handler_deallocate( - void*, std::size_t, - legacy_handler* p) -{ - p->invoked = true; -} - -bool -asio_handler_is_continuation( - legacy_handler* p) -{ - p->invoked = true; - return false; -} - } // (anon) } // beast @@ -207,35 +155,6 @@ struct associated_executor< } }; -template -struct associated_allocator< - boost::beast::legacy_handler, Allocator> -{ - using type = std::allocator; - - static type get( - boost::beast::legacy_handler const& h, - Allocator const& a = Allocator()) noexcept - { - return type{}; - } -}; - -template -struct associated_executor< - boost::beast::legacy_handler, Executor> -{ - using type = typename - boost::beast::legacy_handler::executor; - - static type get( - boost::beast::legacy_handler const&, - Executor const& = Executor()) noexcept - { - return type{}; - } -}; - } // asio } // boost @@ -436,75 +355,195 @@ public: net::system_executor // ignored >>::value); - struct test_op : async_op_base< - legacy_handler, ex1_type> + struct final_handler { - test_op() - : async_op_base< - legacy_handler, - ex1_type>( - ex1_type{}, legacy_handler{}) - { + bool& invoked; - } - - bool invoked() const noexcept + void + operator()() { - return this->handler().invoked; + invoked = true; } }; void - testLegacyHooks() + testBase() { - // asio_handler_invoke + // get_allocator + { + simple_allocator alloc; + simple_allocator alloc2; + async_op_base< + move_only_handler, + simple_executor, + simple_allocator> op( + move_only_handler{}, {}, alloc); + BEAST_EXPECT(op.get_allocator() == alloc); + BEAST_EXPECT(op.get_allocator() != alloc2); + } + + // get_executor + { + simple_executor ex; + simple_executor ex2; + async_op_base< + move_only_handler, + simple_executor> op( + move_only_handler{}, ex); + BEAST_EXPECT(op.get_executor() == ex); + BEAST_EXPECT(op.get_executor() != ex2); + } + + // move construction + { + async_op_base< + move_only_handler, + simple_executor> op( + move_only_handler{}, {}); + auto op2 = std::move(op); + } + + // observers + { + bool b = false; + async_op_base< + legacy_handler, + simple_executor> op( + legacy_handler{b}, {}); + BEAST_EXPECT(! op.handler().hook_invoked); + b = true; + BEAST_EXPECT(op.handler().hook_invoked); + b = false; + BEAST_EXPECT(! op.release_handler().hook_invoked); + } + + // invocation { - test_op h; - BEAST_EXPECT(! h.invoked()); bool invoked = false; - using net::asio_handler_invoke; - asio_handler_invoke( - [&invoked] - { - invoked =true; - }, &h); + async_op_base< + final_handler, + simple_executor> op( + final_handler{invoked}, {}); + op.invoke(); BEAST_EXPECT(invoked); - BEAST_EXPECT(h.invoked()); } - // asio_handler_allocate - { - test_op h; - BEAST_EXPECT(! h.invoked()); - using net::asio_handler_allocate; - asio_handler_allocate(0, &h); - BEAST_EXPECT(h.invoked()); - } - - // asio_handler_deallocate - { - test_op h; - BEAST_EXPECT(! h.invoked()); - using net::asio_handler_deallocate; - asio_handler_deallocate(nullptr, 0, &h); - BEAST_EXPECT(h.invoked()); - } - - // asio_handler_deallocate - { - test_op h; - BEAST_EXPECT(! h.invoked()); - using net::asio_handler_is_continuation; - asio_handler_is_continuation(&h); - BEAST_EXPECT(h.invoked()); - } + // legacy hooks + legacy_handler::test(*this, + [](legacy_handler h) + { + return async_op_base< + legacy_handler, + simple_executor>( + std::move(h), {}); + }); } void - testSpecialMembers() + testStableBase() { - test_op h1; - test_op h2(std::move(h1)); + // get_allocator + { + simple_allocator alloc; + simple_allocator alloc2; + stable_async_op_base< + move_only_handler, + simple_executor, + simple_allocator> op( + move_only_handler{}, {}, alloc); + BEAST_EXPECT(op.get_allocator() == alloc); + BEAST_EXPECT(op.get_allocator() != alloc2); + } + + // get_executor + { + simple_executor ex; + simple_executor ex2; + stable_async_op_base< + move_only_handler, + simple_executor> op( + move_only_handler{}, ex); + BEAST_EXPECT(op.get_executor() == ex); + BEAST_EXPECT(op.get_executor() != ex2); + } + + // move construction + { + stable_async_op_base< + move_only_handler, + simple_executor> op( + move_only_handler{}, {}); + auto op2 = std::move(op); + } + + // invocation + { + bool invoked = false; + stable_async_op_base< + final_handler, + simple_executor> op( + final_handler{invoked}, {}); + op.invoke(); + BEAST_EXPECT(invoked); + } + + // legacy hooks + legacy_handler::test(*this, + [](legacy_handler h) + { + return stable_async_op_base< + legacy_handler, + simple_executor>( + std::move(h), {}); + }); + + // allocate_stable + + { + bool destroyed = false; + { + struct data + { + bool& destroyed; + + ~data() + { + destroyed = true; + } + }; + stable_async_op_base< + move_only_handler, + simple_executor> op( + move_only_handler{}, {}); + BEAST_EXPECT(! destroyed); + auto& d = allocate_stable(op, destroyed); + BEAST_EXPECT(! d.destroyed); + } + BEAST_EXPECT(destroyed); + } + { + struct throwing_data + { + throwing_data() + { + BOOST_THROW_EXCEPTION( + std::exception{}); + } + }; + stable_async_op_base< + move_only_handler, + simple_executor> op( + move_only_handler{}, {}); + try + { + allocate_stable(op); + fail(); + } + catch(std::exception const&) + { + pass(); + } + } } //-------------------------------------------------------------------------- @@ -527,7 +566,7 @@ public: AsyncReadStream& stream, net::mutable_buffer buffer, handler_type& handler) - : base_type(stream.get_executor(), std::move(handler)) + : base_type(std::move(handler), stream.get_executor()) , stream_(stream) , buffer_(buffer) , total_bytes_transferred_(0) @@ -599,7 +638,7 @@ public: temporary_data& data_; op(AsyncWriteStream& stream, std::size_t repeats, std::string message, handler_type& handler) - : base_type(stream.get_executor(), std::move(handler)) + : base_type(std::move(handler), stream.get_executor()) , state_(starting) , stream_(stream) , repeats_(repeats) @@ -672,8 +711,8 @@ public: void run() override { - testLegacyHooks(); - testSpecialMembers(); + testBase(); + testStableBase(); testJavadocs(); } }; diff --git a/test/beast/core/test_handler.hpp b/test/beast/core/test_handler.hpp index 62170c84..7770276b 100644 --- a/test/beast/core/test_handler.hpp +++ b/test/beast/core/test_handler.hpp @@ -21,22 +21,90 @@ namespace boost { namespace beast { +class simple_allocator +{ + std::size_t id_; + +public: + simple_allocator() + : id_([] + { + static std::size_t n = 0; + return ++n; + }()) + { + } + + friend + bool operator==( + simple_allocator const& lhs, + simple_allocator const& rhs) noexcept + { + return lhs.id_ == rhs.id_; + } + + friend + bool operator!=( + simple_allocator const& lhs, + simple_allocator const& rhs) noexcept + { + return lhs.id_ != rhs.id_; + } +}; + +class simple_executor +{ + std::size_t id_; + +public: + simple_executor() + : id_([] + { + static std::size_t n = 0; + return ++n; + }()) + { + } + + void* context() { return nullptr; } + void on_work_started() {} + void on_work_finished() {} + template void dispatch(F&&) {} + template void post(F&&) {} + template void defer(F&&) {} + + friend + bool operator==( + simple_executor const& lhs, + simple_executor const& rhs) noexcept + { + return lhs.id_ == rhs.id_; + } + + friend + bool operator!=( + simple_executor const& lhs, + simple_executor const& rhs) noexcept + { + return lhs.id_ != rhs.id_; + } +}; + +// A move-only handler +struct move_only_handler +{ + move_only_handler() = default; + move_only_handler(move_only_handler&&) = default; + move_only_handler(move_only_handler const&) = delete; + void operator()() const{}; +}; + // Used to test the legacy handler hooks struct legacy_handler { bool& hook_invoked; - struct executor - { - void* context() { return nullptr; } - void on_work_started() {} - void on_work_finished() {} - template void dispatch(F&&) {} - template void post(F&&) {} - template void defer(F&&) {} - }; - - executor + simple_executor get_executor() const noexcept { return {}; @@ -126,4 +194,39 @@ asio_handler_is_continuation( } // beast } // boost +namespace boost { +namespace asio { + +template +struct associated_allocator< + boost::beast::legacy_handler, Allocator> +{ + using type = std::allocator; + + static type get( + boost::beast::legacy_handler const& h, + Allocator const& a = Allocator()) noexcept + { + return type{}; + } +}; + +template +struct associated_executor< + boost::beast::legacy_handler, Executor> +{ + using type = typename + boost::beast::simple_executor; + + static type get( + boost::beast::legacy_handler const&, + Executor const& = Executor()) noexcept + { + return type{}; + } +}; + +} // asio +} // boost + #endif