diff options
Diffstat (limited to 'boost/asio/impl')
36 files changed, 5146 insertions, 1202 deletions
diff --git a/boost/asio/impl/awaitable.hpp b/boost/asio/impl/awaitable.hpp new file mode 100644 index 0000000000..b8cf5373a1 --- /dev/null +++ b/boost/asio/impl/awaitable.hpp @@ -0,0 +1,424 @@ +// +// impl/awaitable.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 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_AWAITABLE_HPP +#define BOOST_ASIO_IMPL_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <exception> +#include <new> +#include <tuple> +#include <utility> +#include <boost/asio/detail/thread_context.hpp> +#include <boost/asio/detail/thread_info_base.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/post.hpp> +#include <boost/system/system_error.hpp> +#include <boost/asio/this_coro.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +// An awaitable_thread represents a thread-of-execution that is composed of one +// or more "stack frames", with each frame represented by an awaitable_frame. +// All execution occurs in the context of the awaitable_thread's executor. An +// awaitable_thread continues to "pump" the stack frames by repeatedly resuming +// the top stack frame until the stack is empty, or until ownership of the +// stack is transferred to another awaitable_thread object. +// +// +------------------------------------+ +// | top_of_stack_ | +// | V +// +--------------+---+ +-----------------+ +// | | | | +// | awaitable_thread |<---------------------------+ awaitable_frame | +// | | attached_thread_ | | +// +--------------+---+ (Set only when +---+-------------+ +// | frames are being | +// | actively pumped | caller_ +// | by a thread, and | +// | then only for V +// | the top frame.) +-----------------+ +// | | | +// | | awaitable_frame | +// | | | +// | +---+-------------+ +// | | +// | | caller_ +// | : +// | : +// | | +// | V +// | +-----------------+ +// | bottom_of_stack_ | | +// +------------------------------->| awaitable_frame | +// | | +// +-----------------+ + +template <typename Executor> +class awaitable_frame_base +{ +public: +#if !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING) + void* operator new(std::size_t size) + { + return boost::asio::detail::thread_info_base::allocate( + boost::asio::detail::thread_info_base::awaitable_frame_tag(), + boost::asio::detail::thread_context::thread_call_stack::top(), + size); + } + + void operator delete(void* pointer, std::size_t size) + { + boost::asio::detail::thread_info_base::deallocate( + boost::asio::detail::thread_info_base::awaitable_frame_tag(), + boost::asio::detail::thread_context::thread_call_stack::top(), + pointer, size); + } +#endif // !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING) + + // The frame starts in a suspended state until the awaitable_thread object + // pumps the stack. + auto initial_suspend() noexcept + { + return suspend_always(); + } + + // On final suspension the frame is popped from the top of the stack. + auto final_suspend() noexcept + { + struct result + { + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return false; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + this_->pop_frame(); + } + + void await_resume() const noexcept + { + } + }; + + return result{this}; + } + + void set_except(std::exception_ptr e) noexcept + { + pending_exception_ = e; + } + + void set_error(const boost::system::error_code& ec) + { + this->set_except(std::make_exception_ptr(boost::system::system_error(ec))); + } + + void unhandled_exception() + { + set_except(std::current_exception()); + } + + void rethrow_exception() + { + if (pending_exception_) + { + std::exception_ptr ex = std::exchange(pending_exception_, nullptr); + std::rethrow_exception(ex); + } + } + + template <typename T> + auto await_transform(awaitable<T, Executor> a) const + { + return a; + } + + // This await transformation obtains the associated executor of the thread of + // execution. + auto await_transform(this_coro::executor_t) noexcept + { + struct result + { + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + } + + auto await_resume() const noexcept + { + return this_->attached_thread_->get_executor(); + } + }; + + return result{this}; + } + + // This await transformation is used to run an async operation's initiation + // function object after the coroutine has been suspended. This ensures that + // immediate resumption of the coroutine in another thread does not cause a + // race condition. + template <typename Function> + auto await_transform(Function f, + typename enable_if< + is_convertible< + typename result_of<Function(awaitable_frame_base*)>::type, + awaitable_thread<Executor>* + >::value + >::type* = 0) + { + struct result + { + Function function_; + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return false; + } + + void await_suspend(coroutine_handle<void>) noexcept + { + function_(this_); + } + + void await_resume() const noexcept + { + } + }; + + return result{std::move(f), this}; + } + + void attach_thread(awaitable_thread<Executor>* handler) noexcept + { + attached_thread_ = handler; + } + + awaitable_thread<Executor>* detach_thread() noexcept + { + return std::exchange(attached_thread_, nullptr); + } + + void push_frame(awaitable_frame_base<Executor>* caller) noexcept + { + caller_ = caller; + attached_thread_ = caller_->attached_thread_; + attached_thread_->top_of_stack_ = this; + caller_->attached_thread_ = nullptr; + } + + void pop_frame() noexcept + { + if (caller_) + caller_->attached_thread_ = attached_thread_; + attached_thread_->top_of_stack_ = caller_; + attached_thread_ = nullptr; + caller_ = nullptr; + } + + void resume() + { + coro_.resume(); + } + + void destroy() + { + coro_.destroy(); + } + +protected: + coroutine_handle<void> coro_ = nullptr; + awaitable_thread<Executor>* attached_thread_ = nullptr; + awaitable_frame_base<Executor>* caller_ = nullptr; + std::exception_ptr pending_exception_ = nullptr; +}; + +template <typename T, typename Executor> +class awaitable_frame + : public awaitable_frame_base<Executor> +{ +public: + awaitable_frame() noexcept + { + } + + awaitable_frame(awaitable_frame&& other) noexcept + : awaitable_frame_base<Executor>(std::move(other)) + { + } + + ~awaitable_frame() + { + if (has_result_) + static_cast<T*>(static_cast<void*>(result_))->~T(); + } + + awaitable<T, Executor> get_return_object() noexcept + { + this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this); + return awaitable<T, Executor>(this); + }; + + template <typename U> + void return_value(U&& u) + { + new (&result_) T(std::forward<U>(u)); + has_result_ = true; + } + + template <typename... Us> + void return_values(Us&&... us) + { + this->return_value(std::forward_as_tuple(std::forward<Us>(us)...)); + } + + T get() + { + this->caller_ = nullptr; + this->rethrow_exception(); + return std::move(*static_cast<T*>(static_cast<void*>(result_))); + } + +private: + alignas(T) unsigned char result_[sizeof(T)]; + bool has_result_ = false; +}; + +template <typename Executor> +class awaitable_frame<void, Executor> + : public awaitable_frame_base<Executor> +{ +public: + awaitable<void, Executor> get_return_object() + { + this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this); + return awaitable<void, Executor>(this); + }; + + void return_void() + { + } + + void get() + { + this->caller_ = nullptr; + this->rethrow_exception(); + } +}; + +template <typename Executor> +class awaitable_thread +{ +public: + typedef Executor executor_type; + + // Construct from the entry point of a new thread of execution. + awaitable_thread(awaitable<void, Executor> p, const Executor& ex) + : bottom_of_stack_(std::move(p)), + top_of_stack_(bottom_of_stack_.frame_), + executor_(ex) + { + } + + // Transfer ownership from another awaitable_thread. + awaitable_thread(awaitable_thread&& other) noexcept + : bottom_of_stack_(std::move(other.bottom_of_stack_)), + top_of_stack_(std::exchange(other.top_of_stack_, nullptr)), + executor_(std::move(other.executor_)) + { + } + + // Clean up with a last ditch effort to ensure the thread is unwound within + // the context of the executor. + ~awaitable_thread() + { + if (bottom_of_stack_.valid()) + { + // Coroutine "stack unwinding" must be performed through the executor. + (post)(executor_, + [a = std::move(bottom_of_stack_)]() mutable + { + awaitable<void, Executor>(std::move(a)); + }); + } + } + + executor_type get_executor() const noexcept + { + return executor_; + } + + // Launch a new thread of execution. + void launch() + { + top_of_stack_->attach_thread(this); + pump(); + } + +protected: + template <typename> friend class awaitable_frame_base; + + // Repeatedly resume the top stack frame until the stack is empty or until it + // has been transferred to another resumable_thread object. + void pump() + { + do top_of_stack_->resume(); while (top_of_stack_); + if (bottom_of_stack_.valid()) + { + awaitable<void, Executor> a(std::move(bottom_of_stack_)); + a.frame_->rethrow_exception(); + } + } + + awaitable<void, Executor> bottom_of_stack_; + awaitable_frame_base<Executor>* top_of_stack_; + executor_type executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#if !defined(GENERATING_DOCUMENTATION) + +namespace std { namespace experimental { + +template <typename T, typename Executor, typename... Args> +struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...> +{ + typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type; +}; + +}} // namespace std::experimental + +#endif // !defined(GENERATING_DOCUMENTATION) + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_AWAITABLE_HPP diff --git a/boost/asio/impl/buffered_read_stream.hpp b/boost/asio/impl/buffered_read_stream.hpp index 2e1c55842b..6a51d8ee56 100644 --- a/boost/asio/impl/buffered_read_stream.hpp +++ b/boost/asio/impl/buffered_read_stream.hpp @@ -2,7 +2,7 @@ // impl/buffered_read_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -21,6 +21,7 @@ #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/push_options.hpp> @@ -138,6 +139,28 @@ namespace detail boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_buffered_fill + { + template <typename ReadHandler, typename Stream> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + buffered_stream_storage* storage, Stream* next_layer) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + std::size_t previous_size = storage->size(); + storage->resize(storage->capacity()); + next_layer->async_read_some( + buffer( + storage->data() + previous_size, + storage->size() - previous_size), + buffered_fill_handler<typename decay<ReadHandler>::type>( + *storage, previous_size, handler2.value)); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) @@ -177,24 +200,9 @@ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, buffered_read_stream<Stream>::async_fill( BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - std::size_t previous_size = storage_.size(); - storage_.resize(storage_.capacity()); - next_layer_.async_read_some( - buffer( - storage_.data() + previous_size, - storage_.size() - previous_size), - detail::buffered_fill_handler<BOOST_ASIO_HANDLER_TYPE( - ReadHandler, void (boost::system::error_code, std::size_t))>( - storage_, previous_size, init.completion_handler)); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_buffered_fill(), handler, &storage_, &next_layer_); } template <typename Stream> @@ -327,6 +335,38 @@ namespace detail boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_buffered_read_some + { + template <typename ReadHandler, typename Stream, + typename MutableBufferSequence> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + buffered_stream_storage* storage, Stream* next_layer, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + using boost::asio::buffer_size; + non_const_lvalue<ReadHandler> handler2(handler); + if (buffer_size(buffers) == 0 || !storage->empty()) + { + next_layer->async_read_some(BOOST_ASIO_MUTABLE_BUFFER(0, 0), + buffered_read_some_handler<MutableBufferSequence, + typename decay<ReadHandler>::type>( + *storage, buffers, handler2.value)); + } + else + { + initiate_async_buffered_fill()( + buffered_read_some_handler<MutableBufferSequence, + typename decay<ReadHandler>::type>( + *storage, buffers, handler2.value), + storage, next_layer); + } + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) @@ -375,31 +415,10 @@ buffered_read_stream<Stream>::async_read_some( const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - using boost::asio::buffer_size; - if (buffer_size(buffers) == 0 || !storage_.empty()) - { - next_layer_.async_read_some(BOOST_ASIO_MUTABLE_BUFFER(0, 0), - detail::buffered_read_some_handler< - MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE( - ReadHandler, void (boost::system::error_code, std::size_t))>( - storage_, buffers, init.completion_handler)); - } - else - { - this->async_fill(detail::buffered_read_some_handler< - MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE( - ReadHandler, void (boost::system::error_code, std::size_t))>( - storage_, buffers, init.completion_handler)); - } - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_buffered_read_some(), + handler, &storage_, &next_layer_, buffers); } template <typename Stream> diff --git a/boost/asio/impl/buffered_write_stream.hpp b/boost/asio/impl/buffered_write_stream.hpp index c5ebf7537b..05d4406347 100644 --- a/boost/asio/impl/buffered_write_stream.hpp +++ b/boost/asio/impl/buffered_write_stream.hpp @@ -2,7 +2,7 @@ // impl/buffered_write_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -21,6 +21,7 @@ #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/push_options.hpp> @@ -124,6 +125,23 @@ namespace detail boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_buffered_flush + { + template <typename WriteHandler, typename Stream> + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + buffered_stream_storage* storage, Stream* next_layer) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + async_write(*next_layer, buffer(storage->data(), storage->size()), + buffered_flush_handler<typename decay<WriteHandler>::type>( + *storage, handler2.value)); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) @@ -163,19 +181,10 @@ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, buffered_write_stream<Stream>::async_flush( BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - async_write(next_layer_, buffer(storage_.data(), storage_.size()), - detail::buffered_flush_handler<BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - storage_, init.completion_handler)); - - return init.result.get(); + return async_initiate<WriteHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_buffered_flush(), + handler, &storage_, &next_layer_); } template <typename Stream> @@ -314,6 +323,38 @@ namespace detail boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_buffered_write_some + { + template <typename WriteHandler, typename Stream, + typename ConstBufferSequence> + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + buffered_stream_storage* storage, Stream* next_layer, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + using boost::asio::buffer_size; + non_const_lvalue<WriteHandler> handler2(handler); + if (buffer_size(buffers) == 0 || storage->size() < storage->capacity()) + { + next_layer->async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0), + buffered_write_some_handler<ConstBufferSequence, + typename decay<WriteHandler>::type>( + *storage, buffers, handler2.value)); + } + else + { + initiate_async_buffered_flush()( + buffered_write_some_handler<ConstBufferSequence, + typename decay<WriteHandler>::type>( + *storage, buffers, handler2.value), + storage, next_layer); + } + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) @@ -362,32 +403,10 @@ buffered_write_stream<Stream>::async_write_some( const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - using boost::asio::buffer_size; - if (buffer_size(buffers) == 0 - || storage_.size() < storage_.capacity()) - { - next_layer_.async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0), - detail::buffered_write_some_handler< - ConstBufferSequence, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - storage_, buffers, init.completion_handler)); - } - else - { - this->async_flush(detail::buffered_write_some_handler< - ConstBufferSequence, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - storage_, buffers, init.completion_handler)); - } - - return init.result.get(); + return async_initiate<WriteHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_buffered_write_some(), + handler, &storage_, &next_layer_, buffers); } template <typename Stream> diff --git a/boost/asio/impl/co_spawn.hpp b/boost/asio/impl/co_spawn.hpp new file mode 100644 index 0000000000..19770cd865 --- /dev/null +++ b/boost/asio/impl/co_spawn.hpp @@ -0,0 +1,140 @@ +// +// impl/co_spawn.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 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_CO_SPAWN_HPP +#define BOOST_ASIO_IMPL_CO_SPAWN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/awaitable.hpp> +#include <boost/asio/dispatch.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/use_awaitable.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename T, typename Executor, typename F, typename Handler> +awaitable<void, Executor> co_spawn_entry_point( + awaitable<T, Executor>*, Executor ex, F f, Handler handler) +{ + auto spawn_work = make_work_guard(ex); + auto handler_work = make_work_guard(handler, ex); + + (void) co_await (post)(spawn_work.get_executor(), + use_awaitable_t<Executor>{}); + + bool done = false; + try + { + T t = co_await f(); + + done = true; + + (dispatch)(handler_work.get_executor(), + [handler = std::move(handler), t = std::move(t)]() mutable + { + handler(std::exception_ptr(), std::move(t)); + }); + } + catch (...) + { + if (done) + throw; + + (dispatch)(handler_work.get_executor(), + [handler = std::move(handler), e = std::current_exception()]() mutable + { + handler(e, T()); + }); + } +} + +template <typename Executor, typename F, typename Handler> +awaitable<void, Executor> co_spawn_entry_point( + awaitable<void, Executor>*, Executor ex, F f, Handler handler) +{ + auto spawn_work = make_work_guard(ex); + auto handler_work = make_work_guard(handler, ex); + + (void) co_await (post)(spawn_work.get_executor(), + use_awaitable_t<Executor>{}); + + std::exception_ptr e = nullptr; + try + { + co_await f(); + } + catch (...) + { + e = std::current_exception(); + } + + (dispatch)(handler_work.get_executor(), + [handler = std::move(handler), e]() mutable + { + handler(e); + }); +} + +struct initiate_co_spawn +{ + template <typename Handler, typename Executor, typename F> + void operator()(Handler&& handler, const Executor& ex, F&& f) const + { + typedef typename result_of<F()>::type awaitable_type; + typedef typename awaitable_type::executor_type executor_type; + + executor_type ex2(ex); + auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr), + ex2, std::forward<F>(f), std::forward<Handler>(handler)); + awaitable_handler<executor_type, void>(std::move(a), ex2).launch(); + } +}; + +} // namespace detail + +template <typename Executor, typename F, typename CompletionToken> +inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature<typename result_of<F()>::type>::type) +co_spawn(const Executor& ex, F&& f, CompletionToken&& token, + typename enable_if< + is_executor<Executor>::value + >::type*) +{ + return async_initiate<CompletionToken, + typename detail::awaitable_signature<typename result_of<F()>::type>>( + detail::initiate_co_spawn(), token, ex, std::forward<F>(f)); +} + +template <typename ExecutionContext, typename F, typename CompletionToken> +inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature<typename result_of<F()>::type>::type) +co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token, + typename enable_if< + is_convertible<ExecutionContext&, execution_context&>::value + >::type*) +{ + return (co_spawn)(ctx.get_executor(), std::forward<F>(f), + std::forward<CompletionToken>(token)); +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_CO_SPAWN_HPP diff --git a/boost/asio/impl/compose.hpp b/boost/asio/impl/compose.hpp new file mode 100644 index 0000000000..76fe54d066 --- /dev/null +++ b/boost/asio/impl/compose.hpp @@ -0,0 +1,421 @@ +// +// impl/compose.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 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_COMPOSE_HPP +#define BOOST_ASIO_IMPL_COMPOSE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/handler_cont_helpers.hpp> +#include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/detail/variadic_templates.hpp> +#include <boost/asio/executor_work_guard.hpp> +#include <boost/asio/is_executor.hpp> +#include <boost/asio/system_executor.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +namespace detail +{ + template <typename> + struct composed_work; + + template <> + struct composed_work<void()> + { + composed_work() BOOST_ASIO_NOEXCEPT + : head_(system_executor()) + { + } + + void reset() + { + head_.reset(); + } + + typedef system_executor head_type; + executor_work_guard<system_executor> head_; + }; + + inline composed_work<void()> make_composed_work() + { + return composed_work<void()>(); + } + + template <typename Head> + struct composed_work<void(Head)> + { + explicit composed_work(const Head& ex) BOOST_ASIO_NOEXCEPT + : head_(ex) + { + } + + void reset() + { + head_.reset(); + } + + typedef Head head_type; + executor_work_guard<Head> head_; + }; + + template <typename Head> + inline composed_work<void(Head)> make_composed_work(const Head& head) + { + return composed_work<void(Head)>(head); + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Head, typename... Tail> + struct composed_work<void(Head, Tail...)> + { + explicit composed_work(const Head& head, + const Tail&... tail) BOOST_ASIO_NOEXCEPT + : head_(head), + tail_(tail...) + { + } + + void reset() + { + head_.reset(); + tail_.reset(); + } + + typedef Head head_type; + executor_work_guard<Head> head_; + composed_work<void(Tail...)> tail_; + }; + + template <typename Head, typename... Tail> + inline composed_work<void(Head, Tail...)> + make_composed_work(const Head& head, const Tail&... tail) + { + return composed_work<void(Head, Tail...)>(head, tail...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF(n) \ + template <typename Head, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + struct composed_work<void(Head, BOOST_ASIO_VARIADIC_TARGS(n))> \ + { \ + explicit composed_work(const Head& head, \ + BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) BOOST_ASIO_NOEXCEPT \ + : head_(head), \ + tail_(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) \ + { \ + } \ + \ + void reset() \ + { \ + head_.reset(); \ + tail_.reset(); \ + } \ + \ + typedef Head head_type; \ + executor_work_guard<Head> head_; \ + composed_work<void(BOOST_ASIO_VARIADIC_TARGS(n))> tail_; \ + }; \ + \ + template <typename Head, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + inline composed_work<void(Head, BOOST_ASIO_VARIADIC_TARGS(n))> \ + make_composed_work(const Head& head, BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) \ + { \ + return composed_work< \ + void(Head, BOOST_ASIO_VARIADIC_TARGS(n))>( \ + head, BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF) +#undef BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + template <typename Impl, typename Work, typename Handler, typename Signature> + class composed_op; + + template <typename Impl, typename Work, typename Handler, + typename R, typename... Args> + class composed_op<Impl, Work, Handler, R(Args...)> +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + template <typename Impl, typename Work, typename Handler, typename Signature> + class composed_op +#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)), + invocations_(0) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + composed_op(composed_op&& other) + : impl_(BOOST_ASIO_MOVE_CAST(Impl)(other.impl_)), + work_(BOOST_ASIO_MOVE_CAST(Work)(other.work_)), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + invocations_(other.invocations_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + typedef typename associated_executor<Handler, + typename Work::head_type>::type executor_type; + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return (get_associated_executor)(handler_, work_.head_.get_executor()); + } + + typedef typename associated_allocator<Handler, + std::allocator<void> >::type allocator_type; + + allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT + { + return (get_associated_allocator)(handler_, std::allocator<void>()); + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template<typename... T> + void operator()(BOOST_ASIO_MOVE_ARG(T)... t) + { + if (invocations_ < ~unsigned(0)) + ++invocations_; + impl_(*this, BOOST_ASIO_MOVE_CAST(T)(t)...); + } + + void complete(Args... args) + { + this->work_.reset(); + this->handler_(BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + void operator()() + { + if (invocations_ < ~unsigned(0)) + ++invocations_; + impl_(*this); + } + + void complete() + { + this->work_.reset(); + this->handler_(); + } + +#define BOOST_ASIO_PRIVATE_COMPOSED_OP_DEF(n) \ + template<BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + if (invocations_ < ~unsigned(0)) \ + ++invocations_; \ + impl_(*this, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template<BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + void complete(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + this->work_.reset(); \ + this->handler_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_COMPOSED_OP_DEF) +#undef BOOST_ASIO_PRIVATE_COMPOSED_OP_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + //private: + Impl impl_; + Work work_; + Handler handler_; + unsigned invocations_; + }; + + template <typename Impl, typename Work, typename Handler, typename Signature> + inline void* asio_handler_allocate(std::size_t size, + composed_op<Impl, Work, Handler, Signature>* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename Impl, typename Work, typename Handler, typename Signature> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + composed_op<Impl, Work, Handler, Signature>* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Impl, typename Work, typename Handler, typename Signature> + inline bool asio_handler_is_continuation( + composed_op<Impl, Work, Handler, Signature>* this_handler) + { + return this_handler->invocations_ > 1 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename Impl, + typename Work, typename Handler, typename Signature> + inline void asio_handler_invoke(Function& function, + composed_op<Impl, Work, Handler, Signature>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename Impl, + typename Work, typename Handler, typename Signature> + inline void asio_handler_invoke(const Function& function, + composed_op<Impl, Work, Handler, Signature>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Signature> + struct initiate_composed_op + { + template <typename Handler, typename Impl, typename Work> + void operator()(BOOST_ASIO_MOVE_ARG(Handler) handler, + BOOST_ASIO_MOVE_ARG(Impl) impl, + BOOST_ASIO_MOVE_ARG(Work) work) const + { + composed_op<typename decay<Impl>::type, typename decay<Work>::type, + typename decay<Handler>::type, Signature>( + BOOST_ASIO_MOVE_CAST(Impl)(impl), BOOST_ASIO_MOVE_CAST(Work)(work), + BOOST_ASIO_MOVE_CAST(Handler)(handler))(); + } + }; + + template <typename IoObject> + inline typename IoObject::executor_type + get_composed_io_executor(IoObject& io_object) + { + return io_object.get_executor(); + } + + template <typename Executor> + inline const Executor& get_composed_io_executor(const Executor& ex, + typename enable_if<is_executor<Executor>::value>::type* = 0) + { + return ex; + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename CompletionToken, typename Signature, + typename Implementation, typename... IoObjectsOrExecutors> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, + BOOST_ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors) +{ + return async_initiate<CompletionToken, Signature>( + detail::initiate_composed_op<Signature>(), token, + BOOST_ASIO_MOVE_CAST(Implementation)(implementation), + detail::make_composed_work( + detail::get_composed_io_executor( + BOOST_ASIO_MOVE_CAST(IoObjectsOrExecutors)( + io_objects_or_executors))...)); +} + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename CompletionToken, typename Signature, typename Implementation> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token) +{ + return async_initiate<CompletionToken, Signature>( + detail::initiate_composed_op<Signature>(), token, + BOOST_ASIO_MOVE_CAST(Implementation)(implementation), + detail::make_composed_work()); +} + +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n) \ + BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_##n + +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_1 \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T1)(x1)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_2 \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T1)(x1)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T2)(x2)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_3 \ + 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)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_4 \ + 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)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_5 \ + 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)) + +#define BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \ + template <typename CompletionToken, typename Signature, \ + typename Implementation, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) \ + async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, \ + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return async_initiate<CompletionToken, Signature>( \ + detail::initiate_composed_op<Signature>(), token, \ + BOOST_ASIO_MOVE_CAST(Implementation)(implementation), \ + detail::make_composed_work( \ + BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n))); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF) +#undef BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF + +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_1 +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_2 +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_3 +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_4 +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_5 + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_COMPOSE_HPP diff --git a/boost/asio/impl/connect.hpp b/boost/asio/impl/connect.hpp index 497f25884c..51e5e6cb16 100644 --- a/boost/asio/impl/connect.hpp +++ b/boost/asio/impl/connect.hpp @@ -2,7 +2,7 @@ // impl/connect.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -23,6 +23,7 @@ #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/post.hpp> @@ -101,9 +102,8 @@ namespace detail } } -template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename EndpointSequence> -typename Protocol::endpoint connect( - basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename EndpointSequence> +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, typename enable_if<is_endpoint_sequence< EndpointSequence>::value>::type*) @@ -114,9 +114,8 @@ typename Protocol::endpoint connect( return result; } -template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename EndpointSequence> -typename Protocol::endpoint connect( - basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename EndpointSequence> +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, boost::system::error_code& ec, typename enable_if<is_endpoint_sequence< EndpointSequence>::value>::type*) @@ -127,8 +126,8 @@ typename Protocol::endpoint connect( } #if !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> -Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, +template <typename Protocol, typename Executor, typename Iterator> +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { boost::system::error_code ec; @@ -137,8 +136,8 @@ Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, return result; } -template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> -inline Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename Iterator> +inline Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, boost::system::error_code& ec, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { @@ -146,8 +145,8 @@ inline Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> -Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename Iterator> +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end) { boost::system::error_code ec; @@ -156,17 +155,16 @@ Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, return result; } -template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> -inline Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +template <typename Protocol, typename Executor, typename Iterator> +inline Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, boost::system::error_code& ec) { return connect(s, begin, end, detail::default_connect_condition(), ec); } -template <typename Protocol BOOST_ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition> -typename Protocol::endpoint connect( - basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, typename enable_if<is_endpoint_sequence< EndpointSequence>::value>::type*) @@ -178,10 +176,9 @@ typename Protocol::endpoint connect( return result; } -template <typename Protocol BOOST_ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition> -typename Protocol::endpoint connect( - basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, boost::system::error_code& ec, typename enable_if<is_endpoint_sequence< @@ -193,9 +190,9 @@ typename Protocol::endpoint connect( } #if !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol BOOST_ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { @@ -205,9 +202,9 @@ Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, return result; } -template <typename Protocol BOOST_ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -inline Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +inline Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, boost::system::error_code& ec, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) @@ -216,10 +213,10 @@ inline Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol BOOST_ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, - Iterator begin, Iterator end, ConnectCondition connect_condition) +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, + Iterator end, ConnectCondition connect_condition) { boost::system::error_code ec; Iterator result = connect(s, begin, end, connect_condition, ec); @@ -227,10 +224,10 @@ Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, return result; } -template <typename Protocol BOOST_ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, - Iterator begin, Iterator end, ConnectCondition connect_condition, +Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, + Iterator end, ConnectCondition connect_condition, boost::system::error_code& ec) { ec = boost::system::error_code(); @@ -295,13 +292,12 @@ namespace detail } }; - template <typename Protocol BOOST_ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler> + template <typename Protocol, typename Executor, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> class range_connect_op : base_from_connect_condition<ConnectCondition> { public: - range_connect_op(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& sock, + range_connect_op(basic_socket<Protocol, Executor>& sock, const EndpointSequence& endpoints, const ConnectCondition& connect_condition, RangeConnectHandler& handler) @@ -338,10 +334,18 @@ namespace detail void operator()(boost::system::error_code ec, int start = 0) { - typename EndpointSequence::const_iterator begin = endpoints_.begin(); - typename EndpointSequence::const_iterator iter = begin; + this->process(ec, start, + const_cast<const EndpointSequence&>(endpoints_).begin(), + const_cast<const EndpointSequence&>(endpoints_).end()); + } + + //private: + template <typename Iterator> + void process(boost::system::error_code ec, + int start, Iterator begin, Iterator end) + { + Iterator iter = begin; std::advance(iter, index_); - typename EndpointSequence::const_iterator end = endpoints_.end(); switch (start_ = start) { @@ -392,75 +396,92 @@ namespace detail } } - //private: - basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket_; + basic_socket<Protocol, Executor>& socket_; EndpointSequence endpoints_; std::size_t index_; int start_; RangeConnectHandler handler_; }; - template <typename Protocol BOOST_ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler> + template <typename Protocol, typename Executor, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> inline void* asio_handler_allocate(std::size_t size, - range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename Protocol BOOST_ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler> + template <typename Protocol, typename Executor, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename Protocol BOOST_ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler> + template <typename Protocol, typename Executor, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> inline bool asio_handler_is_continuation( - range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename Protocol - BOOST_ASIO_SVC_TPARAM, typename EndpointSequence, - typename ConnectCondition, typename RangeConnectHandler> + template <typename Function, typename Executor, typename Protocol, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler> inline void asio_handler_invoke(Function& function, - range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename Protocol - BOOST_ASIO_SVC_TPARAM, typename EndpointSequence, - typename ConnectCondition, typename RangeConnectHandler> + template <typename Function, typename Executor, typename Protocol, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler> inline void asio_handler_invoke(const Function& function, - range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + struct initiate_async_range_connect + { + template <typename RangeConnectHandler, typename Protocol, + typename Executor, typename EndpointSequence, typename ConnectCondition> + void operator()(BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + basic_socket<Protocol, Executor>* s, const EndpointSequence& endpoints, + const ConnectCondition& connect_condition) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for an + // RangeConnectHandler. + BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK(RangeConnectHandler, + handler, typename Protocol::endpoint) type_check; + + non_const_lvalue<RangeConnectHandler> handler2(handler); + range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, + typename decay<RangeConnectHandler>::type>(*s, endpoints, + connect_condition, handler2.value)(boost::system::error_code(), 1); + } + }; + + template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> class iterator_connect_op : base_from_connect_condition<ConnectCondition> { public: - iterator_connect_op(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& sock, + iterator_connect_op(basic_socket<Protocol, Executor>& sock, const Iterator& begin, const Iterator& end, const ConnectCondition& connect_condition, IteratorConnectHandler& handler) @@ -544,82 +565,101 @@ namespace detail } //private: - basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket_; + basic_socket<Protocol, Executor>& socket_; Iterator iter_; Iterator end_; int start_; IteratorConnectHandler handler_; }; - template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline void* asio_handler_allocate(std::size_t size, - iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline bool asio_handler_is_continuation( - iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename Protocol - BOOST_ASIO_SVC_TPARAM, typename Iterator, - typename ConnectCondition, typename IteratorConnectHandler> + template <typename Function, typename Executor, typename Protocol, + typename Iterator, typename ConnectCondition, + typename IteratorConnectHandler> inline void asio_handler_invoke(Function& function, - iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename Protocol - BOOST_ASIO_SVC_TPARAM, typename Iterator, - typename ConnectCondition, typename IteratorConnectHandler> + template <typename Function, typename Executor, typename Protocol, + typename Iterator, typename ConnectCondition, + typename IteratorConnectHandler> inline void asio_handler_invoke(const Function& function, - iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_iterator_connect + { + template <typename IteratorConnectHandler, typename Protocol, + typename Executor, typename Iterator, typename ConnectCondition> + void operator()(BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + basic_socket<Protocol, Executor>* s, Iterator begin, + Iterator end, const ConnectCondition& connect_condition) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for an + // IteratorConnectHandler. + BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; + + non_const_lvalue<IteratorConnectHandler> handler2(handler); + iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, + typename decay<IteratorConnectHandler>::type>(*s, begin, end, + connect_condition, handler2.value)(boost::system::error_code(), 1); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename Protocol BOOST_ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler, typename Allocator> +template <typename Protocol, typename Executor, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler, typename Allocator> struct associated_allocator< - detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, - EndpointSequence, ConnectCondition, RangeConnectHandler>, - Allocator> + detail::range_connect_op<Protocol, Executor, EndpointSequence, + ConnectCondition, RangeConnectHandler>, Allocator> { typedef typename associated_allocator< RangeConnectHandler, Allocator>::type type; static type get( - const detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, - EndpointSequence, ConnectCondition, RangeConnectHandler>& h, + const detail::range_connect_op<Protocol, Executor, EndpointSequence, + ConnectCondition, RangeConnectHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<RangeConnectHandler, @@ -627,40 +667,38 @@ struct associated_allocator< } }; -template <typename Protocol BOOST_ASIO_SVC_TPARAM, - typename EndpointSequence, typename ConnectCondition, - typename RangeConnectHandler, typename Executor> +template <typename Protocol, typename Executor, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler, typename Executor1> struct associated_executor< - detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, - EndpointSequence, ConnectCondition, RangeConnectHandler>, - Executor> + detail::range_connect_op<Protocol, Executor, EndpointSequence, + ConnectCondition, RangeConnectHandler>, Executor1> { typedef typename associated_executor< - RangeConnectHandler, Executor>::type type; + RangeConnectHandler, Executor1>::type type; static type get( - const detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, - EndpointSequence, ConnectCondition, RangeConnectHandler>& h, - const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + const detail::range_connect_op<Protocol, Executor, EndpointSequence, + ConnectCondition, RangeConnectHandler>& h, + const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT { return associated_executor<RangeConnectHandler, - Executor>::get(h.handler_, ex); + Executor1>::get(h.handler_, ex); } }; -template <typename Protocol BOOST_ASIO_SVC_TPARAM, - typename Iterator, typename ConnectCondition, - typename IteratorConnectHandler, typename Allocator> +template <typename Protocol, typename Executor, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler, + typename Allocator> struct associated_allocator< - detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, - ConnectCondition, IteratorConnectHandler>, + detail::iterator_connect_op<Protocol, Executor, + Iterator, ConnectCondition, IteratorConnectHandler>, Allocator> { typedef typename associated_allocator< IteratorConnectHandler, Allocator>::type type; static type get( - const detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, + const detail::iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { @@ -669,189 +707,119 @@ struct associated_allocator< } }; -template <typename Protocol BOOST_ASIO_SVC_TPARAM, - typename Iterator, typename ConnectCondition, - typename IteratorConnectHandler, typename Executor> +template <typename Protocol, typename Executor, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler, + typename Executor1> struct associated_executor< - detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, - ConnectCondition, IteratorConnectHandler>, - Executor> + detail::iterator_connect_op<Protocol, Executor, + Iterator, ConnectCondition, IteratorConnectHandler>, + Executor1> { typedef typename associated_executor< - IteratorConnectHandler, Executor>::type type; + IteratorConnectHandler, Executor1>::type type; static type get( - const detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, + const detail::iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>& h, - const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT { return associated_executor<IteratorConnectHandler, - Executor>::get(h.handler_, ex); + Executor1>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) -template <typename Protocol BOOST_ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename EndpointSequence, typename RangeConnectHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)) -async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, typename enable_if<is_endpoint_sequence< EndpointSequence>::value>::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a RangeConnectHandler. - BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( - RangeConnectHandler, handler, typename Protocol::endpoint) type_check; - - async_completion<RangeConnectHandler, - void (boost::system::error_code, typename Protocol::endpoint)> - init(handler); - - detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, - detail::default_connect_condition, - BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler, - void (boost::system::error_code, typename Protocol::endpoint))>(s, - endpoints, detail::default_connect_condition(), - init.completion_handler)(boost::system::error_code(), 1); - - return init.result.get(); + return async_initiate<RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)>( + detail::initiate_async_range_connect(), handler, + &s, endpoints, detail::default_connect_condition()); } #if !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol BOOST_ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename IteratorConnectHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, - Iterator begin, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, +async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a IteratorConnectHandler. - BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( - IteratorConnectHandler, handler, Iterator) type_check; - - async_completion<IteratorConnectHandler, - void (boost::system::error_code, Iterator)> init(handler); - - detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, - detail::default_connect_condition, BOOST_ASIO_HANDLER_TYPE( - IteratorConnectHandler, void (boost::system::error_code, Iterator))>(s, - begin, Iterator(), detail::default_connect_condition(), - init.completion_handler)(boost::system::error_code(), 1); - - return init.result.get(); + return async_initiate<IteratorConnectHandler, + void (boost::system::error_code, Iterator)>( + detail::initiate_async_iterator_connect(), handler, + &s, begin, Iterator(), detail::default_connect_condition()); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol BOOST_ASIO_SVC_TPARAM, +template <typename Protocol, typename Executor, typename Iterator, typename IteratorConnectHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, - Iterator begin, Iterator end, +async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a IteratorConnectHandler. - BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( - IteratorConnectHandler, handler, Iterator) type_check; - - async_completion<IteratorConnectHandler, - void (boost::system::error_code, Iterator)> init(handler); - - detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, - detail::default_connect_condition, BOOST_ASIO_HANDLER_TYPE( - IteratorConnectHandler, void (boost::system::error_code, Iterator))>(s, - begin, end, detail::default_connect_condition(), - init.completion_handler)(boost::system::error_code(), 1); - - return init.result.get(); + return async_initiate<IteratorConnectHandler, + void (boost::system::error_code, Iterator)>( + detail::initiate_async_iterator_connect(), handler, + &s, begin, end, detail::default_connect_condition()); } -template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename EndpointSequence, +template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition, typename RangeConnectHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)) -async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, +async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, typename enable_if<is_endpoint_sequence< EndpointSequence>::value>::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a RangeConnectHandler. - BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( - RangeConnectHandler, handler, typename Protocol::endpoint) type_check; - - async_completion<RangeConnectHandler, - void (boost::system::error_code, typename Protocol::endpoint)> - init(handler); - - detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, - ConnectCondition, BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler, - void (boost::system::error_code, typename Protocol::endpoint))>(s, - endpoints, connect_condition, init.completion_handler)( - boost::system::error_code(), 1); - - return init.result.get(); + return async_initiate<RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)>( + detail::initiate_async_range_connect(), + handler, &s, endpoints, connect_condition); } #if !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, - Iterator begin, ConnectCondition connect_condition, +async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, + ConnectCondition connect_condition, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a IteratorConnectHandler. - BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( - IteratorConnectHandler, handler, Iterator) type_check; - - async_completion<IteratorConnectHandler, - void (boost::system::error_code, Iterator)> init(handler); - - detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, - ConnectCondition, BOOST_ASIO_HANDLER_TYPE( - IteratorConnectHandler, void (boost::system::error_code, Iterator))>(s, - begin, Iterator(), connect_condition, init.completion_handler)( - boost::system::error_code(), 1); - - return init.result.get(); + return async_initiate<IteratorConnectHandler, + void (boost::system::error_code, Iterator)>( + detail::initiate_async_iterator_connect(), + handler, &s, begin, Iterator(), connect_condition); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, +template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, - Iterator begin, Iterator end, ConnectCondition connect_condition, +async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, + Iterator end, ConnectCondition connect_condition, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a IteratorConnectHandler. - BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( - IteratorConnectHandler, handler, Iterator) type_check; - - async_completion<IteratorConnectHandler, - void (boost::system::error_code, Iterator)> init(handler); - - detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, - ConnectCondition, BOOST_ASIO_HANDLER_TYPE( - IteratorConnectHandler, void (boost::system::error_code, Iterator))>(s, - begin, end, connect_condition, init.completion_handler)( - boost::system::error_code(), 1); - - return init.result.get(); + return async_initiate<IteratorConnectHandler, + void (boost::system::error_code, Iterator)>( + detail::initiate_async_iterator_connect(), + handler, &s, begin, end, connect_condition); } } // namespace asio diff --git a/boost/asio/impl/defer.hpp b/boost/asio/impl/defer.hpp index 7cc86da45c..856a33c788 100644 --- a/boost/asio/impl/defer.hpp +++ b/boost/asio/impl/defer.hpp @@ -2,7 +2,7 @@ // impl/defer.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -24,24 +24,46 @@ namespace boost { namespace asio { +namespace detail { -template <typename CompletionToken> -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( - BOOST_ASIO_MOVE_ARG(CompletionToken) token) +struct initiate_defer { - typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + template <typename CompletionHandler> + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + { + typedef typename decay<CompletionHandler>::type DecayedHandler; + + typename associated_executor<DecayedHandler>::type ex( + (get_associated_executor)(handler)); - async_completion<CompletionToken, void()> init(token); + typename associated_allocator<DecayedHandler>::type alloc( + (get_associated_allocator)(handler)); - typename associated_executor<handler>::type ex( - (get_associated_executor)(init.completion_handler)); + ex.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); + } - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); + template <typename CompletionHandler, typename Executor> + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + BOOST_ASIO_MOVE_ARG(Executor) ex) const + { + typedef typename decay<CompletionHandler>::type DecayedHandler; - ex.defer(BOOST_ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); + typename associated_allocator<DecayedHandler>::type alloc( + (get_associated_allocator)(handler)); - return init.result.get(); + ex.defer(detail::work_dispatcher<DecayedHandler>( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); + } +}; + +} // namespace detail + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + return async_initiate<CompletionToken, void()>( + detail::initiate_defer(), token); } template <typename Executor, typename CompletionToken> @@ -49,16 +71,8 @@ BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if<is_executor<Executor>::value>::type*) { - typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; - - async_completion<CompletionToken, void()> init(token); - - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); - - ex.defer(detail::work_dispatcher<handler>(init.completion_handler), alloc); - - return init.result.get(); + return async_initiate<CompletionToken, void()>( + detail::initiate_defer(), token, ex); } template <typename ExecutionContext, typename CompletionToken> diff --git a/boost/asio/impl/detached.hpp b/boost/asio/impl/detached.hpp new file mode 100644 index 0000000000..ae2c882fba --- /dev/null +++ b/boost/asio/impl/detached.hpp @@ -0,0 +1,132 @@ +// +// impl/detached.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 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_DETACHED_HPP +#define BOOST_ASIO_IMPL_DETACHED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/async_result.hpp> +#include <boost/asio/detail/variadic_templates.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + + // Class to adapt a detached_t as a completion handler. + class detached_handler + { + public: + typedef void result_type; + + detached_handler(detached_t) + { + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename... Args> + void operator()(Args...) + { + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + void operator()() + { + } + +#define BOOST_ASIO_PRIVATE_DETACHED_DEF(n) \ + template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(BOOST_ASIO_VARIADIC_TARGS(n)) \ + { \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_DETACHED_DEF) +#undef BOOST_ASIO_PRIVATE_DETACHED_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + }; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Signature> +struct async_result<detached_t, Signature> +{ + typedef boost::asio::detail::detached_handler completion_handler_type; + + typedef void return_type; + + explicit async_result(completion_handler_type&) + { + } + + void get() + { + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken), + BOOST_ASIO_MOVE_ARG(Args)... args) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( + detail::detached_handler(detached_t()), + BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Initiation, typename RawCompletionToken> + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken)) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( + detail::detached_handler(detached_t())); + } + +#define BOOST_ASIO_PRIVATE_INITIATE_DEF(n) \ + template <typename Initiation, typename RawCompletionToken, \ + BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + static return_type initiate( \ + BOOST_ASIO_MOVE_ARG(Initiation) initiation, \ + BOOST_ASIO_MOVE_ARG(RawCompletionToken), \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( \ + detail::detached_handler(detached_t()), \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INITIATE_DEF) +#undef BOOST_ASIO_PRIVATE_INITIATE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_DETACHED_HPP diff --git a/boost/asio/impl/dispatch.hpp b/boost/asio/impl/dispatch.hpp index 8bdce85180..bcba2ee401 100644 --- a/boost/asio/impl/dispatch.hpp +++ b/boost/asio/impl/dispatch.hpp @@ -2,7 +2,7 @@ // impl/dispatch.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -24,24 +24,46 @@ namespace boost { namespace asio { +namespace detail { -template <typename CompletionToken> -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( - BOOST_ASIO_MOVE_ARG(CompletionToken) token) +struct initiate_dispatch { - typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + template <typename CompletionHandler> + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + { + typedef typename decay<CompletionHandler>::type DecayedHandler; + + typename associated_executor<DecayedHandler>::type ex( + (get_associated_executor)(handler)); - async_completion<CompletionToken, void()> init(token); + typename associated_allocator<DecayedHandler>::type alloc( + (get_associated_allocator)(handler)); - typename associated_executor<handler>::type ex( - (get_associated_executor)(init.completion_handler)); + ex.dispatch(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); + } - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); + template <typename CompletionHandler, typename Executor> + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + BOOST_ASIO_MOVE_ARG(Executor) ex) const + { + typedef typename decay<CompletionHandler>::type DecayedHandler; - ex.dispatch(BOOST_ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); + typename associated_allocator<DecayedHandler>::type alloc( + (get_associated_allocator)(handler)); - return init.result.get(); + ex.dispatch(detail::work_dispatcher<DecayedHandler>( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); + } +}; + +} // namespace detail + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + return async_initiate<CompletionToken, void()>( + detail::initiate_dispatch(), token); } template <typename Executor, typename CompletionToken> @@ -49,17 +71,8 @@ BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if<is_executor<Executor>::value>::type*) { - typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; - - async_completion<CompletionToken, void()> init(token); - - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); - - ex.dispatch(detail::work_dispatcher<handler>( - init.completion_handler), alloc); - - return init.result.get(); + return async_initiate<CompletionToken, void()>( + detail::initiate_dispatch(), token, ex); } template <typename ExecutionContext, typename CompletionToken> diff --git a/boost/asio/impl/error.ipp b/boost/asio/impl/error.ipp index 49a10462bd..0dcb1257c7 100644 --- a/boost/asio/impl/error.ipp +++ b/boost/asio/impl/error.ipp @@ -2,7 +2,7 @@ // impl/error.ipp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) diff --git a/boost/asio/impl/execution_context.hpp b/boost/asio/impl/execution_context.hpp index eadf36b145..a1617f8c9c 100644 --- a/boost/asio/impl/execution_context.hpp +++ b/boost/asio/impl/execution_context.hpp @@ -2,7 +2,7 @@ // impl/execution_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -24,6 +24,8 @@ namespace boost { namespace asio { +#if !defined(GENERATING_DOCUMENTATION) + template <typename Service> inline Service& use_service(execution_context& e) { @@ -33,8 +35,7 @@ inline Service& use_service(execution_context& e) return e.service_registry_->template use_service<Service>(); } -#if !defined(GENERATING_DOCUMENTATION) -# if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Service, typename... Args> Service& make_service(execution_context& e, BOOST_ASIO_MOVE_ARG(Args)... args) @@ -47,7 +48,7 @@ Service& make_service(execution_context& e, BOOST_ASIO_MOVE_ARG(Args)... args) return result; } -# else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Service> Service& make_service(execution_context& e) @@ -75,8 +76,7 @@ Service& make_service(execution_context& e) BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF) #undef BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF -# endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) -#endif // !defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Service> inline void add_service(execution_context& e, Service* svc) @@ -96,6 +96,8 @@ inline bool has_service(execution_context& e) return e.service_registry_->template has_service<Service>(); } +#endif // !defined(GENERATING_DOCUMENTATION) + inline execution_context& execution_context::service::context() { return owner_; diff --git a/boost/asio/impl/execution_context.ipp b/boost/asio/impl/execution_context.ipp index 219a66113d..30e7bb926f 100644 --- a/boost/asio/impl/execution_context.ipp +++ b/boost/asio/impl/execution_context.ipp @@ -2,7 +2,7 @@ // impl/execution_context.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) diff --git a/boost/asio/impl/executor.hpp b/boost/asio/impl/executor.hpp index 106763b042..b1c6cd748f 100644 --- a/boost/asio/impl/executor.hpp +++ b/boost/asio/impl/executor.hpp @@ -2,7 +2,7 @@ // impl/executor.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -17,7 +17,7 @@ #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/atomic_count.hpp> -#include <boost/asio/detail/executor_op.hpp> +#include <boost/asio/detail/executor_function.hpp> #include <boost/asio/detail/global.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/recycling_allocator.hpp> @@ -41,36 +41,37 @@ public: explicit function(F f, const Alloc& a) { // Allocate and construct an operation to wrap the function. - typedef detail::executor_op<F, Alloc> op; - typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; - op_ = new (p.v) op(BOOST_ASIO_MOVE_CAST(F)(f), a); + typedef detail::executor_function<F, Alloc> 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) - : op_(other.op_) + function(function&& other) BOOST_ASIO_NOEXCEPT + : func_(other.func_) { - other.op_ = 0; + other.func_ = 0; } ~function() { - if (op_) - op_->destroy(); + if (func_) + func_->destroy(); } void operator()() { - if (op_) + if (func_) { - detail::scheduler_operation* op = op_; - op_ = 0; - op->complete(this, boost::system::error_code(), 0); + detail::executor_function_base* func = func_; + func_ = 0; + func->complete(); } } private: - detail::scheduler_operation* op_; + detail::executor_function_base* func_; }; #else // defined(BOOST_ASIO_HAS_MOVE) diff --git a/boost/asio/impl/executor.ipp b/boost/asio/impl/executor.ipp index 86114d93f1..289265d706 100644 --- a/boost/asio/impl/executor.ipp +++ b/boost/asio/impl/executor.ipp @@ -2,7 +2,7 @@ // impl/executor.ipp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) diff --git a/boost/asio/impl/handler_alloc_hook.ipp b/boost/asio/impl/handler_alloc_hook.ipp index 2b04ec104e..a580f71ffa 100644 --- a/boost/asio/impl/handler_alloc_hook.ipp +++ b/boost/asio/impl/handler_alloc_hook.ipp @@ -2,7 +2,7 @@ // impl/handler_alloc_hook.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) diff --git a/boost/asio/impl/io_context.hpp b/boost/asio/impl/io_context.hpp index 37f8ace42a..2cf8c4bc8d 100644 --- a/boost/asio/impl/io_context.hpp +++ b/boost/asio/impl/io_context.hpp @@ -2,7 +2,7 @@ // impl/io_context.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -19,6 +19,7 @@ #include <boost/asio/detail/executor_op.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/recycling_allocator.hpp> #include <boost/asio/detail/service_registry.hpp> #include <boost/asio/detail/throw_error.hpp> @@ -26,6 +27,8 @@ #include <boost/asio/detail/push_options.hpp> +#if !defined(GENERATING_DOCUMENTATION) + namespace boost { namespace asio { @@ -49,6 +52,8 @@ inline detail::io_context_impl& use_service<detail::io_context_impl>( } // namespace asio } // namespace boost +#endif // !defined(GENERATING_DOCUMENTATION) + #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HAS_IOCP) @@ -130,70 +135,87 @@ inline void io_context::reset() restart(); } +struct io_context::initiate_dispatch +{ + template <typename LegacyCompletionHandler> + void operator()(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler, + io_context* self) const + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a LegacyCompletionHandler. + BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler); + if (self->impl_.can_dispatch()) + { + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke( + handler2.value, handler2.value); + } + else + { + // Allocate and construct an operation to wrap the handler. + typedef detail::completion_handler< + typename decay<LegacyCompletionHandler>::type> op; + typename op::ptr p = { detail::addressof(handler2.value), + op::ptr::allocate(handler2.value), 0 }; + p.p = new (p.v) op(handler2.value); + + BOOST_ASIO_HANDLER_CREATION((*self, *p.p, + "io_context", self, 0, "dispatch")); + + self->impl_.do_dispatch(p.p); + p.v = p.p = 0; + } + } +}; + template <typename LegacyCompletionHandler> BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) io_context::dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a LegacyCompletionHandler. - BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( - LegacyCompletionHandler, handler) type_check; - - async_completion<LegacyCompletionHandler, void ()> init(handler); + return async_initiate<LegacyCompletionHandler, void ()>( + initiate_dispatch(), handler, this); +} - if (impl_.can_dispatch()) - { - detail::fenced_block b(detail::fenced_block::full); - boost_asio_handler_invoke_helpers::invoke( - init.completion_handler, init.completion_handler); - } - else +struct io_context::initiate_post +{ + template <typename LegacyCompletionHandler> + void operator()(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler, + io_context* self) const { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a LegacyCompletionHandler. + BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler); + + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler2.value); + // Allocate and construct an operation to wrap the handler. typedef detail::completion_handler< - typename handler_type<LegacyCompletionHandler, void ()>::type> op; - typename op::ptr p = { detail::addressof(init.completion_handler), - op::ptr::allocate(init.completion_handler), 0 }; - p.p = new (p.v) op(init.completion_handler); + typename decay<LegacyCompletionHandler>::type> op; + typename op::ptr p = { detail::addressof(handler2.value), + op::ptr::allocate(handler2.value), 0 }; + p.p = new (p.v) op(handler2.value); - BOOST_ASIO_HANDLER_CREATION((*this, *p.p, - "io_context", this, 0, "dispatch")); + BOOST_ASIO_HANDLER_CREATION((*self, *p.p, + "io_context", self, 0, "post")); - impl_.do_dispatch(p.p); + self->impl_.post_immediate_completion(p.p, is_continuation); p.v = p.p = 0; } - - return init.result.get(); -} +}; template <typename LegacyCompletionHandler> BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) io_context::post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a LegacyCompletionHandler. - BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( - LegacyCompletionHandler, handler) type_check; - - async_completion<LegacyCompletionHandler, void ()> init(handler); - - bool is_continuation = - boost_asio_handler_cont_helpers::is_continuation(init.completion_handler); - - // Allocate and construct an operation to wrap the handler. - typedef detail::completion_handler< - typename handler_type<LegacyCompletionHandler, void ()>::type> op; - typename op::ptr p = { detail::addressof(init.completion_handler), - op::ptr::allocate(init.completion_handler), 0 }; - p.p = new (p.v) op(init.completion_handler); - - BOOST_ASIO_HANDLER_CREATION((*this, *p.p, - "io_context", this, 0, "post")); - - impl_.post_immediate_completion(p.p, is_continuation); - p.v = p.p = 0; - - return init.result.get(); + return async_initiate<LegacyCompletionHandler, void ()>( + initiate_post(), handler, this); } template <typename Handler> @@ -320,11 +342,6 @@ inline boost::asio::io_context& io_context::work::get_io_context() { return static_cast<boost::asio::io_context&>(io_context_impl_.context()); } - -inline boost::asio::io_context& io_context::work::get_io_service() -{ - return static_cast<boost::asio::io_context&>(io_context_impl_.context()); -} #endif // !defined(BOOST_ASIO_NO_DEPRECATED) inline boost::asio::io_context& io_context::service::get_io_context() @@ -332,13 +349,6 @@ inline boost::asio::io_context& io_context::service::get_io_context() return static_cast<boost::asio::io_context&>(context()); } -#if !defined(BOOST_ASIO_NO_DEPRECATED) -inline boost::asio::io_context& io_context::service::get_io_service() -{ - return static_cast<boost::asio::io_context&>(context()); -} -#endif // !defined(BOOST_ASIO_NO_DEPRECATED) - } // namespace asio } // namespace boost diff --git a/boost/asio/impl/io_context.ipp b/boost/asio/impl/io_context.ipp index 96a7de7415..5de07181d4 100644 --- a/boost/asio/impl/io_context.ipp +++ b/boost/asio/impl/io_context.ipp @@ -2,7 +2,7 @@ // impl/io_context.ipp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -35,13 +35,14 @@ namespace boost { namespace asio { io_context::io_context() - : impl_(add_impl(new impl_type(*this, BOOST_ASIO_CONCURRENCY_HINT_DEFAULT))) + : impl_(add_impl(new impl_type(*this, + BOOST_ASIO_CONCURRENCY_HINT_DEFAULT, false))) { } io_context::io_context(int concurrency_hint) : impl_(add_impl(new impl_type(*this, concurrency_hint == 1 - ? BOOST_ASIO_CONCURRENCY_HINT_1 : concurrency_hint))) + ? BOOST_ASIO_CONCURRENCY_HINT_1 : concurrency_hint, false))) { } diff --git a/boost/asio/impl/post.hpp b/boost/asio/impl/post.hpp index d318f890ff..ac0831e532 100644 --- a/boost/asio/impl/post.hpp +++ b/boost/asio/impl/post.hpp @@ -2,7 +2,7 @@ // impl/post.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -24,24 +24,46 @@ namespace boost { namespace asio { +namespace detail { -template <typename CompletionToken> -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( - BOOST_ASIO_MOVE_ARG(CompletionToken) token) +struct initiate_post { - typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + template <typename CompletionHandler> + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + { + typedef typename decay<CompletionHandler>::type DecayedHandler; + + typename associated_executor<DecayedHandler>::type ex( + (get_associated_executor)(handler)); - async_completion<CompletionToken, void()> init(token); + typename associated_allocator<DecayedHandler>::type alloc( + (get_associated_allocator)(handler)); - typename associated_executor<handler>::type ex( - (get_associated_executor)(init.completion_handler)); + ex.post(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); + } - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); + template <typename CompletionHandler, typename Executor> + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + BOOST_ASIO_MOVE_ARG(Executor) ex) const + { + typedef typename decay<CompletionHandler>::type DecayedHandler; - ex.post(BOOST_ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); + typename associated_allocator<DecayedHandler>::type alloc( + (get_associated_allocator)(handler)); - return init.result.get(); + ex.post(detail::work_dispatcher<DecayedHandler>( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); + } +}; + +} // namespace detail + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + return async_initiate<CompletionToken, void()>( + detail::initiate_post(), token); } template <typename Executor, typename CompletionToken> @@ -49,16 +71,8 @@ BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if<is_executor<Executor>::value>::type*) { - typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; - - async_completion<CompletionToken, void()> init(token); - - typename associated_allocator<handler>::type alloc( - (get_associated_allocator)(init.completion_handler)); - - ex.post(detail::work_dispatcher<handler>(init.completion_handler), alloc); - - return init.result.get(); + return async_initiate<CompletionToken, void()>( + detail::initiate_post(), token, ex); } template <typename ExecutionContext, typename CompletionToken> diff --git a/boost/asio/impl/read.hpp b/boost/asio/impl/read.hpp index 9fbddc964e..6eabf0f616 100644 --- a/boost/asio/impl/read.hpp +++ b/boost/asio/impl/read.hpp @@ -2,7 +2,7 @@ // impl/read.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -29,6 +29,7 @@ #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> @@ -69,7 +70,8 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, >::type*) { return detail::read_buffer_sequence(s, buffers, - boost::asio::buffer_sequence_begin(buffers), completion_condition, ec); + boost::asio::buffer_sequence_begin(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); } template <typename SyncReadStream, typename MutableBufferSequence> @@ -103,22 +105,26 @@ inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, >::type*) { boost::system::error_code ec; - std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); + std::size_t bytes_transferred = read(s, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); boost::asio::detail::throw_error(ec, "read"); return bytes_transferred; } -template <typename SyncReadStream, typename DynamicBuffer, +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition> std::size_t read(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, boost::system::error_code& ec, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { - typename decay<DynamicBuffer>::type b( - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + typename decay<DynamicBuffer_v1>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); ec = boost::system::error_code(); std::size_t total_transferred = 0; @@ -141,45 +147,48 @@ std::size_t read(SyncReadStream& s, return total_transferred; } -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = read(s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), transfer_all(), ec); + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), ec); boost::asio::detail::throw_error(ec, "read"); return bytes_transferred; } -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, boost::system::error_code& ec, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { - return read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + return read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), ec); } -template <typename SyncReadStream, typename DynamicBuffer, +template <typename SyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition> inline std::size_t read(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = read(s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), - completion_condition, ec); + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); boost::asio::detail::throw_error(ec, "read"); return bytes_transferred; } @@ -193,7 +202,8 @@ inline std::size_t read(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, boost::system::error_code& ec) { - return read(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); + return read(s, basic_streambuf_ref<Allocator>(b), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); } template <typename SyncReadStream, typename Allocator> @@ -217,11 +227,87 @@ inline std::size_t read(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition) { - return read(s, basic_streambuf_ref<Allocator>(b), completion_condition); + return read(s, basic_streambuf_ref<Allocator>(b), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + DynamicBuffer_v2& b = buffers; + + ec = boost::system::error_code(); + std::size_t total_transferred = 0; + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(max_size, b.max_size() - b.size())); + while (bytes_available > 0) + { + std::size_t pos = b.size(); + b.grow(bytes_available); + std::size_t bytes_transferred = s.read_some( + b.data(pos, bytes_available), ec); + b.shrink(bytes_available - bytes_transferred); + total_transferred += bytes_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(max_size, b.max_size() - b.size())); + } + return total_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), transfer_all(), ec); + boost::asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + return read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + transfer_all(), ec); +} + +template <typename SyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} namespace detail { @@ -233,7 +319,7 @@ namespace detail { public: read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, ReadHandler& handler) + CompletionCondition& completion_condition, ReadHandler& handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), @@ -254,9 +340,11 @@ namespace detail } read_op(read_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : detail::base_from_completion_cond<CompletionCondition>( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), stream_(other.stream_), - buffers_(other.buffers_), + buffers_(BOOST_ASIO_MOVE_CAST(buffers_type)(other.buffers_)), start_(other.start_), handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) { @@ -287,9 +375,11 @@ namespace detail } //private: + typedef boost::asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> buffers_type; + AsyncReadStream& stream_; - boost::asio::detail::consuming_buffers<mutable_buffer, - MutableBufferSequence, MutableBufferIterator> buffers_; + buffers_type buffers_; int start_; ReadHandler handler_; }; @@ -355,13 +445,33 @@ namespace detail typename ReadHandler> inline void start_read_buffer_sequence_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, const MutableBufferIterator&, - CompletionCondition completion_condition, ReadHandler& handler) + CompletionCondition& completion_condition, ReadHandler& handler) { detail::read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>( stream, buffers, completion_condition, handler)( boost::system::error_code(), 0, 1); } + + struct initiate_async_read_buffer_sequence + { + template <typename ReadHandler, typename AsyncReadStream, + typename MutableBufferSequence, typename CompletionCondition> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + start_read_buffer_sequence_op(*s, buffers, + boost::asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) @@ -417,18 +527,10 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, is_mutable_buffer_sequence<MutableBufferSequence>::value >::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::start_read_buffer_sequence_op(s, buffers, - boost::asio::buffer_sequence_begin(buffers), completion_condition, - init.completion_handler); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_buffer_sequence(), handler, &s, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncReadStream, typename MutableBufferSequence, @@ -441,32 +543,26 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, is_mutable_buffer_sequence<MutableBufferSequence>::value >::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::start_read_buffer_sequence_op(s, buffers, - boost::asio::buffer_sequence_begin(buffers), transfer_all(), - init.completion_handler); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_buffer_sequence(), + handler, &s, buffers, transfer_all()); } +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + namespace detail { - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> - class read_dynbuf_op + class read_dynbuf_v1_op : detail::base_from_completion_cond<CompletionCondition> { public: template <typename BufferSequence> - read_dynbuf_op(AsyncReadStream& stream, + read_dynbuf_v1_op(AsyncReadStream& stream, BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, - CompletionCondition completion_condition, ReadHandler& handler) + CompletionCondition& completion_condition, ReadHandler& handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), @@ -478,7 +574,7 @@ namespace detail } #if defined(BOOST_ASIO_HAS_MOVE) - read_dynbuf_op(const read_dynbuf_op& other) + read_dynbuf_v1_op(const read_dynbuf_v1_op& other) : detail::base_from_completion_cond<CompletionCondition>(other), stream_(other.stream_), buffers_(other.buffers_), @@ -488,10 +584,12 @@ namespace detail { } - read_dynbuf_op(read_dynbuf_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + read_dynbuf_v1_op(read_dynbuf_v1_op&& other) + : detail::base_from_completion_cond<CompletionCondition>( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), stream_(other.stream_), - buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), start_(other.start_), total_transferred_(other.total_transferred_), handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) @@ -515,7 +613,7 @@ namespace detail for (;;) { stream_.async_read_some(buffers_.prepare(bytes_available), - BOOST_ASIO_MOVE_CAST(read_dynbuf_op)(*this)); + BOOST_ASIO_MOVE_CAST(read_dynbuf_v1_op)(*this)); return; default: total_transferred_ += bytes_transferred; buffers_.commit(bytes_transferred); @@ -535,36 +633,36 @@ namespace detail //private: AsyncReadStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; int start_; std::size_t total_transferred_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_dynbuf_op<AsyncReadStream, DynamicBuffer, + read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_dynbuf_op<AsyncReadStream, DynamicBuffer, + read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( - read_dynbuf_op<AsyncReadStream, DynamicBuffer, + read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true @@ -573,10 +671,10 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename CompletionCondition, + typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline void asio_handler_invoke(Function& function, - read_dynbuf_op<AsyncReadStream, DynamicBuffer, + read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -584,49 +682,71 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename CompletionCondition, + typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_dynbuf_op<AsyncReadStream, DynamicBuffer, + read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_read_dynbuf_v1 + { + template <typename ReadHandler, typename AsyncReadStream, + typename DynamicBuffer_v1, typename CompletionCondition> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + read_dynbuf_v1_op<AsyncReadStream, typename decay<DynamicBuffer_v1>::type, + CompletionCondition, typename decay<ReadHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + completion_cond2.value, handler2.value)( + boost::system::error_code(), 0, 1); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler, typename Allocator> struct associated_allocator< - detail::read_dynbuf_op<AsyncReadStream, - DynamicBuffer, CompletionCondition, ReadHandler>, + detail::read_dynbuf_v1_op<AsyncReadStream, + DynamicBuffer_v1, CompletionCondition, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( - const detail::read_dynbuf_op<AsyncReadStream, - DynamicBuffer, CompletionCondition, ReadHandler>& h, + const detail::read_dynbuf_v1_op<AsyncReadStream, + DynamicBuffer_v1, CompletionCondition, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler, typename Executor> struct associated_executor< - detail::read_dynbuf_op<AsyncReadStream, - DynamicBuffer, CompletionCondition, ReadHandler>, + detail::read_dynbuf_v1_op<AsyncReadStream, + DynamicBuffer_v1, CompletionCondition, ReadHandler>, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( - const detail::read_dynbuf_op<AsyncReadStream, - DynamicBuffer, CompletionCondition, ReadHandler>& h, + const detail::read_dynbuf_v1_op<AsyncReadStream, + DynamicBuffer_v1, CompletionCondition, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); @@ -636,49 +756,44 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return async_read(s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::read_dynbuf_op<AsyncReadStream, - typename decay<DynamicBuffer>::type, - CompletionCondition, BOOST_ASIO_HANDLER_TYPE( - ReadHandler, void (boost::system::error_code, std::size_t))>( - s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), - completion_condition, init.completion_handler)( - boost::system::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_dynbuf_v1(), handler, &s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) @@ -703,11 +818,260 @@ async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_read(s, basic_streambuf_ref<Allocator>(b), - completion_condition, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), + BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename ReadHandler> + class read_dynbuf_v2_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + template <typename BufferSequence> + read_dynbuf_v2_op(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + CompletionCondition& completion_condition, ReadHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + start_(0), + total_transferred_(0), + bytes_available_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_dynbuf_v2_op(const read_dynbuf_v2_op& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + total_transferred_(other.total_transferred_), + bytes_available_(other.bytes_available_), + handler_(other.handler_) + { + } + + read_dynbuf_v2_op(read_dynbuf_v2_op&& other) + : detail::base_from_completion_cond<CompletionCondition>( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), + stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + start_(other.start_), + total_transferred_(other.total_transferred_), + bytes_available_(other.bytes_available_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size, pos; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(max_size, + buffers_.max_size() - buffers_.size())); + for (;;) + { + 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)); + return; default: + total_transferred_ += bytes_transferred; + buffers_.shrink(bytes_available_ - bytes_transferred); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(max_size, + buffers_.max_size() - buffers_.size())); + if ((!ec && bytes_transferred == 0) || bytes_available_ == 0) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + int start_; + std::size_t total_transferred_; + std::size_t bytes_available_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, + CompletionCondition, ReadHandler>* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, + CompletionCondition, ReadHandler>* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, + CompletionCondition, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer_v2, typename CompletionCondition, + typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, + CompletionCondition, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer_v2, typename CompletionCondition, + typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, + CompletionCondition, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_dynbuf_v2 + { + template <typename ReadHandler, typename AsyncReadStream, + typename DynamicBuffer_v2, typename CompletionCondition> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + read_dynbuf_v2_op<AsyncReadStream, typename decay<DynamicBuffer_v2>::type, + CompletionCondition, typename decay<ReadHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + completion_cond2.value, handler2.value)( + boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_dynbuf_v2_op<AsyncReadStream, + DynamicBuffer_v2, CompletionCondition, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_dynbuf_v2_op<AsyncReadStream, + DynamicBuffer_v2, CompletionCondition, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_dynbuf_v2_op<AsyncReadStream, + DynamicBuffer_v2, CompletionCondition, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_dynbuf_v2_op<AsyncReadStream, + DynamicBuffer_v2, CompletionCondition, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + return async_read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + transfer_all(), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename ReadHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_dynbuf_v2(), handler, &s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} } // namespace asio } // namespace boost diff --git a/boost/asio/impl/read_at.hpp b/boost/asio/impl/read_at.hpp index e3c31c543e..8152ef99a4 100644 --- a/boost/asio/impl/read_at.hpp +++ b/boost/asio/impl/read_at.hpp @@ -2,7 +2,7 @@ // impl/read_at.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -29,6 +29,7 @@ #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> @@ -71,7 +72,8 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, CompletionCondition completion_condition, boost::system::error_code& ec) { return detail::read_at_buffer_sequence(d, offset, buffers, - boost::asio::buffer_sequence_begin(buffers), completion_condition, ec); + boost::asio::buffer_sequence_begin(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); } template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence> @@ -100,8 +102,8 @@ inline std::size_t read_at(SyncRandomAccessReadDevice& d, CompletionCondition completion_condition) { boost::system::error_code ec; - std::size_t bytes_transferred = read_at( - d, offset, buffers, completion_condition, ec); + std::size_t bytes_transferred = read_at(d, offset, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); boost::asio::detail::throw_error(ec, "read_at"); return bytes_transferred; } @@ -159,8 +161,8 @@ inline std::size_t read_at(SyncRandomAccessReadDevice& d, CompletionCondition completion_condition) { boost::system::error_code ec; - std::size_t bytes_transferred = read_at( - d, offset, b, completion_condition, ec); + std::size_t bytes_transferred = read_at(d, offset, b, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); boost::asio::detail::throw_error(ec, "read_at"); return bytes_transferred; } @@ -179,7 +181,7 @@ namespace detail public: read_at_op(AsyncRandomAccessReadDevice& device, uint64_t offset, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, ReadHandler& handler) + CompletionCondition& completion_condition, ReadHandler& handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), device_(device), @@ -202,10 +204,12 @@ namespace detail } read_at_op(read_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : detail::base_from_completion_cond<CompletionCondition>( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), device_(other.device_), offset_(other.offset_), - buffers_(other.buffers_), + buffers_(BOOST_ASIO_MOVE_CAST(buffers_type)(other.buffers_)), start_(other.start_), handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) { @@ -237,10 +241,12 @@ namespace detail } //private: + typedef boost::asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> buffers_type; + AsyncRandomAccessReadDevice& device_; uint64_t offset_; - boost::asio::detail::consuming_buffers<mutable_buffer, - MutableBufferSequence, MutableBufferIterator> buffers_; + buffers_type buffers_; int start_; ReadHandler handler_; }; @@ -306,7 +312,7 @@ namespace detail typename CompletionCondition, typename ReadHandler> inline void start_read_at_buffer_sequence_op(AsyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, - const MutableBufferIterator&, CompletionCondition completion_condition, + const MutableBufferIterator&, CompletionCondition& completion_condition, ReadHandler& handler) { detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, @@ -314,6 +320,27 @@ namespace detail d, offset, buffers, completion_condition, handler)( boost::system::error_code(), 0, 1); } + + struct initiate_async_read_at_buffer_sequence + { + template <typename ReadHandler, typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename CompletionCondition> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncRandomAccessReadDevice* d, uint64_t offset, + const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + start_read_at_buffer_sequence_op(*d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) @@ -369,18 +396,10 @@ async_read_at(AsyncRandomAccessReadDevice& d, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::start_read_at_buffer_sequence_op(d, offset, buffers, - boost::asio::buffer_sequence_begin(buffers), completion_condition, - init.completion_handler); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_at_buffer_sequence(), handler, &d, offset, + buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, @@ -391,18 +410,10 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::start_read_at_buffer_sequence_op(d, offset, buffers, - boost::asio::buffer_sequence_begin(buffers), transfer_all(), - init.completion_handler); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_at_buffer_sequence(), + handler, &d, offset, buffers, transfer_all()); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) @@ -418,7 +429,7 @@ namespace detail public: read_at_streambuf_op(AsyncRandomAccessReadDevice& device, uint64_t offset, basic_streambuf<Allocator>& streambuf, - CompletionCondition completion_condition, ReadHandler& handler) + CompletionCondition& completion_condition, ReadHandler& handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), device_(device), @@ -443,7 +454,9 @@ namespace detail } read_at_streambuf_op(read_at_streambuf_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : detail::base_from_completion_cond<CompletionCondition>( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), device_(other.device_), offset_(other.offset_), streambuf_(other.streambuf_), @@ -540,6 +553,28 @@ namespace detail boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_read_at_streambuf + { + template <typename ReadHandler, typename AsyncRandomAccessReadDevice, + typename Allocator, typename CompletionCondition> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncRandomAccessReadDevice* d, uint64_t offset, + basic_streambuf<Allocator>* b, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + CompletionCondition, typename decay<ReadHandler>::type>( + *d, offset, *b, completion_cond2.value, handler2.value)( + boost::system::error_code(), 0, 1); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) @@ -591,20 +626,10 @@ async_read_at(AsyncRandomAccessReadDevice& d, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, - CompletionCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - d, offset, b, completion_condition, init.completion_handler)( - boost::system::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_at_streambuf(), handler, &d, offset, + &b, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncRandomAccessReadDevice, typename Allocator, @@ -615,20 +640,10 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, - detail::transfer_all_t, BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - d, offset, b, transfer_all(), init.completion_handler)( - boost::system::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_at_streambuf(), + handler, &d, offset, &b, transfer_all()); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) diff --git a/boost/asio/impl/read_until.hpp b/boost/asio/impl/read_until.hpp index 8bc959557a..63b86f8f2e 100644 --- a/boost/asio/impl/read_until.hpp +++ b/boost/asio/impl/read_until.hpp @@ -2,7 +2,7 @@ // impl/read_until.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -29,6 +29,7 @@ #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/limits.hpp> +#include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> @@ -36,30 +37,75 @@ namespace boost { namespace asio { -template <typename SyncReadStream, typename DynamicBuffer> +namespace detail +{ + // Algorithm that finds a subsequence of equal values in a sequence. Returns + // (iterator,true) if a full match was found, in which case the iterator + // points to the beginning of the match. Returns (iterator,false) if a + // partial match was found at the end of the first sequence, in which case + // the iterator points to the beginning of the partial match. Returns + // (last1,false) if no full or partial match was found. + template <typename Iterator1, typename Iterator2> + std::pair<Iterator1, bool> partial_search( + Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) + { + for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) + { + Iterator1 test_iter1 = iter1; + Iterator2 test_iter2 = first2; + for (;; ++test_iter1, ++test_iter2) + { + if (test_iter2 == last2) + return std::make_pair(iter1, true); + if (test_iter1 == last1) + { + if (test_iter2 != first2) + return std::make_pair(iter1, false); + else + break; + } + if (*test_iter1 != *test_iter2) + break; + } + } + return std::make_pair(last1, false); + } +} // namespace detail + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read_until(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, char delim) + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim, + typename enable_if< + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = read_until(s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec); + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, ec); boost::asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read_until(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, - char delim, boost::system::error_code& ec) + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + char delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { - typename decay<DynamicBuffer>::type b( - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + typename decay<DynamicBuffer_v1>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = b.data(); iterator begin = iterator::begin(data_buffers); @@ -97,66 +143,39 @@ std::size_t read_until(SyncReadStream& s, } } -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read_until(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, - BOOST_ASIO_STRING_VIEW_PARAM delim) + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, + typename enable_if< + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = read_until(s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec); + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, ec); boost::asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } -namespace detail -{ - // Algorithm that finds a subsequence of equal values in a sequence. Returns - // (iterator,true) if a full match was found, in which case the iterator - // points to the beginning of the match. Returns (iterator,false) if a - // partial match was found at the end of the first sequence, in which case - // the iterator points to the beginning of the partial match. Returns - // (last1,false) if no full or partial match was found. - template <typename Iterator1, typename Iterator2> - std::pair<Iterator1, bool> partial_search( - Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) - { - for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) - { - Iterator1 test_iter1 = iter1; - Iterator2 test_iter2 = first2; - for (;; ++test_iter1, ++test_iter2) - { - if (test_iter2 == last2) - return std::make_pair(iter1, true); - if (test_iter1 == last1) - { - if (test_iter2 != first2) - return std::make_pair(iter1, false); - else - break; - } - if (*test_iter1 != *test_iter2) - break; - } - } - return std::make_pair(last1, false); - } -} // namespace detail - -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read_until(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, - BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec) + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { - typename decay<DynamicBuffer>::type b( - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + typename decay<DynamicBuffer_v1>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = b.data(); iterator begin = iterator::begin(data_buffers); @@ -206,31 +225,39 @@ std::size_t read_until(SyncReadStream& s, #if !defined(BOOST_ASIO_NO_EXTENSIONS) #if defined(BOOST_ASIO_HAS_BOOST_REGEX) -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read_until(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, - const boost::regex& expr) + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const boost::regex& expr, + typename enable_if< + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = read_until(s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), expr, ec); + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr, ec); boost::asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } -template <typename SyncReadStream, typename DynamicBuffer> +template <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read_until(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, - const boost::regex& expr, boost::system::error_code& ec) + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const boost::regex& expr, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { - typename decay<DynamicBuffer>::type b( - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + typename decay<DynamicBuffer_v1>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = b.data(); iterator begin = iterator::begin(data_buffers); @@ -282,35 +309,43 @@ std::size_t read_until(SyncReadStream& s, #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) template <typename SyncReadStream, - typename DynamicBuffer, typename MatchCondition> + typename DynamicBuffer_v1, typename MatchCondition> inline std::size_t read_until(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, MatchCondition match_condition, - typename enable_if<is_match_condition<MatchCondition>::value>::type*) + typename enable_if< + is_match_condition<MatchCondition>::value + && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = read_until(s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition, ec); boost::asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } template <typename SyncReadStream, - typename DynamicBuffer, typename MatchCondition> + typename DynamicBuffer_v1, typename MatchCondition> std::size_t read_until(SyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, MatchCondition match_condition, boost::system::error_code& ec, - typename enable_if<is_match_condition<MatchCondition>::value>::type*) + typename enable_if< + is_match_condition<MatchCondition>::value + && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { - typename decay<DynamicBuffer>::type b( - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + typename decay<DynamicBuffer_v1>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = b.data(); iterator begin = iterator::begin(data_buffers); @@ -424,16 +459,332 @@ inline std::size_t read_until(SyncReadStream& s, #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncReadStream, typename DynamicBuffer_v2> +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, char delim, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + char delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + iterator iter = std::find(start_pos, end, delim); + if (iter != end) + { + // Found a match. We're done. + ec = boost::system::error_code(); + return iter - begin + 1; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair<iterator, bool> result = detail::partial_search( + start_pos, end, delim.begin(), delim.end()); + if (result.first != end) + { + if (result.second) + { + // Full match. We're done. + ec = boost::system::error_code(); + return result.first - begin + delim.length(); + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template <typename SyncReadStream, typename DynamicBuffer_v2> +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, const boost::regex& expr, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer_v2> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::regex& expr, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + boost::match_results<iterator, + typename std::vector<boost::sub_match<iterator> >::allocator_type> + match_results; + if (regex_search(start_pos, end, match_results, expr, + boost::match_default | boost::match_partial)) + { + if (match_results[0].matched) + { + // Full match. We're done. + ec = boost::system::error_code(); + return match_results[0].second - begin; + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = match_results[0].first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template <typename SyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition> +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, MatchCondition match_condition, + typename enable_if< + is_match_condition<MatchCondition>::value + && is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + match_condition, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition> +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, boost::system::error_code& ec, + typename enable_if< + is_match_condition<MatchCondition>::value + && is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair<iterator, bool> result = match_condition(start_pos, end); + if (result.second) + { + // Full match. We're done. + ec = boost::system::error_code(); + return result.first - begin; + } + else if (result.first != end) + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) namespace detail { template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - class read_until_delim_op + typename DynamicBuffer_v1, typename ReadHandler> + class read_until_delim_op_v1 { public: template <typename BufferSequence> - read_until_delim_op(AsyncReadStream& stream, + read_until_delim_op_v1(AsyncReadStream& stream, BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, char delim, ReadHandler& handler) : stream_(stream), @@ -446,7 +797,7 @@ namespace detail } #if defined(BOOST_ASIO_HAS_MOVE) - read_until_delim_op(const read_until_delim_op& other) + read_until_delim_op_v1(const read_until_delim_op_v1& other) : stream_(other.stream_), buffers_(other.buffers_), delim_(other.delim_), @@ -456,9 +807,9 @@ namespace detail { } - read_until_delim_op(read_until_delim_op&& other) + read_until_delim_op_v1(read_until_delim_op_v1&& other) : stream_(other.stream_), - buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), delim_(other.delim_), start_(other.start_), search_position_(other.search_position_), @@ -479,7 +830,7 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = buffers_.data(); @@ -520,9 +871,9 @@ namespace detail if (!start && bytes_to_read == 0) break; - // Start a new asynchronous read operation to obtain more data. + // 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)(*this)); + BOOST_ASIO_MOVE_CAST(read_until_delim_op_v1)(*this)); return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) @@ -543,7 +894,7 @@ namespace detail //private: AsyncReadStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; char delim_; int start_; std::size_t search_position_; @@ -551,30 +902,30 @@ namespace detail }; template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline bool asio_handler_is_continuation( - read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( @@ -582,58 +933,79 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline void asio_handler_invoke(Function& function, - read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_read_until_delim_v1 + { + template <typename ReadHandler, typename AsyncReadStream, + typename DynamicBuffer_v1> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + char delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_delim_op_v1<AsyncReadStream, + typename decay<DynamicBuffer_v1>::type, + typename decay<ReadHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + delim, handler2.value)(boost::system::error_code(), 0, 1); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler, typename Allocator> struct associated_allocator< - detail::read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>, + detail::read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( - const detail::read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>& h, + const detail::read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler, typename Executor> struct associated_executor< - detail::read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>, + detail::read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( - const detail::read_until_delim_op<AsyncReadStream, - DynamicBuffer, ReadHandler>& h, + const detail::read_until_delim_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); @@ -643,39 +1015,32 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, - char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::read_until_delim_op<AsyncReadStream, - typename decay<DynamicBuffer>::type, - BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), - delim, init.completion_handler)(boost::system::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_until_delim_v1(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim); } namespace detail { template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> - class read_until_delim_string_op + typename DynamicBuffer_v1, typename ReadHandler> + class read_until_delim_string_op_v1 { public: template <typename BufferSequence> - read_until_delim_string_op(AsyncReadStream& stream, + read_until_delim_string_op_v1(AsyncReadStream& stream, BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, const std::string& delim, ReadHandler& handler) : stream_(stream), @@ -688,7 +1053,7 @@ namespace detail } #if defined(BOOST_ASIO_HAS_MOVE) - read_until_delim_string_op(const read_until_delim_string_op& other) + read_until_delim_string_op_v1(const read_until_delim_string_op_v1& other) : stream_(other.stream_), buffers_(other.buffers_), delim_(other.delim_), @@ -698,9 +1063,9 @@ namespace detail { } - read_until_delim_string_op(read_until_delim_string_op&& other) + read_until_delim_string_op_v1(read_until_delim_string_op_v1&& other) : stream_(other.stream_), - buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)), start_(other.start_), search_position_(other.search_position_), @@ -721,7 +1086,7 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = buffers_.data(); @@ -773,9 +1138,9 @@ namespace detail if (!start && bytes_to_read == 0) break; - // Start a new asynchronous read operation to obtain more data. + // 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)(*this)); + BOOST_ASIO_MOVE_CAST(read_until_delim_string_op_v1)(*this)); return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) @@ -796,7 +1161,7 @@ namespace detail //private: AsyncReadStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; std::string delim_; int start_; std::size_t search_position_; @@ -804,30 +1169,30 @@ namespace detail }; template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline bool asio_handler_is_continuation( - read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( @@ -835,58 +1200,79 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline void asio_handler_invoke(Function& function, - read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>* this_handler) + read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_read_until_delim_string_v1 + { + template <typename ReadHandler, typename AsyncReadStream, + typename DynamicBuffer_v1> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const std::string& delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_delim_string_op_v1<AsyncReadStream, + typename decay<DynamicBuffer_v1>::type, + typename decay<ReadHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + delim, handler2.value)(boost::system::error_code(), 0, 1); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler, typename Allocator> struct associated_allocator< - detail::read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>, + detail::read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( - const detail::read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>& h, + const detail::read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler, typename Executor> struct associated_executor< - detail::read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>, + detail::read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( - const detail::read_until_delim_string_op<AsyncReadStream, - DynamicBuffer, ReadHandler>& h, + const detail::read_until_delim_string_op_v1<AsyncReadStream, + DynamicBuffer_v1, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); @@ -896,30 +1282,23 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, BOOST_ASIO_STRING_VIEW_PARAM delim, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::read_until_delim_string_op<AsyncReadStream, - typename decay<DynamicBuffer>::type, - BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), - static_cast<std::string>(delim), - init.completion_handler)(boost::system::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_until_delim_string_v1(), + handler, &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + static_cast<std::string>(delim)); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) @@ -927,13 +1306,13 @@ async_read_until(AsyncReadStream& s, namespace detail { - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> - class read_until_expr_op + class read_until_expr_op_v1 { public: template <typename BufferSequence> - read_until_expr_op(AsyncReadStream& stream, + read_until_expr_op_v1(AsyncReadStream& stream, BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, const boost::regex& expr, ReadHandler& handler) : stream_(stream), @@ -946,7 +1325,7 @@ namespace detail } #if defined(BOOST_ASIO_HAS_MOVE) - read_until_expr_op(const read_until_expr_op& other) + read_until_expr_op_v1(const read_until_expr_op_v1& other) : stream_(other.stream_), buffers_(other.buffers_), expr_(other.expr_), @@ -956,9 +1335,9 @@ namespace detail { } - read_until_expr_op(read_until_expr_op&& other) + read_until_expr_op_v1(read_until_expr_op_v1&& other) : stream_(other.stream_), - buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), expr_(other.expr_), start_(other.start_), search_position_(other.search_position_), @@ -979,7 +1358,7 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = buffers_.data(); @@ -1034,9 +1413,9 @@ namespace detail if (!start && bytes_to_read == 0) break; - // Start a new asynchronous read operation to obtain more data. + // 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)(*this)); + BOOST_ASIO_MOVE_CAST(read_until_expr_op_v1)(*this)); return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) @@ -1057,38 +1436,38 @@ namespace detail //private: AsyncReadStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; RegEx expr_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>* this_handler) + read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>* this_handler) + read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline bool asio_handler_is_continuation( - read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>* this_handler) + read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( @@ -1096,58 +1475,79 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename RegEx, typename ReadHandler> + typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline void asio_handler_invoke(Function& function, - read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>* this_handler) + read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename RegEx, typename ReadHandler> + typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>* this_handler) + read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_read_until_expr_v1 + { + template <typename ReadHandler, typename AsyncReadStream, + typename DynamicBuffer_v1, typename RegEx> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const RegEx& expr) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_expr_op_v1<AsyncReadStream, + typename decay<DynamicBuffer_v1>::type, + RegEx, typename decay<ReadHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + expr, handler2.value)(boost::system::error_code(), 0, 1); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler, typename Allocator> struct associated_allocator< - detail::read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>, + detail::read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( - const detail::read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>& h, + const detail::read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler, typename Executor> struct associated_executor< - detail::read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>, + detail::read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( - const detail::read_until_expr_op<AsyncReadStream, - DynamicBuffer, RegEx, ReadHandler>& h, + const detail::read_until_expr_op_v1<AsyncReadStream, + DynamicBuffer_v1, RegEx, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); @@ -1157,42 +1557,35 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, - typename DynamicBuffer, typename ReadHandler> + typename DynamicBuffer_v1, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, const boost::regex& expr, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::read_until_expr_op<AsyncReadStream, - typename decay<DynamicBuffer>::type, - boost::regex, BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), - expr, init.completion_handler)(boost::system::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_until_expr_v1(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr); } #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) namespace detail { - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> - class read_until_match_op + class read_until_match_op_v1 { public: template <typename BufferSequence> - read_until_match_op(AsyncReadStream& stream, + read_until_match_op_v1(AsyncReadStream& stream, BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, MatchCondition match_condition, ReadHandler& handler) : stream_(stream), @@ -1205,7 +1598,7 @@ namespace detail } #if defined(BOOST_ASIO_HAS_MOVE) - read_until_match_op(const read_until_match_op& other) + read_until_match_op_v1(const read_until_match_op_v1& other) : stream_(other.stream_), buffers_(other.buffers_), match_condition_(other.match_condition_), @@ -1215,9 +1608,9 @@ namespace detail { } - read_until_match_op(read_until_match_op&& other) + read_until_match_op_v1(read_until_match_op_v1&& other) : stream_(other.stream_), - buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), match_condition_(other.match_condition_), start_(other.start_), search_position_(other.search_position_), @@ -1238,7 +1631,7 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename DynamicBuffer::const_buffers_type + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; typedef buffers_iterator<buffers_type> iterator; buffers_type data_buffers = buffers_.data(); @@ -1289,9 +1682,9 @@ namespace detail if (!start && bytes_to_read == 0) break; - // Start a new asynchronous read operation to obtain more data. + // 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)(*this)); + BOOST_ASIO_MOVE_CAST(read_until_match_op_v1)(*this)); return; default: buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) @@ -1312,37 +1705,37 @@ namespace detail //private: AsyncReadStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; MatchCondition match_condition_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_until_match_op<AsyncReadStream, DynamicBuffer, + read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_match_op<AsyncReadStream, DynamicBuffer, + read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename DynamicBuffer, + template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> inline bool asio_handler_is_continuation( - read_until_match_op<AsyncReadStream, DynamicBuffer, + read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true @@ -1351,10 +1744,10 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename MatchCondition, + typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> inline void asio_handler_invoke(Function& function, - read_until_match_op<AsyncReadStream, DynamicBuffer, + read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -1362,49 +1755,70 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename DynamicBuffer, typename MatchCondition, + typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_until_match_op<AsyncReadStream, DynamicBuffer, + read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_read_until_match_v1 + { + template <typename ReadHandler, typename AsyncReadStream, + typename DynamicBuffer_v1, typename MatchCondition> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + MatchCondition match_condition) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_match_op_v1<AsyncReadStream, + typename decay<DynamicBuffer_v1>::type, + MatchCondition, typename decay<ReadHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + match_condition, handler2.value)(boost::system::error_code(), 0, 1); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler, typename Allocator> struct associated_allocator< - detail::read_until_match_op<AsyncReadStream, - DynamicBuffer, MatchCondition, ReadHandler>, + detail::read_until_match_op_v1<AsyncReadStream, + DynamicBuffer_v1, MatchCondition, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( - const detail::read_until_match_op<AsyncReadStream, - DynamicBuffer, MatchCondition, ReadHandler>& h, + const detail::read_until_match_op_v1<AsyncReadStream, + DynamicBuffer_v1, MatchCondition, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler, typename Executor> struct associated_executor< - detail::read_until_match_op<AsyncReadStream, - DynamicBuffer, MatchCondition, ReadHandler>, + detail::read_until_match_op_v1<AsyncReadStream, + DynamicBuffer_v1, MatchCondition, ReadHandler>, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( - const detail::read_until_match_op<AsyncReadStream, - DynamicBuffer, MatchCondition, ReadHandler>& h, + const detail::read_until_match_op_v1<AsyncReadStream, + DynamicBuffer_v1, MatchCondition, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); @@ -1413,31 +1827,23 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template <typename AsyncReadStream, typename DynamicBuffer, +template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - typename enable_if<is_match_condition<MatchCondition>::value>::type*) + typename enable_if< + is_match_condition<MatchCondition>::value + && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value + >::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - async_completion<ReadHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::read_until_match_op<AsyncReadStream, - typename decay<DynamicBuffer>::type, - MatchCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), - match_condition, init.completion_handler)( - boost::system::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_until_match_v1(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition); } #if !defined(BOOST_ASIO_NO_IOSTREAM) @@ -1495,6 +1901,1102 @@ async_read_until(AsyncReadStream& s, #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + class read_until_delim_op_v2 + { + public: + template <typename BufferSequence> + read_until_delim_op_v2(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + char delim, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + delim_(delim), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_delim_op_v2(const read_until_delim_op_v2& other) + : stream_(other.stream_), + buffers_(other.buffers_), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_delim_op_v2(read_until_delim_op_v2&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + iterator iter = std::find(start_pos, end, delim_); + if (iter != end) + { + // Found a match. We're done. + search_position_ = iter - begin + 1; + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + // Next search can start with the new data. + search_position_ = end - begin; + bytes_to_read_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // 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)); + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + char delim_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_delim_v2 + { + template <typename ReadHandler, typename AsyncReadStream, + typename DynamicBuffer_v2> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + char delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_delim_op_v2<AsyncReadStream, + typename decay<DynamicBuffer_v2>::type, + typename decay<ReadHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + delim, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_until_delim_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_until_delim_v2(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim); +} + +namespace detail +{ + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + class read_until_delim_string_op_v2 + { + public: + template <typename BufferSequence> + read_until_delim_string_op_v2(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + const std::string& delim, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + delim_(delim), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_delim_string_op_v2(const read_until_delim_string_op_v2& other) + : stream_(other.stream_), + buffers_(other.buffers_), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_delim_string_op_v2(read_until_delim_string_op_v2&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair<iterator, bool> result = detail::partial_search( + start_pos, end, delim_.begin(), delim_.end()); + if (result.first != end && result.second) + { + // Full match. We're done. + search_position_ = result.first - begin + delim_.length(); + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // 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)); + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + std::string delim_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_delim_string_v2 + { + template <typename ReadHandler, typename AsyncReadStream, + typename DynamicBuffer_v2> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + const std::string& delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_delim_string_op_v2<AsyncReadStream, + typename decay<DynamicBuffer_v2>::type, + typename decay<ReadHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + delim, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_until_delim_string_op_v2<AsyncReadStream, + DynamicBuffer_v2, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_until_delim_string_v2(), + handler, &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + static_cast<std::string>(delim)); +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +namespace detail +{ + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename RegEx, typename ReadHandler> + class read_until_expr_op_v2 + { + public: + template <typename BufferSequence> + read_until_expr_op_v2(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + const boost::regex& expr, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + expr_(expr), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_expr_op_v2(const read_until_expr_op_v2& other) + : stream_(other.stream_), + buffers_(other.buffers_), + expr_(other.expr_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_expr_op_v2(read_until_expr_op_v2&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + expr_(other.expr_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + boost::match_results<iterator, + typename std::vector<boost::sub_match<iterator> >::allocator_type> + match_results; + bool match = regex_search(start_pos, end, match_results, expr_, + boost::match_default | boost::match_partial); + if (match && match_results[0].matched) + { + // Full match. We're done. + search_position_ = match_results[0].second - begin; + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + if (match) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = match_results[0].first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // 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)); + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + RegEx expr_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename RegEx, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename RegEx, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename RegEx, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer_v2, typename RegEx, typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer_v2, typename RegEx, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_expr_v2 + { + template <typename ReadHandler, typename AsyncReadStream, + typename DynamicBuffer_v2, typename RegEx> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + const RegEx& expr) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_expr_op_v2<AsyncReadStream, + typename decay<DynamicBuffer_v2>::type, + RegEx, typename decay<ReadHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + expr, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename RegEx, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename RegEx, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_until_expr_op_v2<AsyncReadStream, + DynamicBuffer_v2, RegEx, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer_v2, typename ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::regex& expr, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_until_expr_v2(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr); +} + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + +namespace detail +{ + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename MatchCondition, typename ReadHandler> + class read_until_match_op_v2 + { + public: + template <typename BufferSequence> + read_until_match_op_v2(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + MatchCondition match_condition, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + match_condition_(match_condition), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_match_op_v2(const read_until_match_op_v2& other) + : stream_(other.stream_), + buffers_(other.buffers_), + match_condition_(other.match_condition_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_match_op_v2(read_until_match_op_v2&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + match_condition_(other.match_condition_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits<std::size_t>::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = + const_cast<const DynamicBuffer_v2&>(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair<iterator, bool> result = match_condition_(start_pos, end); + if (result.second) + { + // Full match. We're done. + search_position_ = result.first - begin; + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read_ = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // 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)); + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + MatchCondition match_condition_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename MatchCondition, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, + MatchCondition, ReadHandler>* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename MatchCondition, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, + MatchCondition, ReadHandler>* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename MatchCondition, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, + MatchCondition, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition, + typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, + MatchCondition, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition, + typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, + MatchCondition, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_match_v2 + { + template <typename ReadHandler, typename AsyncReadStream, + typename DynamicBuffer_v2, typename MatchCondition> + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + MatchCondition match_condition) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue<ReadHandler> handler2(handler); + read_until_match_op_v2<AsyncReadStream, + typename decay<DynamicBuffer_v2>::type, + MatchCondition, typename decay<ReadHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + match_condition, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename MatchCondition, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_match_op_v2<AsyncReadStream, + DynamicBuffer_v2, MatchCondition, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_until_match_op_v2<AsyncReadStream, + DynamicBuffer_v2, MatchCondition, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename MatchCondition, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_match_op_v2<AsyncReadStream, + DynamicBuffer_v2, MatchCondition, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_until_match_op_v2<AsyncReadStream, + DynamicBuffer_v2, MatchCondition, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer_v2, + typename MatchCondition, typename ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_match_condition<MatchCondition>::value + && is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + return async_initiate<ReadHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_read_until_match_v2(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), match_condition); +} + +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) } // namespace asio } // namespace boost diff --git a/boost/asio/impl/redirect_error.hpp b/boost/asio/impl/redirect_error.hpp new file mode 100644 index 0000000000..eb0d82998a --- /dev/null +++ b/boost/asio/impl/redirect_error.hpp @@ -0,0 +1,374 @@ + +// impl/redirect_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 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_REDIRECT_ERROR_HPP +#define BOOST_ASIO_IMPL_REDIRECT_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/async_result.hpp> +#include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/handler_cont_helpers.hpp> +#include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/detail/variadic_templates.hpp> +#include <boost/system/system_error.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +// Class to adapt a redirect_error_t as a completion handler. +template <typename Handler> +class redirect_error_handler +{ +public: + typedef void result_type; + + template <typename CompletionToken> + redirect_error_handler(redirect_error_t<CompletionToken> e) + : ec_(e.ec_), + handler_(BOOST_ASIO_MOVE_CAST(CompletionToken)(e.token_)) + { + } + + template <typename RedirectedHandler> + redirect_error_handler(boost::system::error_code& ec, + BOOST_ASIO_MOVE_ARG(RedirectedHandler) h) + : ec_(ec), + handler_(BOOST_ASIO_MOVE_CAST(RedirectedHandler)(h)) + { + } + + void operator()() + { + handler_(); + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Arg, typename... Args> + typename enable_if< + !is_same<typename decay<Arg>::type, boost::system::error_code>::value + >::type + operator()(BOOST_ASIO_MOVE_ARG(Arg) arg, BOOST_ASIO_MOVE_ARG(Args)... args) + { + handler_(BOOST_ASIO_MOVE_CAST(Arg)(arg), + BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + + template <typename... Args> + void operator()(const boost::system::error_code& ec, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + ec_ = ec; + handler_(BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Arg> + typename enable_if< + !is_same<typename decay<Arg>::type, boost::system::error_code>::value + >::type + operator()(BOOST_ASIO_MOVE_ARG(Arg) arg) + { + handler_(BOOST_ASIO_MOVE_CAST(Arg)(arg)); + } + + void operator()(const boost::system::error_code& ec) + { + ec_ = ec; + handler_(); + } + +#define BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \ + template <typename Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + typename enable_if< \ + !is_same<typename decay<Arg>::type, boost::system::error_code>::value \ + >::type \ + operator()(BOOST_ASIO_MOVE_ARG(Arg) arg, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + handler_(BOOST_ASIO_MOVE_CAST(Arg)(arg), \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(const boost::system::error_code& ec, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + ec_ = ec; \ + handler_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF) +#undef BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +//private: + boost::system::error_code& ec_; + Handler handler_; +}; + +template <typename Handler> +inline void* asio_handler_allocate(std::size_t size, + redirect_error_handler<Handler>* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template <typename Handler> +inline void asio_handler_deallocate(void* pointer, std::size_t size, + redirect_error_handler<Handler>* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template <typename Handler> +inline bool asio_handler_is_continuation( + redirect_error_handler<Handler>* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler> +inline void asio_handler_invoke(Function& function, + redirect_error_handler<Handler>* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Function, typename Handler> +inline void asio_handler_invoke(const Function& function, + redirect_error_handler<Handler>* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template <typename Signature> +struct redirect_error_signature +{ + typedef Signature type; +}; + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename R, typename... Args> +struct redirect_error_signature<R(boost::system::error_code, Args...)> +{ + typedef R type(Args...); +}; + +template <typename R, typename... Args> +struct redirect_error_signature<R(const boost::system::error_code&, Args...)> +{ + typedef R type(Args...); +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename R> +struct redirect_error_signature<R(boost::system::error_code)> +{ + typedef R type(); +}; + +template <typename R> +struct redirect_error_signature<R(const boost::system::error_code&)> +{ + typedef R type(); +}; + +#define BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \ + template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + struct redirect_error_signature< \ + R(boost::system::error_code, BOOST_ASIO_VARIADIC_TARGS(n))> \ + { \ + typedef R type(BOOST_ASIO_VARIADIC_TARGS(n)); \ + }; \ + \ + template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + struct redirect_error_signature< \ + R(const boost::system::error_code&, BOOST_ASIO_VARIADIC_TARGS(n))> \ + { \ + typedef R type(BOOST_ASIO_VARIADIC_TARGS(n)); \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF) +#undef BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename CompletionToken, typename Signature> +struct async_result<redirect_error_t<CompletionToken>, Signature> +{ + typedef typename async_result<CompletionToken, + typename detail::redirect_error_signature<Signature>::type> + ::return_type return_type; + + template <typename Initiation> + struct init_wrapper + { + template <typename Init> + init_wrapper(boost::system::error_code& ec, BOOST_ASIO_MOVE_ARG(Init) init) + : ec_(ec), + initiation_(BOOST_ASIO_MOVE_CAST(Init)(init)) + { + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Handler, typename... Args> + void operator()( + BOOST_ASIO_MOVE_ARG(Handler) handler, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation_)( + detail::redirect_error_handler< + typename decay<Handler>::type>( + ec_, BOOST_ASIO_MOVE_CAST(Handler)(handler)), + BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Handler> + void operator()( + BOOST_ASIO_MOVE_ARG(Handler) handler) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation_)( + detail::redirect_error_handler< + typename decay<Handler>::type>( + ec_, BOOST_ASIO_MOVE_CAST(Handler)(handler))); + } + +#define BOOST_ASIO_PRIVATE_INIT_WRAPPER_DEF(n) \ + template <typename Handler, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + void operator()( \ + BOOST_ASIO_MOVE_ARG(Handler) handler, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + BOOST_ASIO_MOVE_CAST(Initiation)(initiation_)( \ + detail::redirect_error_handler< \ + typename decay<Handler>::type>( \ + ec_, BOOST_ASIO_MOVE_CAST(Handler)(handler)), \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INIT_WRAPPER_DEF) +#undef BOOST_ASIO_PRIVATE_INIT_WRAPPER_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + boost::system::error_code& ec_; + Initiation initiation_; + }; + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Initiation, typename RawCompletionToken, typename... Args> + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + return async_initiate<CompletionToken, + typename detail::redirect_error_signature<Signature>::type>( + init_wrapper<typename decay<Initiation>::type>( + token.ec_, BOOST_ASIO_MOVE_CAST(Initiation)(initiation)), + token.token_, BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Initiation, typename RawCompletionToken> + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token) + { + return async_initiate<CompletionToken, + typename detail::redirect_error_signature<Signature>::type>( + init_wrapper<typename decay<Initiation>::type>( + token.ec_, BOOST_ASIO_MOVE_CAST(Initiation)(initiation)), + token.token_); + } + +#define BOOST_ASIO_PRIVATE_INITIATE_DEF(n) \ + template <typename Initiation, typename RawCompletionToken, \ + BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + static return_type initiate( \ + BOOST_ASIO_MOVE_ARG(Initiation) initiation, \ + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return async_initiate<CompletionToken, \ + typename detail::redirect_error_signature<Signature>::type>( \ + init_wrapper<typename decay<Initiation>::type>( \ + token.ec_, BOOST_ASIO_MOVE_CAST(Initiation)(initiation)), \ + token.token_, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INITIATE_DEF) +#undef BOOST_ASIO_PRIVATE_INITIATE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +}; + +template <typename Handler, typename Executor> +struct associated_executor<detail::redirect_error_handler<Handler>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get( + const detail::redirect_error_handler<Handler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +template <typename Handler, typename Allocator> +struct associated_allocator<detail::redirect_error_handler<Handler>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get( + const detail::redirect_error_handler<Handler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_REDIRECT_ERROR_HPP diff --git a/boost/asio/impl/serial_port_base.hpp b/boost/asio/impl/serial_port_base.hpp index 7f2dfe88df..c456e30800 100644 --- a/boost/asio/impl/serial_port_base.hpp +++ b/boost/asio/impl/serial_port_base.hpp @@ -2,7 +2,7 @@ // impl/serial_port_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying diff --git a/boost/asio/impl/serial_port_base.ipp b/boost/asio/impl/serial_port_base.ipp index 9954f77d2e..c7ff51876a 100644 --- a/boost/asio/impl/serial_port_base.ipp +++ b/boost/asio/impl/serial_port_base.ipp @@ -2,7 +2,7 @@ // impl/serial_port_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying diff --git a/boost/asio/impl/spawn.hpp b/boost/asio/impl/spawn.hpp index c2da5ce09a..cf4ce5622f 100644 --- a/boost/asio/impl/spawn.hpp +++ b/boost/asio/impl/spawn.hpp @@ -2,7 +2,7 @@ // impl/spawn.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -278,51 +278,6 @@ public: } }; -#if !defined(BOOST_ASIO_NO_DEPRECATED) - -template <typename Handler, typename ReturnType> -struct handler_type<basic_yield_context<Handler>, ReturnType()> -{ - typedef detail::coro_handler<Handler, void> type; -}; - -template <typename Handler, typename ReturnType, typename Arg1> -struct handler_type<basic_yield_context<Handler>, ReturnType(Arg1)> -{ - typedef detail::coro_handler<Handler, typename decay<Arg1>::type> type; -}; - -template <typename Handler, typename ReturnType> -struct handler_type<basic_yield_context<Handler>, - ReturnType(boost::system::error_code)> -{ - typedef detail::coro_handler<Handler, void> type; -}; - -template <typename Handler, typename ReturnType, typename Arg2> -struct handler_type<basic_yield_context<Handler>, - ReturnType(boost::system::error_code, Arg2)> -{ - typedef detail::coro_handler<Handler, typename decay<Arg2>::type> type; -}; - -template <typename Handler, typename T> -class async_result<detail::coro_handler<Handler, T> > - : public detail::coro_async_result<Handler, T> -{ -public: - typedef typename detail::coro_async_result<Handler, T>::return_type type; - - explicit async_result( - typename detail::coro_async_result<Handler, - T>::completion_handler_type& h) - : detail::coro_async_result<Handler, T>(h) - { - } -}; - -#endif // !defined(BOOST_ASIO_NO_DEPRECATED) - template <typename Handler, typename T, typename Allocator> struct associated_allocator<detail::coro_handler<Handler, T>, Allocator> { diff --git a/boost/asio/impl/src.cpp b/boost/asio/impl/src.cpp index 3823acfaf3..8f43dbf0ca 100644 --- a/boost/asio/impl/src.cpp +++ b/boost/asio/impl/src.cpp @@ -2,7 +2,7 @@ // impl/src.cpp // ~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) diff --git a/boost/asio/impl/src.hpp b/boost/asio/impl/src.hpp index b891a453fe..7f155ad25c 100644 --- a/boost/asio/impl/src.hpp +++ b/boost/asio/impl/src.hpp @@ -2,7 +2,7 @@ // impl/src.hpp // ~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) diff --git a/boost/asio/impl/system_context.hpp b/boost/asio/impl/system_context.hpp index dab5d4d085..2a6b61f312 100644 --- a/boost/asio/impl/system_context.hpp +++ b/boost/asio/impl/system_context.hpp @@ -2,7 +2,7 @@ // impl/system_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) diff --git a/boost/asio/impl/system_context.ipp b/boost/asio/impl/system_context.ipp index e56632c816..0ec6fad171 100644 --- a/boost/asio/impl/system_context.ipp +++ b/boost/asio/impl/system_context.ipp @@ -2,7 +2,7 @@ // impl/system_context.ipp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -35,7 +35,7 @@ struct system_context::thread_function }; system_context::system_context() - : scheduler_(use_service<detail::scheduler>(*this)) + : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))) { scheduler_.work_started(); @@ -67,6 +67,13 @@ void system_context::join() threads_.join(); } +detail::scheduler& system_context::add_scheduler(detail::scheduler* s) +{ + detail::scoped_ptr<detail::scheduler> scoped_impl(s); + boost::asio::add_service<detail::scheduler>(*this, scoped_impl.get()); + return *scoped_impl.release(); +} + } // namespace asio } // namespace boost diff --git a/boost/asio/impl/system_executor.hpp b/boost/asio/impl/system_executor.hpp index c59e780d3f..25c51a6560 100644 --- a/boost/asio/impl/system_executor.hpp +++ b/boost/asio/impl/system_executor.hpp @@ -2,7 +2,7 @@ // impl/system_executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) diff --git a/boost/asio/impl/thread_pool.hpp b/boost/asio/impl/thread_pool.hpp index ed8d768cd0..31d8b37ee0 100644 --- a/boost/asio/impl/thread_pool.hpp +++ b/boost/asio/impl/thread_pool.hpp @@ -2,7 +2,7 @@ // impl/thread_pool.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) diff --git a/boost/asio/impl/thread_pool.ipp b/boost/asio/impl/thread_pool.ipp index e0952eb657..d59b6ef15f 100644 --- a/boost/asio/impl/thread_pool.ipp +++ b/boost/asio/impl/thread_pool.ipp @@ -2,7 +2,7 @@ // impl/thread_pool.ipp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -35,7 +35,7 @@ struct thread_pool::thread_function }; thread_pool::thread_pool() - : scheduler_(use_service<detail::scheduler>(*this)) + : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))) { scheduler_.work_started(); @@ -45,7 +45,8 @@ thread_pool::thread_pool() } thread_pool::thread_pool(std::size_t num_threads) - : scheduler_(use_service<detail::scheduler>(*this)) + : scheduler_(add_scheduler(new detail::scheduler( + *this, num_threads == 1 ? 1 : 0, false))) { scheduler_.work_started(); @@ -66,8 +67,18 @@ void thread_pool::stop() void thread_pool::join() { - scheduler_.work_finished(); - threads_.join(); + if (!threads_.empty()) + { + scheduler_.work_finished(); + threads_.join(); + } +} + +detail::scheduler& thread_pool::add_scheduler(detail::scheduler* s) +{ + detail::scoped_ptr<detail::scheduler> scoped_impl(s); + boost::asio::add_service<detail::scheduler>(*this, scoped_impl.get()); + return *scoped_impl.release(); } } // namespace asio diff --git a/boost/asio/impl/use_awaitable.hpp b/boost/asio/impl/use_awaitable.hpp new file mode 100644 index 0000000000..0d7ad0a42b --- /dev/null +++ b/boost/asio/impl/use_awaitable.hpp @@ -0,0 +1,278 @@ +// +// impl/use_awaitable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 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_USE_AWAITABLE_HPP +#define BOOST_ASIO_IMPL_USE_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/async_result.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename Executor, typename T> +class awaitable_handler_base + : public awaitable_thread<Executor> +{ +public: + typedef void result_type; + typedef awaitable<T, Executor> awaitable_type; + + // Construct from the entry point of a new thread of execution. + awaitable_handler_base(awaitable<void, Executor> a, const Executor& ex) + : awaitable_thread<Executor>(std::move(a), ex) + { + } + + // Transfer ownership from another awaitable_thread. + explicit awaitable_handler_base(awaitable_thread<Executor>* h) + : awaitable_thread<Executor>(std::move(*h)) + { + } + +protected: + awaitable_frame<T, Executor>* frame() noexcept + { + return static_cast<awaitable_frame<T, Executor>*>(this->top_of_stack_); + } +}; + +template <typename, typename...> +class awaitable_handler; + +template <typename Executor> +class awaitable_handler<Executor, void> + : public awaitable_handler_base<Executor, void> +{ +public: + using awaitable_handler_base<Executor, void>::awaitable_handler_base; + + void operator()() + { + this->frame()->attach_thread(this); + this->frame()->return_void(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor> +class awaitable_handler<Executor, boost::system::error_code> + : public awaitable_handler_base<Executor, void> +{ +public: + using awaitable_handler_base<Executor, void>::awaitable_handler_base; + + void operator()(const boost::system::error_code& ec) + { + this->frame()->attach_thread(this); + if (ec) + this->frame()->set_error(ec); + else + this->frame()->return_void(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor> +class awaitable_handler<Executor, std::exception_ptr> + : public awaitable_handler_base<Executor, void> +{ +public: + using awaitable_handler_base<Executor, void>::awaitable_handler_base; + + void operator()(std::exception_ptr ex) + { + this->frame()->attach_thread(this); + if (ex) + this->frame()->set_except(ex); + else + this->frame()->return_void(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename T> +class awaitable_handler<Executor, T> + : public awaitable_handler_base<Executor, T> +{ +public: + using awaitable_handler_base<Executor, T>::awaitable_handler_base; + + template <typename Arg> + void operator()(Arg&& arg) + { + this->frame()->attach_thread(this); + this->frame()->return_value(std::forward<Arg>(arg)); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename T> +class awaitable_handler<Executor, boost::system::error_code, T> + : public awaitable_handler_base<Executor, T> +{ +public: + using awaitable_handler_base<Executor, T>::awaitable_handler_base; + + template <typename Arg> + void operator()(const boost::system::error_code& ec, Arg&& arg) + { + this->frame()->attach_thread(this); + if (ec) + this->frame()->set_error(ec); + else + this->frame()->return_value(std::forward<Arg>(arg)); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename T> +class awaitable_handler<Executor, std::exception_ptr, T> + : public awaitable_handler_base<Executor, T> +{ +public: + using awaitable_handler_base<Executor, T>::awaitable_handler_base; + + template <typename Arg> + void operator()(std::exception_ptr ex, Arg&& arg) + { + this->frame()->attach_thread(this); + if (ex) + this->frame()->set_except(ex); + else + this->frame()->return_value(std::forward<Arg>(arg)); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename... Ts> +class awaitable_handler + : public awaitable_handler_base<Executor, std::tuple<Ts...>> +{ +public: + using awaitable_handler_base<Executor, + std::tuple<Ts...>>::awaitable_handler_base; + + template <typename... Args> + void operator()(Args&&... args) + { + this->frame()->attach_thread(this); + this->frame()->return_values(std::forward<Args>(args)...); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename... Ts> +class awaitable_handler<Executor, boost::system::error_code, Ts...> + : public awaitable_handler_base<Executor, std::tuple<Ts...>> +{ +public: + using awaitable_handler_base<Executor, + std::tuple<Ts...>>::awaitable_handler_base; + + template <typename... Args> + void operator()(const boost::system::error_code& ec, Args&&... args) + { + this->frame()->attach_thread(this); + if (ec) + this->frame()->set_error(ec); + else + this->frame()->return_values(std::forward<Args>(args)...); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template <typename Executor, typename... Ts> +class awaitable_handler<Executor, std::exception_ptr, Ts...> + : public awaitable_handler_base<Executor, std::tuple<Ts...>> +{ +public: + using awaitable_handler_base<Executor, + std::tuple<Ts...>>::awaitable_handler_base; + + template <typename... Args> + void operator()(std::exception_ptr ex, Args&&... args) + { + this->frame()->attach_thread(this); + if (ex) + this->frame()->set_except(ex); + else + this->frame()->return_values(std::forward<Args>(args)...); + this->frame()->pop_frame(); + this->pump(); + } +}; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Executor, typename R, typename... Args> +class async_result<use_awaitable_t<Executor>, R(Args...)> +{ +public: + typedef typename detail::awaitable_handler< + Executor, typename decay<Args>::type...> handler_type; + typedef typename handler_type::awaitable_type return_type; + +#if defined(_MSC_VER) + template <typename T> + static T dummy_return() + { + return std::move(*static_cast<T*>(nullptr)); + } + + template <> + static void dummy_return() + { + } +#endif // defined(_MSC_VER) + + template <typename Initiation, typename... InitArgs> + static return_type initiate(Initiation initiation, + use_awaitable_t<Executor>, InitArgs... args) + { + co_await [&](auto* frame) + { + handler_type handler(frame->detach_thread()); + std::move(initiation)(std::move(handler), std::move(args)...); + return static_cast<handler_type*>(nullptr); + }; + + for (;;) {} // Never reached. +#if defined(_MSC_VER) + co_return dummy_return<typename return_type::value_type>(); +#endif // defined(_MSC_VER) + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_USE_AWAITABLE_HPP diff --git a/boost/asio/impl/use_future.hpp b/boost/asio/impl/use_future.hpp index fd75a7c8e8..83fb74aecb 100644 --- a/boost/asio/impl/use_future.hpp +++ b/boost/asio/impl/use_future.hpp @@ -2,7 +2,7 @@ // impl/use_future.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -879,56 +879,6 @@ public: #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) -#if !defined(BOOST_ASIO_NO_DEPRECATED) - -template <typename Allocator, typename Signature> -struct handler_type<use_future_t<Allocator>, Signature> -{ - typedef typename async_result<use_future_t<Allocator>, - Signature>::completion_handler_type type; -}; - -template <typename Signature, typename Allocator> -class async_result<detail::promise_handler<Signature, Allocator> > - : public detail::promise_async_result<Signature, Allocator> -{ -public: - typedef typename detail::promise_async_result< - Signature, Allocator>::return_type type; - - explicit async_result( - typename detail::promise_async_result< - Signature, Allocator>::completion_handler_type& h) - : detail::promise_async_result<Signature, Allocator>(h) - { - } -}; - -template <typename Function, typename Allocator, typename Signature> -struct handler_type<detail::packaged_token<Function, Allocator>, Signature> -{ - typedef typename async_result<detail::packaged_token<Function, Allocator>, - Signature>::completion_handler_type type; -}; - -template <typename Function, typename Allocator, typename Result> -class async_result<detail::packaged_handler<Function, Allocator, Result> > - : public detail::packaged_async_result<Function, Allocator, Result> -{ -public: - typedef typename detail::packaged_async_result< - Function, Allocator, Result>::return_type type; - - explicit async_result( - typename detail::packaged_async_result< - Function, Allocator, Result>::completion_handler_type& h) - : detail::packaged_async_result<Function, Allocator, Result>(h) - { - } -}; - -#endif // !defined(BOOST_ASIO_NO_DEPRECATED) - #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio diff --git a/boost/asio/impl/write.hpp b/boost/asio/impl/write.hpp index 0be48b89f4..96243591ec 100644 --- a/boost/asio/impl/write.hpp +++ b/boost/asio/impl/write.hpp @@ -2,7 +2,7 @@ // impl/write.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -28,6 +28,7 @@ #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> @@ -67,7 +68,8 @@ inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, >::type*) { return detail::write_buffer_sequence(s, buffers, - boost::asio::buffer_sequence_begin(buffers), completion_condition, ec); + boost::asio::buffer_sequence_begin(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); } template <typename SyncWriteStream, typename ConstBufferSequence> @@ -101,68 +103,76 @@ inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, >::type*) { boost::system::error_code ec; - std::size_t bytes_transferred = write(s, buffers, completion_condition, ec); + std::size_t bytes_transferred = write(s, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); boost::asio::detail::throw_error(ec, "write"); return bytes_transferred; } -template <typename SyncWriteStream, typename DynamicBuffer, +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition> std::size_t write(SyncWriteStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, boost::system::error_code& ec, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { - typename decay<DynamicBuffer>::type b( - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + typename decay<DynamicBuffer_v1>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); - std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec); + std::size_t bytes_transferred = write(s, b.data(), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); b.consume(bytes_transferred); return bytes_transferred; } -template <typename SyncWriteStream, typename DynamicBuffer> +template <typename SyncWriteStream, typename DynamicBuffer_v1> inline std::size_t write(SyncWriteStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = write(s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), ec); boost::asio::detail::throw_error(ec, "write"); return bytes_transferred; } -template <typename SyncWriteStream, typename DynamicBuffer> +template <typename SyncWriteStream, typename DynamicBuffer_v1> inline std::size_t write(SyncWriteStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, boost::system::error_code& ec, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { - return write(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + return write(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), ec); } -template <typename SyncWriteStream, typename DynamicBuffer, +template <typename SyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = write(s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), - completion_condition, ec); + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); boost::asio::detail::throw_error(ec, "write"); return bytes_transferred; } @@ -176,7 +186,8 @@ inline std::size_t write(SyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, boost::system::error_code& ec) { - return write(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); + return write(s, basic_streambuf_ref<Allocator>(b), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); } template <typename SyncWriteStream, typename Allocator> @@ -200,11 +211,68 @@ inline std::size_t write(SyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition) { - return write(s, basic_streambuf_ref<Allocator>(b), completion_condition); + return write(s, basic_streambuf_ref<Allocator>(b), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template <typename SyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + std::size_t bytes_transferred = write(s, buffers.data(0, buffers.size()), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + buffers.consume(bytes_transferred); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename DynamicBuffer_v2> +inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + transfer_all(), ec); + boost::asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename DynamicBuffer_v2> +inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + return write(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + transfer_all(), ec); +} + +template <typename SyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} namespace detail { @@ -216,7 +284,7 @@ namespace detail { public: write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, WriteHandler& handler) + CompletionCondition& completion_condition, WriteHandler& handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), @@ -237,9 +305,11 @@ namespace detail } write_op(write_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : detail::base_from_completion_cond<CompletionCondition>( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), stream_(other.stream_), - buffers_(other.buffers_), + buffers_(BOOST_ASIO_MOVE_CAST(buffers_type)(other.buffers_)), start_(other.start_), handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) { @@ -270,9 +340,11 @@ namespace detail } //private: + typedef boost::asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> buffers_type; + AsyncWriteStream& stream_; - boost::asio::detail::consuming_buffers<const_buffer, - ConstBufferSequence, ConstBufferIterator> buffers_; + buffers_type buffers_; int start_; WriteHandler handler_; }; @@ -338,7 +410,7 @@ namespace detail typename WriteHandler> inline void start_write_buffer_sequence_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, const ConstBufferIterator&, - CompletionCondition completion_condition, WriteHandler& handler) + CompletionCondition& completion_condition, WriteHandler& handler) { detail::write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>( @@ -346,6 +418,25 @@ namespace detail boost::system::error_code(), 0, 1); } + struct initiate_async_write_buffer_sequence + { + template <typename WriteHandler, typename AsyncWriteStream, + typename ConstBufferSequence, typename CompletionCondition> + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + AsyncWriteStream* s, const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + start_write_buffer_sequence_op(*s, buffers, + boost::asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) @@ -401,18 +492,10 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, is_const_buffer_sequence<ConstBufferSequence>::value >::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::start_write_buffer_sequence_op(s, buffers, - boost::asio::buffer_sequence_begin(buffers), completion_condition, - init.completion_handler); - - return init.result.get(); + return async_initiate<WriteHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_write_buffer_sequence(), handler, &s, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncWriteStream, typename ConstBufferSequence, @@ -425,31 +508,25 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, is_const_buffer_sequence<ConstBufferSequence>::value >::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::start_write_buffer_sequence_op(s, buffers, - boost::asio::buffer_sequence_begin(buffers), transfer_all(), - init.completion_handler); - - return init.result.get(); + return async_initiate<WriteHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_write_buffer_sequence(), + handler, &s, buffers, transfer_all()); } +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + namespace detail { - template <typename AsyncWriteStream, typename DynamicBuffer, + template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> - class write_dynbuf_op + class write_dynbuf_v1_op { public: template <typename BufferSequence> - write_dynbuf_op(AsyncWriteStream& stream, + write_dynbuf_v1_op(AsyncWriteStream& stream, BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, - CompletionCondition completion_condition, WriteHandler& handler) + CompletionCondition& completion_condition, WriteHandler& handler) : stream_(stream), buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), completion_condition_( @@ -459,7 +536,7 @@ namespace detail } #if defined(BOOST_ASIO_HAS_MOVE) - write_dynbuf_op(const write_dynbuf_op& other) + write_dynbuf_v1_op(const write_dynbuf_v1_op& other) : stream_(other.stream_), buffers_(other.buffers_), completion_condition_(other.completion_condition_), @@ -467,9 +544,9 @@ namespace detail { } - write_dynbuf_op(write_dynbuf_op&& other) + write_dynbuf_v1_op(write_dynbuf_v1_op&& other) : stream_(other.stream_), - buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), completion_condition_( BOOST_ASIO_MOVE_CAST(CompletionCondition)( other.completion_condition_)), @@ -484,8 +561,9 @@ namespace detail switch (start) { case 1: - async_write(stream_, buffers_.data(), completion_condition_, - BOOST_ASIO_MOVE_CAST(write_dynbuf_op)(*this)); + async_write(stream_, buffers_.data(), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition_), + BOOST_ASIO_MOVE_CAST(write_dynbuf_v1_op)(*this)); return; default: buffers_.consume(bytes_transferred); handler_(ec, static_cast<const std::size_t&>(bytes_transferred)); @@ -494,35 +572,35 @@ namespace detail //private: AsyncWriteStream& stream_; - DynamicBuffer buffers_; + DynamicBuffer_v1 buffers_; CompletionCondition completion_condition_; WriteHandler handler_; }; - template <typename AsyncWriteStream, typename DynamicBuffer, + template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline void* asio_handler_allocate(std::size_t size, - write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncWriteStream, typename DynamicBuffer, + template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncWriteStream, typename DynamicBuffer, + template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline bool asio_handler_is_continuation( - write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( @@ -530,10 +608,10 @@ namespace detail } template <typename Function, typename AsyncWriteStream, - typename DynamicBuffer, typename CompletionCondition, + typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline void asio_handler_invoke(Function& function, - write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -541,49 +619,72 @@ namespace detail } template <typename Function, typename AsyncWriteStream, - typename DynamicBuffer, typename CompletionCondition, + typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline void asio_handler_invoke(const Function& function, - write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + struct initiate_async_write_dynbuf_v1 + { + template <typename WriteHandler, typename AsyncWriteStream, + typename DynamicBuffer_v1, typename CompletionCondition> + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + AsyncWriteStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + write_dynbuf_v1_op<AsyncWriteStream, + typename decay<DynamicBuffer_v1>::type, + CompletionCondition, typename decay<WriteHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + completion_cond2.value, handler2.value)( + boost::system::error_code(), 0, 1); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) -template <typename AsyncWriteStream, typename DynamicBuffer, +template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler, typename Allocator> struct associated_allocator< - detail::write_dynbuf_op<AsyncWriteStream, - DynamicBuffer, CompletionCondition, WriteHandler>, + detail::write_dynbuf_v1_op<AsyncWriteStream, + DynamicBuffer_v1, CompletionCondition, WriteHandler>, Allocator> { typedef typename associated_allocator<WriteHandler, Allocator>::type type; static type get( - const detail::write_dynbuf_op<AsyncWriteStream, - DynamicBuffer, CompletionCondition, WriteHandler>& h, + const detail::write_dynbuf_v1_op<AsyncWriteStream, + DynamicBuffer_v1, CompletionCondition, WriteHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); } }; -template <typename AsyncWriteStream, typename DynamicBuffer, +template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler, typename Executor> struct associated_executor< - detail::write_dynbuf_op<AsyncWriteStream, - DynamicBuffer, CompletionCondition, WriteHandler>, + detail::write_dynbuf_v1_op<AsyncWriteStream, + DynamicBuffer_v1, CompletionCondition, WriteHandler>, Executor> { typedef typename associated_executor<WriteHandler, Executor>::type type; static type get( - const detail::write_dynbuf_op<AsyncWriteStream, - DynamicBuffer, CompletionCondition, WriteHandler>& h, + const detail::write_dynbuf_v1_op<AsyncWriteStream, + DynamicBuffer_v1, CompletionCondition, WriteHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); @@ -593,49 +694,40 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncWriteStream, - typename DynamicBuffer, typename WriteHandler> + typename DynamicBuffer_v1, typename WriteHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return async_write(s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); } -template <typename AsyncWriteStream, typename DynamicBuffer, +template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(WriteHandler) handler, typename enable_if< - is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value + && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::write_dynbuf_op<AsyncWriteStream, - typename decay<DynamicBuffer>::type, - CompletionCondition, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), - completion_condition, init.completion_handler)( - boost::system::error_code(), 0, 1); - - return init.result.get(); + return async_initiate<WriteHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_write_dynbuf_v1(), handler, &s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) @@ -662,11 +754,223 @@ async_write(AsyncWriteStream& s, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { return async_write(s, basic_streambuf_ref<Allocator>(b), - completion_condition, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), + BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template <typename AsyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename WriteHandler> + class write_dynbuf_v2_op + { + public: + template <typename BufferSequence> + write_dynbuf_v2_op(AsyncWriteStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + CompletionCondition& completion_condition, WriteHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + completion_condition_( + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + write_dynbuf_v2_op(const write_dynbuf_v2_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + completion_condition_(other.completion_condition_), + handler_(other.handler_) + { + } + + write_dynbuf_v2_op(write_dynbuf_v2_op&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + completion_condition_( + BOOST_ASIO_MOVE_CAST(CompletionCondition)( + other.completion_condition_)), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + switch (start) + { + case 1: + async_write(stream_, buffers_.data(0, buffers_.size()), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition_), + BOOST_ASIO_MOVE_CAST(write_dynbuf_v2_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + handler_(ec, static_cast<const std::size_t&>(bytes_transferred)); + } + } + + //private: + AsyncWriteStream& stream_; + DynamicBuffer_v2 buffers_; + CompletionCondition completion_condition_; + WriteHandler handler_; + }; + + template <typename AsyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, + CompletionCondition, WriteHandler>* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, + CompletionCondition, WriteHandler>* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename WriteHandler> + inline bool asio_handler_is_continuation( + write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, + CompletionCondition, WriteHandler>* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncWriteStream, + typename DynamicBuffer_v2, typename CompletionCondition, + typename WriteHandler> + inline void asio_handler_invoke(Function& function, + write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, + CompletionCondition, WriteHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncWriteStream, + typename DynamicBuffer_v2, typename CompletionCondition, + typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, + CompletionCondition, WriteHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_write_dynbuf_v2 + { + template <typename WriteHandler, typename AsyncWriteStream, + typename DynamicBuffer_v2, typename CompletionCondition> + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + AsyncWriteStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + write_dynbuf_v2_op<AsyncWriteStream, + typename decay<DynamicBuffer_v2>::type, + CompletionCondition, typename decay<WriteHandler>::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + completion_cond2.value, handler2.value)( + boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::write_dynbuf_v2_op<AsyncWriteStream, + DynamicBuffer_v2, CompletionCondition, WriteHandler>, + Allocator> +{ + typedef typename associated_allocator<WriteHandler, Allocator>::type type; + + static type get( + const detail::write_dynbuf_v2_op<AsyncWriteStream, + DynamicBuffer_v2, CompletionCondition, WriteHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename WriteHandler, typename Executor> +struct associated_executor< + detail::write_dynbuf_v2_op<AsyncWriteStream, + DynamicBuffer_v2, CompletionCondition, WriteHandler>, + Executor> +{ + typedef typename associated_executor<WriteHandler, Executor>::type type; + + static type get( + const detail::write_dynbuf_v2_op<AsyncWriteStream, + DynamicBuffer_v2, CompletionCondition, WriteHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncWriteStream, + typename DynamicBuffer_v2, typename WriteHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + return async_write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + transfer_all(), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +} + +template <typename AsyncWriteStream, typename DynamicBuffer_v2, + typename CompletionCondition, typename WriteHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_v2<DynamicBuffer_v2>::value + >::type*) +{ + return async_initiate<WriteHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_write_dynbuf_v2(), handler, &s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} } // namespace asio } // namespace boost diff --git a/boost/asio/impl/write_at.hpp b/boost/asio/impl/write_at.hpp index 6b597d2085..3cad9c5b50 100644 --- a/boost/asio/impl/write_at.hpp +++ b/boost/asio/impl/write_at.hpp @@ -2,7 +2,7 @@ // impl/write_at.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2019 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) @@ -28,6 +28,7 @@ #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> @@ -69,7 +70,8 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, CompletionCondition completion_condition, boost::system::error_code& ec) { return detail::write_at_buffer_sequence(d, offset, buffers, - boost::asio::buffer_sequence_begin(buffers), completion_condition, ec); + boost::asio::buffer_sequence_begin(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); } template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence> @@ -98,8 +100,8 @@ inline std::size_t write_at(SyncRandomAccessWriteDevice& d, CompletionCondition completion_condition) { boost::system::error_code ec; - std::size_t bytes_transferred = write_at( - d, offset, buffers, completion_condition, ec); + std::size_t bytes_transferred = write_at(d, offset, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); boost::asio::detail::throw_error(ec, "write_at"); return bytes_transferred; } @@ -113,8 +115,8 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, boost::system::error_code& ec) { - std::size_t bytes_transferred = write_at( - d, offset, b.data(), completion_condition, ec); + std::size_t bytes_transferred = write_at(d, offset, b.data(), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); b.consume(bytes_transferred); return bytes_transferred; } @@ -144,8 +146,8 @@ inline std::size_t write_at(SyncRandomAccessWriteDevice& d, CompletionCondition completion_condition) { boost::system::error_code ec; - std::size_t bytes_transferred = write_at( - d, offset, b, completion_condition, ec); + std::size_t bytes_transferred = write_at(d, offset, b, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); boost::asio::detail::throw_error(ec, "write_at"); return bytes_transferred; } @@ -164,7 +166,7 @@ namespace detail public: write_at_op(AsyncRandomAccessWriteDevice& device, uint64_t offset, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, WriteHandler& handler) + CompletionCondition& completion_condition, WriteHandler& handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), device_(device), @@ -187,10 +189,12 @@ namespace detail } write_at_op(write_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), + : detail::base_from_completion_cond<CompletionCondition>( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), device_(other.device_), offset_(other.offset_), - buffers_(other.buffers_), + buffers_(BOOST_ASIO_MOVE_CAST(buffers_type)(other.buffers_)), start_(other.start_), handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) { @@ -222,10 +226,12 @@ namespace detail } //private: + typedef boost::asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> buffers_type; + AsyncRandomAccessWriteDevice& device_; uint64_t offset_; - boost::asio::detail::consuming_buffers<const_buffer, - ConstBufferSequence, ConstBufferIterator> buffers_; + buffers_type buffers_; int start_; WriteHandler handler_; }; @@ -291,7 +297,7 @@ namespace detail typename CompletionCondition, typename WriteHandler> inline void start_write_at_buffer_sequence_op(AsyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, - const ConstBufferIterator&, CompletionCondition completion_condition, + const ConstBufferIterator&, CompletionCondition& completion_condition, WriteHandler& handler) { detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, @@ -299,6 +305,27 @@ namespace detail d, offset, buffers, completion_condition, handler)( boost::system::error_code(), 0, 1); } + + struct initiate_async_write_at_buffer_sequence + { + template <typename WriteHandler, typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename CompletionCondition> + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + AsyncRandomAccessWriteDevice* d, uint64_t offset, + const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); + start_write_at_buffer_sequence_op(*d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) @@ -354,18 +381,10 @@ async_write_at(AsyncRandomAccessWriteDevice& d, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::start_write_at_buffer_sequence_op(d, offset, buffers, - boost::asio::buffer_sequence_begin(buffers), completion_condition, - init.completion_handler); - - return init.result.get(); + return async_initiate<WriteHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_write_at_buffer_sequence(), handler, &d, offset, + buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, @@ -376,18 +395,10 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - detail::start_write_at_buffer_sequence_op(d, offset, buffers, - boost::asio::buffer_sequence_begin(buffers), transfer_all(), - init.completion_handler); - - return init.result.get(); + return async_initiate<WriteHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_write_at_buffer_sequence(), + handler, &d, offset, buffers, transfer_all()); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) @@ -473,13 +484,26 @@ namespace detail function, this_handler->handler_); } - template <typename Allocator, typename WriteHandler> - inline write_at_streambuf_op<Allocator, WriteHandler> - make_write_at_streambuf_op( - boost::asio::basic_streambuf<Allocator>& b, WriteHandler handler) + struct initiate_async_write_at_streambuf { - return write_at_streambuf_op<Allocator, WriteHandler>(b, handler); - } + template <typename WriteHandler, typename AsyncRandomAccessWriteDevice, + typename Allocator, typename CompletionCondition> + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + AsyncRandomAccessWriteDevice* d, uint64_t offset, + basic_streambuf<Allocator>* b, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_condition) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue<WriteHandler> handler2(handler); + async_write_at(*d, offset, b->data(), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), + write_at_streambuf_op<Allocator, typename decay<WriteHandler>::type>( + *b, handler2.value)); + } + }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) @@ -525,19 +549,10 @@ async_write_at(AsyncRandomAccessWriteDevice& d, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - async_write_at(d, offset, b.data(), completion_condition, - detail::write_at_streambuf_op<Allocator, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - b, init.completion_handler)); - - return init.result.get(); + return async_initiate<WriteHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_write_at_streambuf(), handler, &d, offset, + &b, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncRandomAccessWriteDevice, typename Allocator, @@ -548,19 +563,10 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - async_completion<WriteHandler, - void (boost::system::error_code, std::size_t)> init(handler); - - async_write_at(d, offset, b.data(), transfer_all(), - detail::write_at_streambuf_op<Allocator, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - b, init.completion_handler)); - - return init.result.get(); + return async_initiate<WriteHandler, + void (boost::system::error_code, std::size_t)>( + detail::initiate_async_write_at_streambuf(), + handler, &d, offset, &b, transfer_all()); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) |