diff options
Diffstat (limited to 'lib/asio/impl')
31 files changed, 10140 insertions, 0 deletions
diff --git a/lib/asio/impl/buffered_read_stream.hpp b/lib/asio/impl/buffered_read_stream.hpp new file mode 100644 index 0000000..e0ed20e --- /dev/null +++ b/lib/asio/impl/buffered_read_stream.hpp @@ -0,0 +1,429 @@ +// +// impl/buffered_read_stream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_BUFFERED_READ_STREAM_HPP +#define ASIO_IMPL_BUFFERED_READ_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_type_requirements.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename Stream> +std::size_t buffered_read_stream<Stream>::fill() +{ + detail::buffer_resize_guard<detail::buffered_stream_storage> + resize_guard(storage_); + std::size_t previous_size = storage_.size(); + storage_.resize(storage_.capacity()); + storage_.resize(previous_size + next_layer_.read_some(buffer( + storage_.data() + previous_size, + storage_.size() - previous_size))); + resize_guard.commit(); + return storage_.size() - previous_size; +} + +template <typename Stream> +std::size_t buffered_read_stream<Stream>::fill(asio::error_code& ec) +{ + detail::buffer_resize_guard<detail::buffered_stream_storage> + resize_guard(storage_); + std::size_t previous_size = storage_.size(); + storage_.resize(storage_.capacity()); + storage_.resize(previous_size + next_layer_.read_some(buffer( + storage_.data() + previous_size, + storage_.size() - previous_size), + ec)); + resize_guard.commit(); + return storage_.size() - previous_size; +} + +namespace detail +{ + template <typename ReadHandler> + class buffered_fill_handler + { + public: + buffered_fill_handler(detail::buffered_stream_storage& storage, + std::size_t previous_size, ReadHandler& handler) + : storage_(storage), + previous_size_(previous_size), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + buffered_fill_handler(const buffered_fill_handler& other) + : storage_(other.storage_), + previous_size_(other.previous_size_), + handler_(other.handler_) + { + } + + buffered_fill_handler(buffered_fill_handler&& other) + : storage_(other.storage_), + previous_size_(other.previous_size_), + handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, + const std::size_t bytes_transferred) + { + storage_.resize(previous_size_ + bytes_transferred); + handler_(ec, bytes_transferred); + } + + //private: + detail::buffered_stream_storage& storage_; + std::size_t previous_size_; + ReadHandler handler_; + }; + + template <typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + buffered_fill_handler<ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + buffered_fill_handler<ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename ReadHandler> + inline bool asio_handler_is_continuation( + buffered_fill_handler<ReadHandler>* this_handler) + { + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename ReadHandler> + inline void asio_handler_invoke(Function& function, + buffered_fill_handler<ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + buffered_fill_handler<ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::buffered_fill_handler<ReadHandler>, Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get(const detail::buffered_fill_handler<ReadHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename ReadHandler, typename Executor> +struct associated_executor< + detail::buffered_fill_handler<ReadHandler>, Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get(const detail::buffered_fill_handler<ReadHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename Stream> +template <typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +buffered_read_stream<Stream>::async_fill( + 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::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<ASIO_HANDLER_TYPE( + ReadHandler, void (asio::error_code, std::size_t))>( + storage_, previous_size, init.completion_handler)); + + return init.result.get(); +} + +template <typename Stream> +template <typename MutableBufferSequence> +std::size_t buffered_read_stream<Stream>::read_some( + const MutableBufferSequence& buffers) +{ + using asio::buffer_size; + if (buffer_size(buffers) == 0) + return 0; + + if (storage_.empty()) + this->fill(); + + return this->copy(buffers); +} + +template <typename Stream> +template <typename MutableBufferSequence> +std::size_t buffered_read_stream<Stream>::read_some( + const MutableBufferSequence& buffers, asio::error_code& ec) +{ + ec = asio::error_code(); + + using asio::buffer_size; + if (buffer_size(buffers) == 0) + return 0; + + if (storage_.empty() && !this->fill(ec)) + return 0; + + return this->copy(buffers); +} + +namespace detail +{ + template <typename MutableBufferSequence, typename ReadHandler> + class buffered_read_some_handler + { + public: + buffered_read_some_handler(detail::buffered_stream_storage& storage, + const MutableBufferSequence& buffers, ReadHandler& handler) + : storage_(storage), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + buffered_read_some_handler(const buffered_read_some_handler& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(other.handler_) + { + } + + buffered_read_some_handler(buffered_read_some_handler&& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, std::size_t) + { + if (ec || storage_.empty()) + { + const std::size_t length = 0; + handler_(ec, length); + } + else + { + const std::size_t bytes_copied = asio::buffer_copy( + buffers_, storage_.data(), storage_.size()); + storage_.consume(bytes_copied); + handler_(ec, bytes_copied); + } + } + + //private: + detail::buffered_stream_storage& storage_; + MutableBufferSequence buffers_; + ReadHandler handler_; + }; + + template <typename MutableBufferSequence, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + buffered_read_some_handler< + MutableBufferSequence, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename MutableBufferSequence, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + buffered_read_some_handler< + MutableBufferSequence, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename MutableBufferSequence, typename ReadHandler> + inline bool asio_handler_is_continuation( + buffered_read_some_handler< + MutableBufferSequence, ReadHandler>* this_handler) + { + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename MutableBufferSequence, + typename ReadHandler> + inline void asio_handler_invoke(Function& function, + buffered_read_some_handler< + MutableBufferSequence, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename MutableBufferSequence, + typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + buffered_read_some_handler< + MutableBufferSequence, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename MutableBufferSequence, + typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::buffered_read_some_handler< + MutableBufferSequence, ReadHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename MutableBufferSequence, + typename ReadHandler, typename Executor> +struct associated_executor< + detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::buffered_read_some_handler< + MutableBufferSequence, ReadHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename Stream> +template <typename MutableBufferSequence, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +buffered_read_stream<Stream>::async_read_some( + const MutableBufferSequence& buffers, + 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + using asio::buffer_size; + if (buffer_size(buffers) == 0 || !storage_.empty()) + { + next_layer_.async_read_some(ASIO_MUTABLE_BUFFER(0, 0), + detail::buffered_read_some_handler< + MutableBufferSequence, ASIO_HANDLER_TYPE( + ReadHandler, void (asio::error_code, std::size_t))>( + storage_, buffers, init.completion_handler)); + } + else + { + this->async_fill(detail::buffered_read_some_handler< + MutableBufferSequence, ASIO_HANDLER_TYPE( + ReadHandler, void (asio::error_code, std::size_t))>( + storage_, buffers, init.completion_handler)); + } + + return init.result.get(); +} + +template <typename Stream> +template <typename MutableBufferSequence> +std::size_t buffered_read_stream<Stream>::peek( + const MutableBufferSequence& buffers) +{ + if (storage_.empty()) + this->fill(); + return this->peek_copy(buffers); +} + +template <typename Stream> +template <typename MutableBufferSequence> +std::size_t buffered_read_stream<Stream>::peek( + const MutableBufferSequence& buffers, asio::error_code& ec) +{ + ec = asio::error_code(); + if (storage_.empty() && !this->fill(ec)) + return 0; + return this->peek_copy(buffers); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_BUFFERED_READ_STREAM_HPP diff --git a/lib/asio/impl/buffered_write_stream.hpp b/lib/asio/impl/buffered_write_stream.hpp new file mode 100644 index 0000000..bc2d823 --- /dev/null +++ b/lib/asio/impl/buffered_write_stream.hpp @@ -0,0 +1,411 @@ +// +// impl/buffered_write_stream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP +#define ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_type_requirements.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename Stream> +std::size_t buffered_write_stream<Stream>::flush() +{ + std::size_t bytes_written = write(next_layer_, + buffer(storage_.data(), storage_.size())); + storage_.consume(bytes_written); + return bytes_written; +} + +template <typename Stream> +std::size_t buffered_write_stream<Stream>::flush(asio::error_code& ec) +{ + std::size_t bytes_written = write(next_layer_, + buffer(storage_.data(), storage_.size()), + transfer_all(), ec); + storage_.consume(bytes_written); + return bytes_written; +} + +namespace detail +{ + template <typename WriteHandler> + class buffered_flush_handler + { + public: + buffered_flush_handler(detail::buffered_stream_storage& storage, + WriteHandler& handler) + : storage_(storage), + handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + buffered_flush_handler(const buffered_flush_handler& other) + : storage_(other.storage_), + handler_(other.handler_) + { + } + + buffered_flush_handler(buffered_flush_handler&& other) + : storage_(other.storage_), + handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, + const std::size_t bytes_written) + { + storage_.consume(bytes_written); + handler_(ec, bytes_written); + } + + //private: + detail::buffered_stream_storage& storage_; + WriteHandler handler_; + }; + + template <typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + buffered_flush_handler<WriteHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + buffered_flush_handler<WriteHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename WriteHandler> + inline bool asio_handler_is_continuation( + buffered_flush_handler<WriteHandler>* this_handler) + { + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename WriteHandler> + inline void asio_handler_invoke(Function& function, + buffered_flush_handler<WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + buffered_flush_handler<WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::buffered_flush_handler<WriteHandler>, Allocator> +{ + typedef typename associated_allocator<WriteHandler, Allocator>::type type; + + static type get(const detail::buffered_flush_handler<WriteHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename WriteHandler, typename Executor> +struct associated_executor< + detail::buffered_flush_handler<WriteHandler>, Executor> +{ + typedef typename associated_executor<WriteHandler, Executor>::type type; + + static type get(const detail::buffered_flush_handler<WriteHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename Stream> +template <typename WriteHandler> +ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +buffered_write_stream<Stream>::async_flush( + 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. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + async_write(next_layer_, buffer(storage_.data(), storage_.size()), + detail::buffered_flush_handler<ASIO_HANDLER_TYPE( + WriteHandler, void (asio::error_code, std::size_t))>( + storage_, init.completion_handler)); + + return init.result.get(); +} + +template <typename Stream> +template <typename ConstBufferSequence> +std::size_t buffered_write_stream<Stream>::write_some( + const ConstBufferSequence& buffers) +{ + using asio::buffer_size; + if (buffer_size(buffers) == 0) + return 0; + + if (storage_.size() == storage_.capacity()) + this->flush(); + + return this->copy(buffers); +} + +template <typename Stream> +template <typename ConstBufferSequence> +std::size_t buffered_write_stream<Stream>::write_some( + const ConstBufferSequence& buffers, asio::error_code& ec) +{ + ec = asio::error_code(); + + using asio::buffer_size; + if (buffer_size(buffers) == 0) + return 0; + + if (storage_.size() == storage_.capacity() && !flush(ec)) + return 0; + + return this->copy(buffers); +} + +namespace detail +{ + template <typename ConstBufferSequence, typename WriteHandler> + class buffered_write_some_handler + { + public: + buffered_write_some_handler(detail::buffered_stream_storage& storage, + const ConstBufferSequence& buffers, WriteHandler& handler) + : storage_(storage), + buffers_(buffers), + handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + buffered_write_some_handler(const buffered_write_some_handler& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(other.handler_) + { + } + + buffered_write_some_handler(buffered_write_some_handler&& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, std::size_t) + { + if (ec) + { + const std::size_t length = 0; + handler_(ec, length); + } + else + { + using asio::buffer_size; + std::size_t orig_size = storage_.size(); + std::size_t space_avail = storage_.capacity() - orig_size; + std::size_t bytes_avail = buffer_size(buffers_); + std::size_t length = bytes_avail < space_avail + ? bytes_avail : space_avail; + storage_.resize(orig_size + length); + const std::size_t bytes_copied = asio::buffer_copy( + storage_.data() + orig_size, buffers_, length); + handler_(ec, bytes_copied); + } + } + + //private: + detail::buffered_stream_storage& storage_; + ConstBufferSequence buffers_; + WriteHandler handler_; + }; + + template <typename ConstBufferSequence, typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + buffered_write_some_handler< + ConstBufferSequence, WriteHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename ConstBufferSequence, typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + buffered_write_some_handler< + ConstBufferSequence, WriteHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename ConstBufferSequence, typename WriteHandler> + inline bool asio_handler_is_continuation( + buffered_write_some_handler< + ConstBufferSequence, WriteHandler>* this_handler) + { + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename ConstBufferSequence, + typename WriteHandler> + inline void asio_handler_invoke(Function& function, + buffered_write_some_handler< + ConstBufferSequence, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename ConstBufferSequence, + typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + buffered_write_some_handler< + ConstBufferSequence, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename ConstBufferSequence, + typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>, + Allocator> +{ + typedef typename associated_allocator<WriteHandler, Allocator>::type type; + + static type get( + const detail::buffered_write_some_handler< + ConstBufferSequence, WriteHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename ConstBufferSequence, + typename WriteHandler, typename Executor> +struct associated_executor< + detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>, + Executor> +{ + typedef typename associated_executor<WriteHandler, Executor>::type type; + + static type get( + const detail::buffered_write_some_handler< + ConstBufferSequence, WriteHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename Stream> +template <typename ConstBufferSequence, typename WriteHandler> +ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +buffered_write_stream<Stream>::async_write_some( + const ConstBufferSequence& buffers, + 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. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + using asio::buffer_size; + if (buffer_size(buffers) == 0 + || storage_.size() < storage_.capacity()) + { + next_layer_.async_write_some(ASIO_CONST_BUFFER(0, 0), + detail::buffered_write_some_handler< + ConstBufferSequence, ASIO_HANDLER_TYPE( + WriteHandler, void (asio::error_code, std::size_t))>( + storage_, buffers, init.completion_handler)); + } + else + { + this->async_flush(detail::buffered_write_some_handler< + ConstBufferSequence, ASIO_HANDLER_TYPE( + WriteHandler, void (asio::error_code, std::size_t))>( + storage_, buffers, init.completion_handler)); + } + + return init.result.get(); +} + +template <typename Stream> +template <typename ConstBufferSequence> +std::size_t buffered_write_stream<Stream>::copy( + const ConstBufferSequence& buffers) +{ + using asio::buffer_size; + std::size_t orig_size = storage_.size(); + std::size_t space_avail = storage_.capacity() - orig_size; + std::size_t bytes_avail = buffer_size(buffers); + std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail; + storage_.resize(orig_size + length); + return asio::buffer_copy( + storage_.data() + orig_size, buffers, length); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP diff --git a/lib/asio/impl/connect.hpp b/lib/asio/impl/connect.hpp new file mode 100644 index 0000000..bff1913 --- /dev/null +++ b/lib/asio/impl/connect.hpp @@ -0,0 +1,860 @@ +// +// impl/connect.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_CONNECT_HPP +#define ASIO_IMPL_CONNECT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <algorithm> +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" +#include "asio/post.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +namespace detail +{ + struct default_connect_condition + { + template <typename Endpoint> + bool operator()(const asio::error_code&, const Endpoint&) + { + return true; + } + }; + + template <typename Protocol, typename Iterator> + inline typename Protocol::endpoint deref_connect_result( + Iterator iter, asio::error_code& ec) + { + return ec ? typename Protocol::endpoint() : *iter; + } + + template <typename T, typename Iterator> + struct legacy_connect_condition_helper : T + { + typedef char (*fallback_func_type)(...); + operator fallback_func_type() const; + }; + + template <typename R, typename Arg1, typename Arg2, typename Iterator> + struct legacy_connect_condition_helper<R (*)(Arg1, Arg2), Iterator> + { + R operator()(Arg1, Arg2) const; + char operator()(...) const; + }; + + template <typename T, typename Iterator> + struct is_legacy_connect_condition + { + static char asio_connect_condition_check(char); + static char (&asio_connect_condition_check(Iterator))[2]; + + static const bool value = + sizeof(asio_connect_condition_check( + (*static_cast<legacy_connect_condition_helper<T, Iterator>*>(0))( + *static_cast<const asio::error_code*>(0), + *static_cast<const Iterator*>(0)))) != 1; + }; + + template <typename ConnectCondition, typename Iterator> + inline Iterator call_connect_condition(ConnectCondition& connect_condition, + const asio::error_code& ec, Iterator next, Iterator end, + typename enable_if<is_legacy_connect_condition< + ConnectCondition, Iterator>::value>::type* = 0) + { + if (next != end) + return connect_condition(ec, next); + return end; + } + + template <typename ConnectCondition, typename Iterator> + inline Iterator call_connect_condition(ConnectCondition& connect_condition, + const asio::error_code& ec, Iterator next, Iterator end, + typename enable_if<!is_legacy_connect_condition< + ConnectCondition, Iterator>::value>::type* = 0) + { + for (;next != end; ++next) + if (connect_condition(ec, *next)) + return next; + return end; + } +} + +template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence> +typename Protocol::endpoint connect( + basic_socket<Protocol ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type*) +{ + asio::error_code ec; + typename Protocol::endpoint result = connect(s, endpoints, ec); + asio::detail::throw_error(ec, "connect"); + return result; +} + +template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence> +typename Protocol::endpoint connect( + basic_socket<Protocol ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, asio::error_code& ec, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type*) +{ + return detail::deref_connect_result<Protocol>( + connect(s, endpoints.begin(), endpoints.end(), + detail::default_connect_condition(), ec), ec); +} + +#if !defined(ASIO_NO_DEPRECATED) +template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> +Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, Iterator begin, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) +{ + asio::error_code ec; + Iterator result = connect(s, begin, ec); + asio::detail::throw_error(ec, "connect"); + return result; +} + +template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> +inline Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, asio::error_code& ec, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) +{ + return connect(s, begin, Iterator(), detail::default_connect_condition(), ec); +} +#endif // !defined(ASIO_NO_DEPRECATED) + +template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> +Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, Iterator end) +{ + asio::error_code ec; + Iterator result = connect(s, begin, end, ec); + asio::detail::throw_error(ec, "connect"); + return result; +} + +template <typename Protocol ASIO_SVC_TPARAM, typename Iterator> +inline Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, Iterator end, asio::error_code& ec) +{ + return connect(s, begin, end, detail::default_connect_condition(), ec); +} + +template <typename Protocol ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition> +typename Protocol::endpoint connect( + basic_socket<Protocol ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type*) +{ + asio::error_code ec; + typename Protocol::endpoint result = connect( + s, endpoints, connect_condition, ec); + asio::detail::throw_error(ec, "connect"); + return result; +} + +template <typename Protocol ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition> +typename Protocol::endpoint connect( + basic_socket<Protocol ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + asio::error_code& ec, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type*) +{ + return detail::deref_connect_result<Protocol>( + connect(s, endpoints.begin(), endpoints.end(), + connect_condition, ec), ec); +} + +#if !defined(ASIO_NO_DEPRECATED) +template <typename Protocol ASIO_SVC_TPARAM, + typename Iterator, typename ConnectCondition> +Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, ConnectCondition connect_condition, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) +{ + asio::error_code ec; + Iterator result = connect(s, begin, connect_condition, ec); + asio::detail::throw_error(ec, "connect"); + return result; +} + +template <typename Protocol ASIO_SVC_TPARAM, + typename Iterator, typename ConnectCondition> +inline Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, ConnectCondition connect_condition, + asio::error_code& ec, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) +{ + return connect(s, begin, Iterator(), connect_condition, ec); +} +#endif // !defined(ASIO_NO_DEPRECATED) + +template <typename Protocol ASIO_SVC_TPARAM, + typename Iterator, typename ConnectCondition> +Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, Iterator end, ConnectCondition connect_condition) +{ + asio::error_code ec; + Iterator result = connect(s, begin, end, connect_condition, ec); + asio::detail::throw_error(ec, "connect"); + return result; +} + +template <typename Protocol ASIO_SVC_TPARAM, + typename Iterator, typename ConnectCondition> +Iterator connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, Iterator end, ConnectCondition connect_condition, + asio::error_code& ec) +{ + ec = asio::error_code(); + + for (Iterator iter = begin; iter != end; ++iter) + { + iter = (detail::call_connect_condition(connect_condition, ec, iter, end)); + if (iter != end) + { + s.close(ec); + s.connect(*iter, ec); + if (!ec) + return iter; + } + else + break; + } + + if (!ec) + ec = asio::error::not_found; + + return end; +} + +namespace detail +{ + // Enable the empty base class optimisation for the connect condition. + template <typename ConnectCondition> + class base_from_connect_condition + { + protected: + explicit base_from_connect_condition( + const ConnectCondition& connect_condition) + : connect_condition_(connect_condition) + { + } + + template <typename Iterator> + void check_condition(const asio::error_code& ec, + Iterator& iter, Iterator& end) + { + iter = detail::call_connect_condition(connect_condition_, ec, iter, end); + } + + private: + ConnectCondition connect_condition_; + }; + + // The default_connect_condition implementation is essentially a no-op. This + // template specialisation lets us eliminate all costs associated with it. + template <> + class base_from_connect_condition<default_connect_condition> + { + protected: + explicit base_from_connect_condition(const default_connect_condition&) + { + } + + template <typename Iterator> + void check_condition(const asio::error_code&, Iterator&, Iterator&) + { + } + }; + + template <typename Protocol ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler> + class range_connect_op : base_from_connect_condition<ConnectCondition> + { + public: + range_connect_op(basic_socket<Protocol ASIO_SVC_TARG>& sock, + const EndpointSequence& endpoints, + const ConnectCondition& connect_condition, + RangeConnectHandler& handler) + : base_from_connect_condition<ConnectCondition>(connect_condition), + socket_(sock), + endpoints_(endpoints), + index_(0), + start_(0), + handler_(ASIO_MOVE_CAST(RangeConnectHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + range_connect_op(const range_connect_op& other) + : base_from_connect_condition<ConnectCondition>(other), + socket_(other.socket_), + endpoints_(other.endpoints_), + index_(other.index_), + start_(other.start_), + handler_(other.handler_) + { + } + + range_connect_op(range_connect_op&& other) + : base_from_connect_condition<ConnectCondition>(other), + socket_(other.socket_), + endpoints_(other.endpoints_), + index_(other.index_), + start_(other.start_), + handler_(ASIO_MOVE_CAST(RangeConnectHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(asio::error_code ec, int start = 0) + { + typename EndpointSequence::const_iterator begin = endpoints_.begin(); + typename EndpointSequence::const_iterator iter = begin; + std::advance(iter, index_); + typename EndpointSequence::const_iterator end = endpoints_.end(); + + switch (start_ = start) + { + case 1: + for (;;) + { + this->check_condition(ec, iter, end); + index_ = std::distance(begin, iter); + + if (iter != end) + { + socket_.close(ec); + socket_.async_connect(*iter, + ASIO_MOVE_CAST(range_connect_op)(*this)); + return; + } + + if (start) + { + ec = asio::error::not_found; + asio::post(socket_.get_executor(), + detail::bind_handler( + ASIO_MOVE_CAST(range_connect_op)(*this), ec)); + return; + } + + default: + + if (iter == end) + break; + + if (!socket_.is_open()) + { + ec = asio::error::operation_aborted; + break; + } + + if (!ec) + break; + + ++iter; + ++index_; + } + + handler_(static_cast<const asio::error_code&>(ec), + static_cast<const typename Protocol::endpoint&>( + ec || iter == end ? typename Protocol::endpoint() : *iter)); + } + } + + //private: + basic_socket<Protocol ASIO_SVC_TARG>& socket_; + EndpointSequence endpoints_; + std::size_t index_; + int start_; + RangeConnectHandler handler_; + }; + + template <typename Protocol ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler> + inline void* asio_handler_allocate(std::size_t size, + range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, RangeConnectHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename Protocol ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, RangeConnectHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Protocol ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler> + inline bool asio_handler_is_continuation( + range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, RangeConnectHandler>* this_handler) + { + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename Protocol + ASIO_SVC_TPARAM, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> + inline void asio_handler_invoke(Function& function, + range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, RangeConnectHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename Protocol + ASIO_SVC_TPARAM, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> + inline void asio_handler_invoke(const Function& function, + range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, RangeConnectHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> + class iterator_connect_op : base_from_connect_condition<ConnectCondition> + { + public: + iterator_connect_op(basic_socket<Protocol ASIO_SVC_TARG>& sock, + const Iterator& begin, const Iterator& end, + const ConnectCondition& connect_condition, + IteratorConnectHandler& handler) + : base_from_connect_condition<ConnectCondition>(connect_condition), + socket_(sock), + iter_(begin), + end_(end), + start_(0), + handler_(ASIO_MOVE_CAST(IteratorConnectHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + iterator_connect_op(const iterator_connect_op& other) + : base_from_connect_condition<ConnectCondition>(other), + socket_(other.socket_), + iter_(other.iter_), + end_(other.end_), + start_(other.start_), + handler_(other.handler_) + { + } + + iterator_connect_op(iterator_connect_op&& other) + : base_from_connect_condition<ConnectCondition>(other), + socket_(other.socket_), + iter_(other.iter_), + end_(other.end_), + start_(other.start_), + handler_(ASIO_MOVE_CAST(IteratorConnectHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(asio::error_code ec, int start = 0) + { + switch (start_ = start) + { + case 1: + for (;;) + { + this->check_condition(ec, iter_, end_); + + if (iter_ != end_) + { + socket_.close(ec); + socket_.async_connect(*iter_, + ASIO_MOVE_CAST(iterator_connect_op)(*this)); + return; + } + + if (start) + { + ec = asio::error::not_found; + asio::post(socket_.get_executor(), + detail::bind_handler( + ASIO_MOVE_CAST(iterator_connect_op)(*this), ec)); + return; + } + + default: + + if (iter_ == end_) + break; + + if (!socket_.is_open()) + { + ec = asio::error::operation_aborted; + break; + } + + if (!ec) + break; + + ++iter_; + } + + handler_(static_cast<const asio::error_code&>(ec), + static_cast<const Iterator&>(iter_)); + } + } + + //private: + basic_socket<Protocol ASIO_SVC_TARG>& socket_; + Iterator iter_; + Iterator end_; + int start_; + IteratorConnectHandler handler_; + }; + + template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> + inline void* asio_handler_allocate(std::size_t size, + iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> + inline bool asio_handler_is_continuation( + iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>* this_handler) + { + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename Protocol + ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> + inline void asio_handler_invoke(Function& function, + iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename Protocol + ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> + inline void asio_handler_invoke(const Function& function, + iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Protocol ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler, typename Allocator> +struct associated_allocator< + detail::range_connect_op<Protocol ASIO_SVC_TARG, + EndpointSequence, ConnectCondition, RangeConnectHandler>, + Allocator> +{ + typedef typename associated_allocator< + RangeConnectHandler, Allocator>::type type; + + static type get( + const detail::range_connect_op<Protocol ASIO_SVC_TARG, + EndpointSequence, ConnectCondition, RangeConnectHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<RangeConnectHandler, + Allocator>::get(h.handler_, a); + } +}; + +template <typename Protocol ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler, typename Executor> +struct associated_executor< + detail::range_connect_op<Protocol ASIO_SVC_TARG, + EndpointSequence, ConnectCondition, RangeConnectHandler>, + Executor> +{ + typedef typename associated_executor< + RangeConnectHandler, Executor>::type type; + + static type get( + const detail::range_connect_op<Protocol ASIO_SVC_TARG, + EndpointSequence, ConnectCondition, RangeConnectHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<RangeConnectHandler, + Executor>::get(h.handler_, ex); + } +}; + +template <typename Protocol ASIO_SVC_TPARAM, + typename Iterator, typename ConnectCondition, + typename IteratorConnectHandler, typename Allocator> +struct associated_allocator< + detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>, + Allocator> +{ + typedef typename associated_allocator< + IteratorConnectHandler, Allocator>::type type; + + static type get( + const detail::iterator_connect_op<Protocol ASIO_SVC_TARG, + Iterator, ConnectCondition, IteratorConnectHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<IteratorConnectHandler, + Allocator>::get(h.handler_, a); + } +}; + +template <typename Protocol ASIO_SVC_TPARAM, + typename Iterator, typename ConnectCondition, + typename IteratorConnectHandler, typename Executor> +struct associated_executor< + detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>, + Executor> +{ + typedef typename associated_executor< + IteratorConnectHandler, Executor>::type type; + + static type get( + const detail::iterator_connect_op<Protocol ASIO_SVC_TARG, + Iterator, ConnectCondition, IteratorConnectHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<IteratorConnectHandler, + Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename Protocol ASIO_SVC_TPARAM, + typename EndpointSequence, typename RangeConnectHandler> +inline ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (asio::error_code, typename Protocol::endpoint)) +async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, + 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. + ASIO_RANGE_CONNECT_HANDLER_CHECK( + RangeConnectHandler, handler, typename Protocol::endpoint) type_check; + + async_completion<RangeConnectHandler, + void (asio::error_code, typename Protocol::endpoint)> + init(handler); + + detail::range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, + detail::default_connect_condition, + ASIO_HANDLER_TYPE(RangeConnectHandler, + void (asio::error_code, typename Protocol::endpoint))>(s, + endpoints, detail::default_connect_condition(), + init.completion_handler)(asio::error_code(), 1); + + return init.result.get(); +} + +#if !defined(ASIO_NO_DEPRECATED) +template <typename Protocol ASIO_SVC_TPARAM, + typename Iterator, typename IteratorConnectHandler> +inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (asio::error_code, Iterator)) +async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, 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. + ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; + + async_completion<IteratorConnectHandler, + void (asio::error_code, Iterator)> init(handler); + + detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + detail::default_connect_condition, ASIO_HANDLER_TYPE( + IteratorConnectHandler, void (asio::error_code, Iterator))>(s, + begin, Iterator(), detail::default_connect_condition(), + init.completion_handler)(asio::error_code(), 1); + + return init.result.get(); +} +#endif // !defined(ASIO_NO_DEPRECATED) + +template <typename Protocol ASIO_SVC_TPARAM, + typename Iterator, typename IteratorConnectHandler> +inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (asio::error_code, Iterator)) +async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, Iterator end, + 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. + ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; + + async_completion<IteratorConnectHandler, + void (asio::error_code, Iterator)> init(handler); + + detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + detail::default_connect_condition, ASIO_HANDLER_TYPE( + IteratorConnectHandler, void (asio::error_code, Iterator))>(s, + begin, end, detail::default_connect_condition(), + init.completion_handler)(asio::error_code(), 1); + + return init.result.get(); +} + +template <typename Protocol ASIO_SVC_TPARAM, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> +inline ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (asio::error_code, typename Protocol::endpoint)) +async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + 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. + ASIO_RANGE_CONNECT_HANDLER_CHECK( + RangeConnectHandler, handler, typename Protocol::endpoint) type_check; + + async_completion<RangeConnectHandler, + void (asio::error_code, typename Protocol::endpoint)> + init(handler); + + detail::range_connect_op<Protocol ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, ASIO_HANDLER_TYPE(RangeConnectHandler, + void (asio::error_code, typename Protocol::endpoint))>(s, + endpoints, connect_condition, init.completion_handler)( + asio::error_code(), 1); + + return init.result.get(); +} + +#if !defined(ASIO_NO_DEPRECATED) +template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> +inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (asio::error_code, Iterator)) +async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, ConnectCondition connect_condition, + 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. + ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; + + async_completion<IteratorConnectHandler, + void (asio::error_code, Iterator)> init(handler); + + detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + ConnectCondition, ASIO_HANDLER_TYPE( + IteratorConnectHandler, void (asio::error_code, Iterator))>(s, + begin, Iterator(), connect_condition, init.completion_handler)( + asio::error_code(), 1); + + return init.result.get(); +} +#endif // !defined(ASIO_NO_DEPRECATED) + +template <typename Protocol ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> +inline ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (asio::error_code, Iterator)) +async_connect(basic_socket<Protocol ASIO_SVC_TARG>& s, + Iterator begin, Iterator end, ConnectCondition connect_condition, + 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. + ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; + + async_completion<IteratorConnectHandler, + void (asio::error_code, Iterator)> init(handler); + + detail::iterator_connect_op<Protocol ASIO_SVC_TARG, Iterator, + ConnectCondition, ASIO_HANDLER_TYPE( + IteratorConnectHandler, void (asio::error_code, Iterator))>(s, + begin, end, connect_condition, init.completion_handler)( + asio::error_code(), 1); + + return init.result.get(); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_CONNECT_HPP diff --git a/lib/asio/impl/defer.hpp b/lib/asio/impl/defer.hpp new file mode 100644 index 0000000..a27df0f --- /dev/null +++ b/lib/asio/impl/defer.hpp @@ -0,0 +1,77 @@ +// +// impl/defer.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_DEFER_HPP +#define ASIO_IMPL_DEFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/work_dispatcher.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename CompletionToken> +ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + + async_completion<CompletionToken, void()> init(token); + + typename associated_executor<handler>::type ex( + (get_associated_executor)(init.completion_handler)); + + typename associated_allocator<handler>::type alloc( + (get_associated_allocator)(init.completion_handler)); + + ex.defer(ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); + + return init.result.get(); +} + +template <typename Executor, typename CompletionToken> +ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_executor<Executor>::value>::type*) +{ + typedef 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(); +} + +template <typename ExecutionContext, typename CompletionToken> +inline ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type*) +{ + return (defer)(ctx.get_executor(), + ASIO_MOVE_CAST(CompletionToken)(token)); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_DEFER_HPP diff --git a/lib/asio/impl/dispatch.hpp b/lib/asio/impl/dispatch.hpp new file mode 100644 index 0000000..4e11c6b --- /dev/null +++ b/lib/asio/impl/dispatch.hpp @@ -0,0 +1,78 @@ +// +// impl/dispatch.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_DISPATCH_HPP +#define ASIO_IMPL_DISPATCH_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/work_dispatcher.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename CompletionToken> +ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + + async_completion<CompletionToken, void()> init(token); + + typename associated_executor<handler>::type ex( + (get_associated_executor)(init.completion_handler)); + + typename associated_allocator<handler>::type alloc( + (get_associated_allocator)(init.completion_handler)); + + ex.dispatch(ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); + + return init.result.get(); +} + +template <typename Executor, typename CompletionToken> +ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_executor<Executor>::value>::type*) +{ + typedef 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(); +} + +template <typename ExecutionContext, typename CompletionToken> +inline ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type*) +{ + return (dispatch)(ctx.get_executor(), + ASIO_MOVE_CAST(CompletionToken)(token)); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_DISPATCH_HPP diff --git a/lib/asio/impl/error.ipp b/lib/asio/impl/error.ipp new file mode 100644 index 0000000..6b1f33a --- /dev/null +++ b/lib/asio/impl/error.ipp @@ -0,0 +1,128 @@ +// +// impl/error.ipp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_ERROR_IPP +#define ASIO_IMPL_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <string> +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace error { + +#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +namespace detail { + +class netdb_category : public asio::error_category +{ +public: + const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + { + return "asio.netdb"; + } + + std::string message(int value) const + { + if (value == error::host_not_found) + return "Host not found (authoritative)"; + if (value == error::host_not_found_try_again) + return "Host not found (non-authoritative), try again later"; + if (value == error::no_data) + return "The query is valid, but it does not have associated data"; + if (value == error::no_recovery) + return "A non-recoverable error occurred during database lookup"; + return "asio.netdb error"; + } +}; + +} // namespace detail + +const asio::error_category& get_netdb_category() +{ + static detail::netdb_category instance; + return instance; +} + +namespace detail { + +class addrinfo_category : public asio::error_category +{ +public: + const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + { + return "asio.addrinfo"; + } + + std::string message(int value) const + { + if (value == error::service_not_found) + return "Service not found"; + if (value == error::socket_type_not_supported) + return "Socket type not supported"; + return "asio.addrinfo error"; + } +}; + +} // namespace detail + +const asio::error_category& get_addrinfo_category() +{ + static detail::addrinfo_category instance; + return instance; +} + +#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__) + +namespace detail { + +class misc_category : public asio::error_category +{ +public: + const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + { + return "asio.misc"; + } + + std::string message(int value) const + { + if (value == error::already_open) + return "Already open"; + if (value == error::eof) + return "End of file"; + if (value == error::not_found) + return "Element not found"; + if (value == error::fd_set_failure) + return "The descriptor does not fit into the select call's fd_set"; + return "asio.misc error"; + } +}; + +} // namespace detail + +const asio::error_category& get_misc_category() +{ + static detail::misc_category instance; + return instance; +} + +} // namespace error +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_ERROR_IPP diff --git a/lib/asio/impl/error_code.ipp b/lib/asio/impl/error_code.ipp new file mode 100644 index 0000000..0c8a827 --- /dev/null +++ b/lib/asio/impl/error_code.ipp @@ -0,0 +1,206 @@ +// +// impl/error_code.ipp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_ERROR_CODE_IPP +#define ASIO_IMPL_ERROR_CODE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# include <winerror.h> +#elif defined(ASIO_WINDOWS_RUNTIME) +# include <windows.h> +#else +# include <cerrno> +# include <cstring> +# include <string> +#endif +#include "asio/detail/local_free_on_block_exit.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/error_code.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class system_category : public error_category +{ +public: + const char* name() const ASIO_ERROR_CATEGORY_NOEXCEPT + { + return "asio.system"; + } + + std::string message(int value) const + { +#if defined(ASIO_WINDOWS_RUNTIME) || defined(ASIO_WINDOWS_APP) + std::wstring wmsg(128, wchar_t()); + for (;;) + { + DWORD wlength = ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + &wmsg[0], static_cast<DWORD>(wmsg.size()), 0); + if (wlength == 0 && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + wmsg.resize(wmsg.size() + wmsg.size() / 2); + continue; + } + if (wlength && wmsg[wlength - 1] == '\n') + --wlength; + if (wlength && wmsg[wlength - 1] == '\r') + --wlength; + if (wlength) + { + std::string msg(wlength * 2, char()); + int length = ::WideCharToMultiByte(CP_ACP, 0, + wmsg.c_str(), static_cast<int>(wlength), + &msg[0], static_cast<int>(wlength * 2), 0, 0); + if (length <= 0) + return "asio.system error"; + msg.resize(static_cast<std::size_t>(length)); + return msg; + } + else + return "asio.system error"; + } +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) + char* msg = 0; + DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0); + detail::local_free_on_block_exit local_free_obj(msg); + if (length && msg[length - 1] == '\n') + msg[--length] = '\0'; + if (length && msg[length - 1] == '\r') + msg[--length] = '\0'; + if (length) + return msg; + else + return "asio.system error"; +#else // defined(ASIO_WINDOWS_DESKTOP) || defined(__CYGWIN__) +#if !defined(__sun) + if (value == ECANCELED) + return "Operation aborted."; +#endif // !defined(__sun) +#if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__) + using namespace std; + return strerror(value); +#else + char buf[256] = ""; + using namespace std; + return strerror_result(strerror_r(value, buf, sizeof(buf)), buf); +#endif +#endif // defined(ASIO_WINDOWS_DESKTOP) || defined(__CYGWIN__) + } + +#if defined(ASIO_HAS_STD_ERROR_CODE) + std::error_condition default_error_condition( + int ev) const ASIO_ERROR_CATEGORY_NOEXCEPT + { + switch (ev) + { + case access_denied: + return std::errc::permission_denied; + case address_family_not_supported: + return std::errc::address_family_not_supported; + case address_in_use: + return std::errc::address_in_use; + case already_connected: + return std::errc::already_connected; + case already_started: + return std::errc::connection_already_in_progress; + case broken_pipe: + return std::errc::broken_pipe; + case connection_aborted: + return std::errc::connection_aborted; + case connection_refused: + return std::errc::connection_refused; + case connection_reset: + return std::errc::connection_reset; + case bad_descriptor: + return std::errc::bad_file_descriptor; + case fault: + return std::errc::bad_address; + case host_unreachable: + return std::errc::host_unreachable; + case in_progress: + return std::errc::operation_in_progress; + case interrupted: + return std::errc::interrupted; + case invalid_argument: + return std::errc::invalid_argument; + case message_size: + return std::errc::message_size; + case name_too_long: + return std::errc::filename_too_long; + case network_down: + return std::errc::network_down; + case network_reset: + return std::errc::network_reset; + case network_unreachable: + return std::errc::network_unreachable; + case no_descriptors: + return std::errc::too_many_files_open; + case no_buffer_space: + return std::errc::no_buffer_space; + case no_memory: + return std::errc::not_enough_memory; + case no_permission: + return std::errc::operation_not_permitted; + case no_protocol_option: + return std::errc::no_protocol_option; + case no_such_device: + return std::errc::no_such_device; + case not_connected: + return std::errc::not_connected; + case not_socket: + return std::errc::not_a_socket; + case operation_aborted: + return std::errc::operation_canceled; + case operation_not_supported: + return std::errc::operation_not_supported; + case shut_down: + return std::make_error_condition(ev, *this); + case timed_out: + return std::errc::timed_out; + case try_again: + return std::errc::resource_unavailable_try_again; + case would_block: + return std::errc::operation_would_block; + default: + return std::make_error_condition(ev, *this); + } +#endif // defined(ASIO_HAS_STD_ERROR_CODE) + +private: + // Helper function to adapt the result from glibc's variant of strerror_r. + static const char* strerror_result(int, const char* s) { return s; } + static const char* strerror_result(const char* s, const char*) { return s; } +}; + +} // namespace detail + +const error_category& system_category() +{ + static detail::system_category instance; + return instance; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_ERROR_CODE_IPP diff --git a/lib/asio/impl/execution_context.hpp b/lib/asio/impl/execution_context.hpp new file mode 100644 index 0000000..3d1e457 --- /dev/null +++ b/lib/asio/impl/execution_context.hpp @@ -0,0 +1,107 @@ +// +// impl/execution_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_EXECUTION_CONTEXT_HPP +#define ASIO_IMPL_EXECUTION_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/service_registry.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename Service> +inline Service& use_service(execution_context& e) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); + + return e.service_registry_->template use_service<Service>(); +} + +#if !defined(GENERATING_DOCUMENTATION) +# if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename Service, typename... Args> +Service& make_service(execution_context& e, ASIO_MOVE_ARG(Args)... args) +{ + detail::scoped_ptr<Service> svc( + new Service(e, ASIO_MOVE_CAST(Args)(args)...)); + e.service_registry_->template add_service<Service>(svc.get()); + Service& result = *svc; + svc.release(); + return result; +} + +# else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename Service> +Service& make_service(execution_context& e) +{ + detail::scoped_ptr<Service> svc(new Service(e)); + e.service_registry_->template add_service<Service>(svc.get()); + Service& result = *svc; + svc.release(); + return result; +} + +#define ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \ + template <typename Service, ASIO_VARIADIC_TPARAMS(n)> \ + Service& make_service(execution_context& e, \ + ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + detail::scoped_ptr<Service> svc( \ + new Service(e, ASIO_VARIADIC_MOVE_ARGS(n))); \ + e.service_registry_->template add_service<Service>(svc.get()); \ + Service& result = *svc; \ + svc.release(); \ + return result; \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_MAKE_SERVICE_DEF) +#undef ASIO_PRIVATE_MAKE_SERVICE_DEF + +# endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename Service> +inline void add_service(execution_context& e, Service* svc) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); + + e.service_registry_->template add_service<Service>(svc); +} + +template <typename Service> +inline bool has_service(execution_context& e) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); + + return e.service_registry_->template has_service<Service>(); +} + +inline execution_context& execution_context::service::context() +{ + return owner_; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_EXECUTION_CONTEXT_HPP diff --git a/lib/asio/impl/execution_context.ipp b/lib/asio/impl/execution_context.ipp new file mode 100644 index 0000000..c2b3b21 --- /dev/null +++ b/lib/asio/impl/execution_context.ipp @@ -0,0 +1,82 @@ +// +// impl/execution_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_EXECUTION_CONTEXT_IPP +#define ASIO_IMPL_EXECUTION_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/execution_context.hpp" +#include "asio/detail/service_registry.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +execution_context::execution_context() + : service_registry_(new asio::detail::service_registry(*this)) +{ +} + +execution_context::~execution_context() +{ + shutdown(); + destroy(); + delete service_registry_; +} + +void execution_context::shutdown() +{ + service_registry_->shutdown_services(); +} + +void execution_context::destroy() +{ + service_registry_->destroy_services(); +} + +void execution_context::notify_fork( + asio::execution_context::fork_event event) +{ + service_registry_->notify_fork(event); +} + +execution_context::service::service(execution_context& owner) + : owner_(owner), + next_(0) +{ +} + +execution_context::service::~service() +{ +} + +void execution_context::service::notify_fork(execution_context::fork_event) +{ +} + +service_already_exists::service_already_exists() + : std::logic_error("Service already exists.") +{ +} + +invalid_service_owner::invalid_service_owner() + : std::logic_error("Invalid service owner.") +{ +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_EXECUTION_CONTEXT_IPP diff --git a/lib/asio/impl/executor.hpp b/lib/asio/impl/executor.hpp new file mode 100644 index 0000000..0fcf5f5 --- /dev/null +++ b/lib/asio/impl/executor.hpp @@ -0,0 +1,386 @@ +// +// impl/executor.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_EXECUTOR_HPP +#define ASIO_IMPL_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/executor_op.hpp" +#include "asio/detail/global.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/executor.hpp" +#include "asio/system_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +#if !defined(GENERATING_DOCUMENTATION) + +#if defined(ASIO_HAS_MOVE) + +// Lightweight, move-only function object wrapper. +class executor::function +{ +public: + template <typename F, typename Alloc> + 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(ASIO_MOVE_CAST(F)(f), a); + p.v = 0; + } + + function(function&& other) + : op_(other.op_) + { + other.op_ = 0; + } + + ~function() + { + if (op_) + op_->destroy(); + } + + void operator()() + { + if (op_) + { + detail::scheduler_operation* op = op_; + op_ = 0; + op->complete(this, asio::error_code(), 0); + } + } + +private: + detail::scheduler_operation* op_; +}; + +#else // defined(ASIO_HAS_MOVE) + +// Not so lightweight, copyable function object wrapper. +class executor::function +{ +public: + template <typename F, typename Alloc> + explicit function(const F& f, const Alloc&) + : impl_(new impl<F>(f)) + { + } + + void operator()() + { + impl_->invoke_(impl_.get()); + } + +private: + // Base class for polymorphic function implementations. + struct impl_base + { + void (*invoke_)(impl_base*); + }; + + // Polymorphic function implementation. + template <typename F> + struct impl : impl_base + { + impl(const F& f) + : function_(f) + { + invoke_ = &function::invoke<F>; + } + + F function_; + }; + + // Helper to invoke a function. + template <typename F> + static void invoke(impl_base* i) + { + static_cast<impl<F>*>(i)->function_(); + } + + detail::shared_ptr<impl_base> impl_; +}; + +#endif // defined(ASIO_HAS_MOVE) + +// Default polymorphic allocator implementation. +template <typename Executor, typename Allocator> +class executor::impl + : public executor::impl_base +{ +public: + typedef ASIO_REBIND_ALLOC(Allocator, impl) allocator_type; + + static impl_base* create(const Executor& e, Allocator a = Allocator()) + { + raw_mem mem(a); + impl* p = new (mem.ptr_) impl(e, a); + mem.ptr_ = 0; + return p; + } + + impl(const Executor& e, const Allocator& a) ASIO_NOEXCEPT + : impl_base(false), + ref_count_(1), + executor_(e), + allocator_(a) + { + } + + impl_base* clone() const ASIO_NOEXCEPT + { + ++ref_count_; + return const_cast<impl_base*>(static_cast<const impl_base*>(this)); + } + + void destroy() ASIO_NOEXCEPT + { + if (--ref_count_ == 0) + { + allocator_type alloc(allocator_); + impl* p = this; + p->~impl(); + alloc.deallocate(p, 1); + } + } + + void on_work_started() ASIO_NOEXCEPT + { + executor_.on_work_started(); + } + + void on_work_finished() ASIO_NOEXCEPT + { + executor_.on_work_finished(); + } + + execution_context& context() ASIO_NOEXCEPT + { + return executor_.context(); + } + + void dispatch(ASIO_MOVE_ARG(function) f) + { + executor_.dispatch(ASIO_MOVE_CAST(function)(f), allocator_); + } + + void post(ASIO_MOVE_ARG(function) f) + { + executor_.post(ASIO_MOVE_CAST(function)(f), allocator_); + } + + void defer(ASIO_MOVE_ARG(function) f) + { + executor_.defer(ASIO_MOVE_CAST(function)(f), allocator_); + } + + type_id_result_type target_type() const ASIO_NOEXCEPT + { + return type_id<Executor>(); + } + + void* target() ASIO_NOEXCEPT + { + return &executor_; + } + + const void* target() const ASIO_NOEXCEPT + { + return &executor_; + } + + bool equals(const impl_base* e) const ASIO_NOEXCEPT + { + if (this == e) + return true; + if (target_type() != e->target_type()) + return false; + return executor_ == *static_cast<const Executor*>(e->target()); + } + +private: + mutable detail::atomic_count ref_count_; + Executor executor_; + Allocator allocator_; + + struct raw_mem + { + allocator_type allocator_; + impl* ptr_; + + explicit raw_mem(const Allocator& a) + : allocator_(a), + ptr_(allocator_.allocate(1)) + { + } + + ~raw_mem() + { + if (ptr_) + allocator_.deallocate(ptr_, 1); + } + + private: + // Disallow copying and assignment. + raw_mem(const raw_mem&); + raw_mem operator=(const raw_mem&); + }; +}; + +// Polymorphic allocator specialisation for system_executor. +template <typename Allocator> +class executor::impl<system_executor, Allocator> + : public executor::impl_base +{ +public: + static impl_base* create(const system_executor&, + const Allocator& = Allocator()) + { + return &detail::global<impl<system_executor, std::allocator<void> > >(); + } + + impl() + : impl_base(true) + { + } + + impl_base* clone() const ASIO_NOEXCEPT + { + return const_cast<impl_base*>(static_cast<const impl_base*>(this)); + } + + void destroy() ASIO_NOEXCEPT + { + } + + void on_work_started() ASIO_NOEXCEPT + { + executor_.on_work_started(); + } + + void on_work_finished() ASIO_NOEXCEPT + { + executor_.on_work_finished(); + } + + execution_context& context() ASIO_NOEXCEPT + { + return executor_.context(); + } + + void dispatch(ASIO_MOVE_ARG(function) f) + { + executor_.dispatch(ASIO_MOVE_CAST(function)(f), allocator_); + } + + void post(ASIO_MOVE_ARG(function) f) + { + executor_.post(ASIO_MOVE_CAST(function)(f), allocator_); + } + + void defer(ASIO_MOVE_ARG(function) f) + { + executor_.defer(ASIO_MOVE_CAST(function)(f), allocator_); + } + + type_id_result_type target_type() const ASIO_NOEXCEPT + { + return type_id<system_executor>(); + } + + void* target() ASIO_NOEXCEPT + { + return &executor_; + } + + const void* target() const ASIO_NOEXCEPT + { + return &executor_; + } + + bool equals(const impl_base* e) const ASIO_NOEXCEPT + { + return this == e; + } + +private: + system_executor executor_; + Allocator allocator_; +}; + +template <typename Executor> +executor::executor(Executor e) + : impl_(impl<Executor, std::allocator<void> >::create(e)) +{ +} + +template <typename Executor, typename Allocator> +executor::executor(allocator_arg_t, const Allocator& a, Executor e) + : impl_(impl<Executor, Allocator>::create(e, a)) +{ +} + +template <typename Function, typename Allocator> +void executor::dispatch(ASIO_MOVE_ARG(Function) f, + const Allocator& a) const +{ + impl_base* i = get_impl(); + if (i->fast_dispatch_) + system_executor().dispatch(ASIO_MOVE_CAST(Function)(f), a); + else + i->dispatch(function(ASIO_MOVE_CAST(Function)(f), a)); +} + +template <typename Function, typename Allocator> +void executor::post(ASIO_MOVE_ARG(Function) f, + const Allocator& a) const +{ + get_impl()->post(function(ASIO_MOVE_CAST(Function)(f), a)); +} + +template <typename Function, typename Allocator> +void executor::defer(ASIO_MOVE_ARG(Function) f, + const Allocator& a) const +{ + get_impl()->defer(function(ASIO_MOVE_CAST(Function)(f), a)); +} + +template <typename Executor> +Executor* executor::target() ASIO_NOEXCEPT +{ + return impl_ && impl_->target_type() == type_id<Executor>() + ? static_cast<Executor*>(impl_->target()) : 0; +} + +template <typename Executor> +const Executor* executor::target() const ASIO_NOEXCEPT +{ + return impl_ && impl_->target_type() == type_id<Executor>() + ? static_cast<Executor*>(impl_->target()) : 0; +} + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_EXECUTOR_HPP diff --git a/lib/asio/impl/executor.ipp b/lib/asio/impl/executor.ipp new file mode 100644 index 0000000..4bd0dc5 --- /dev/null +++ b/lib/asio/impl/executor.ipp @@ -0,0 +1,38 @@ +// +// impl/executor.ipp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_EXECUTOR_IPP +#define ASIO_IMPL_EXECUTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +bad_executor::bad_executor() ASIO_NOEXCEPT +{ +} + +const char* bad_executor::what() const ASIO_NOEXCEPT_OR_NOTHROW +{ + return "bad executor"; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_EXECUTOR_IPP diff --git a/lib/asio/impl/handler_alloc_hook.ipp b/lib/asio/impl/handler_alloc_hook.ipp new file mode 100644 index 0000000..909ddac --- /dev/null +++ b/lib/asio/impl/handler_alloc_hook.ipp @@ -0,0 +1,52 @@ +// +// impl/handler_alloc_hook.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP +#define ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/detail/thread_context.hpp" +#include "asio/detail/thread_info_base.hpp" +#include "asio/handler_alloc_hook.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +void* asio_handler_allocate(std::size_t size, ...) +{ +#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return detail::thread_info_base::allocate( + detail::thread_context::thread_call_stack::top(), size); +#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return ::operator new(size); +#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +} + +void asio_handler_deallocate(void* pointer, std::size_t size, ...) +{ +#if !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + detail::thread_info_base::deallocate( + detail::thread_context::thread_call_stack::top(), pointer, size); +#else // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + (void)size; + ::operator delete(pointer); +#endif // !defined(ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP diff --git a/lib/asio/impl/io_context.hpp b/lib/asio/impl/io_context.hpp new file mode 100644 index 0000000..eaf580d --- /dev/null +++ b/lib/asio/impl/io_context.hpp @@ -0,0 +1,343 @@ +// +// impl/io_context.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_IO_CONTEXT_HPP +#define ASIO_IMPL_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/completion_handler.hpp" +#include "asio/detail/executor_op.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/detail/service_registry.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/detail/type_traits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename Service> +inline Service& use_service(io_context& ioc) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); + (void)static_cast<const execution_context::id*>(&Service::id); + + return ioc.service_registry_->template use_service<Service>(ioc); +} + +template <> +inline detail::io_context_impl& use_service<detail::io_context_impl>( + io_context& ioc) +{ + return ioc.impl_; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else +# include "asio/detail/scheduler.hpp" +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { + +inline io_context::executor_type +io_context::get_executor() ASIO_NOEXCEPT +{ + return executor_type(*this); +} + +#if defined(ASIO_HAS_CHRONO) + +template <typename Rep, typename Period> +std::size_t io_context::run_for( + const chrono::duration<Rep, Period>& rel_time) +{ + return this->run_until(chrono::steady_clock::now() + rel_time); +} + +template <typename Clock, typename Duration> +std::size_t io_context::run_until( + const chrono::time_point<Clock, Duration>& abs_time) +{ + std::size_t n = 0; + while (this->run_one_until(abs_time)) + if (n != (std::numeric_limits<std::size_t>::max)()) + ++n; + return n; +} + +template <typename Rep, typename Period> +std::size_t io_context::run_one_for( + const chrono::duration<Rep, Period>& rel_time) +{ + return this->run_one_until(chrono::steady_clock::now() + rel_time); +} + +template <typename Clock, typename Duration> +std::size_t io_context::run_one_until( + const chrono::time_point<Clock, Duration>& abs_time) +{ + typename Clock::time_point now = Clock::now(); + while (now < abs_time) + { + typename Clock::duration rel_time = abs_time - now; + if (rel_time > chrono::seconds(1)) + rel_time = chrono::seconds(1); + + asio::error_code ec; + std::size_t s = impl_.wait_one( + static_cast<long>(chrono::duration_cast< + chrono::microseconds>(rel_time).count()), ec); + asio::detail::throw_error(ec); + + if (s || impl_.stopped()) + return s; + + now = Clock::now(); + } + + return 0; +} + +#endif // defined(ASIO_HAS_CHRONO) + +#if !defined(ASIO_NO_DEPRECATED) + +inline void io_context::reset() +{ + restart(); +} + +template <typename LegacyCompletionHandler> +ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) +io_context::dispatch(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. + ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + async_completion<LegacyCompletionHandler, void ()> init(handler); + + if (impl_.can_dispatch()) + { + detail::fenced_block b(detail::fenced_block::full); + asio_handler_invoke_helpers::invoke( + init.completion_handler, init.completion_handler); + } + else + { + // 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); + + ASIO_HANDLER_CREATION((*this, *p.p, + "io_context", this, 0, "dispatch")); + + impl_.do_dispatch(p.p); + p.v = p.p = 0; + } + + return init.result.get(); +} + +template <typename LegacyCompletionHandler> +ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) +io_context::post(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. + ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + async_completion<LegacyCompletionHandler, void ()> init(handler); + + bool is_continuation = + 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); + + 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(); +} + +template <typename Handler> +#if defined(GENERATING_DOCUMENTATION) +unspecified +#else +inline detail::wrapped_handler<io_context&, Handler> +#endif +io_context::wrap(Handler handler) +{ + return detail::wrapped_handler<io_context&, Handler>(*this, handler); +} + +#endif // !defined(ASIO_NO_DEPRECATED) + +inline io_context& +io_context::executor_type::context() const ASIO_NOEXCEPT +{ + return io_context_; +} + +inline void +io_context::executor_type::on_work_started() const ASIO_NOEXCEPT +{ + io_context_.impl_.work_started(); +} + +inline void +io_context::executor_type::on_work_finished() const ASIO_NOEXCEPT +{ + io_context_.impl_.work_finished(); +} + +template <typename Function, typename Allocator> +void io_context::executor_type::dispatch( + ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Invoke immediately if we are already inside the thread pool. + if (io_context_.impl_.can_dispatch()) + { + // Make a local, non-const copy of the function. + function_type tmp(ASIO_MOVE_CAST(Function)(f)); + + detail::fenced_block b(detail::fenced_block::full); + asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator, detail::operation> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a); + + ASIO_HANDLER_CREATION((this->context(), *p.p, + "io_context", &this->context(), 0, "post")); + + io_context_.impl_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template <typename Function, typename Allocator> +void io_context::executor_type::post( + ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator, detail::operation> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a); + + ASIO_HANDLER_CREATION((this->context(), *p.p, + "io_context", &this->context(), 0, "post")); + + io_context_.impl_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template <typename Function, typename Allocator> +void io_context::executor_type::defer( + ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator, detail::operation> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a); + + ASIO_HANDLER_CREATION((this->context(), *p.p, + "io_context", &this->context(), 0, "defer")); + + io_context_.impl_.post_immediate_completion(p.p, true); + p.v = p.p = 0; +} + +inline bool +io_context::executor_type::running_in_this_thread() const ASIO_NOEXCEPT +{ + return io_context_.impl_.can_dispatch(); +} + +#if !defined(ASIO_NO_DEPRECATED) +inline io_context::work::work(asio::io_context& io_context) + : io_context_impl_(io_context.impl_) +{ + io_context_impl_.work_started(); +} + +inline io_context::work::work(const work& other) + : io_context_impl_(other.io_context_impl_) +{ + io_context_impl_.work_started(); +} + +inline io_context::work::~work() +{ + io_context_impl_.work_finished(); +} + +inline asio::io_context& io_context::work::get_io_context() +{ + return static_cast<asio::io_context&>(io_context_impl_.context()); +} + +inline asio::io_context& io_context::work::get_io_service() +{ + return static_cast<asio::io_context&>(io_context_impl_.context()); +} +#endif // !defined(ASIO_NO_DEPRECATED) + +inline asio::io_context& io_context::service::get_io_context() +{ + return static_cast<asio::io_context&>(context()); +} + +#if !defined(ASIO_NO_DEPRECATED) +inline asio::io_context& io_context::service::get_io_service() +{ + return static_cast<asio::io_context&>(context()); +} +#endif // !defined(ASIO_NO_DEPRECATED) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_IO_CONTEXT_HPP diff --git a/lib/asio/impl/io_context.ipp b/lib/asio/impl/io_context.ipp new file mode 100644 index 0000000..7eb467d --- /dev/null +++ b/lib/asio/impl/io_context.ipp @@ -0,0 +1,174 @@ +// +// impl/io_context.ipp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_IO_CONTEXT_IPP +#define ASIO_IMPL_IO_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/io_context.hpp" +#include "asio/detail/concurrency_hint.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/scoped_ptr.hpp" +#include "asio/detail/service_registry.hpp" +#include "asio/detail/throw_error.hpp" + +#if defined(ASIO_HAS_IOCP) +# include "asio/detail/win_iocp_io_context.hpp" +#else +# include "asio/detail/scheduler.hpp" +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { + +io_context::io_context() + : impl_(add_impl(new impl_type(*this, ASIO_CONCURRENCY_HINT_DEFAULT))) +{ +} + +io_context::io_context(int concurrency_hint) + : impl_(add_impl(new impl_type(*this, concurrency_hint == 1 + ? ASIO_CONCURRENCY_HINT_1 : concurrency_hint))) +{ +} + +io_context::impl_type& io_context::add_impl(io_context::impl_type* impl) +{ + asio::detail::scoped_ptr<impl_type> scoped_impl(impl); + asio::add_service<impl_type>(*this, scoped_impl.get()); + return *scoped_impl.release(); +} + +io_context::~io_context() +{ +} + +io_context::count_type io_context::run() +{ + asio::error_code ec; + count_type s = impl_.run(ec); + asio::detail::throw_error(ec); + return s; +} + +#if !defined(ASIO_NO_DEPRECATED) +io_context::count_type io_context::run(asio::error_code& ec) +{ + return impl_.run(ec); +} +#endif // !defined(ASIO_NO_DEPRECATED) + +io_context::count_type io_context::run_one() +{ + asio::error_code ec; + count_type s = impl_.run_one(ec); + asio::detail::throw_error(ec); + return s; +} + +#if !defined(ASIO_NO_DEPRECATED) +io_context::count_type io_context::run_one(asio::error_code& ec) +{ + return impl_.run_one(ec); +} +#endif // !defined(ASIO_NO_DEPRECATED) + +io_context::count_type io_context::poll() +{ + asio::error_code ec; + count_type s = impl_.poll(ec); + asio::detail::throw_error(ec); + return s; +} + +#if !defined(ASIO_NO_DEPRECATED) +io_context::count_type io_context::poll(asio::error_code& ec) +{ + return impl_.poll(ec); +} +#endif // !defined(ASIO_NO_DEPRECATED) + +io_context::count_type io_context::poll_one() +{ + asio::error_code ec; + count_type s = impl_.poll_one(ec); + asio::detail::throw_error(ec); + return s; +} + +#if !defined(ASIO_NO_DEPRECATED) +io_context::count_type io_context::poll_one(asio::error_code& ec) +{ + return impl_.poll_one(ec); +} +#endif // !defined(ASIO_NO_DEPRECATED) + +void io_context::stop() +{ + impl_.stop(); +} + +bool io_context::stopped() const +{ + return impl_.stopped(); +} + +void io_context::restart() +{ + impl_.restart(); +} + +io_context::service::service(asio::io_context& owner) + : execution_context::service(owner) +{ +} + +io_context::service::~service() +{ +} + +void io_context::service::shutdown() +{ +#if !defined(ASIO_NO_DEPRECATED) + shutdown_service(); +#endif // !defined(ASIO_NO_DEPRECATED) +} + +#if !defined(ASIO_NO_DEPRECATED) +void io_context::service::shutdown_service() +{ +} +#endif // !defined(ASIO_NO_DEPRECATED) + +void io_context::service::notify_fork(io_context::fork_event ev) +{ +#if !defined(ASIO_NO_DEPRECATED) + fork_service(ev); +#else // !defined(ASIO_NO_DEPRECATED) + (void)ev; +#endif // !defined(ASIO_NO_DEPRECATED) +} + +#if !defined(ASIO_NO_DEPRECATED) +void io_context::service::fork_service(io_context::fork_event) +{ +} +#endif // !defined(ASIO_NO_DEPRECATED) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_IO_CONTEXT_IPP diff --git a/lib/asio/impl/post.hpp b/lib/asio/impl/post.hpp new file mode 100644 index 0000000..5538953 --- /dev/null +++ b/lib/asio/impl/post.hpp @@ -0,0 +1,77 @@ +// +// impl/post.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_POST_HPP +#define ASIO_IMPL_POST_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/detail/work_dispatcher.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename CompletionToken> +ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + + async_completion<CompletionToken, void()> init(token); + + typename associated_executor<handler>::type ex( + (get_associated_executor)(init.completion_handler)); + + typename associated_allocator<handler>::type alloc( + (get_associated_allocator)(init.completion_handler)); + + ex.post(ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); + + return init.result.get(); +} + +template <typename Executor, typename CompletionToken> +ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + const Executor& ex, ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_executor<Executor>::value>::type*) +{ + typedef 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(); +} + +template <typename ExecutionContext, typename CompletionToken> +inline ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + ExecutionContext& ctx, ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type*) +{ + return (post)(ctx.get_executor(), + ASIO_MOVE_CAST(CompletionToken)(token)); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_POST_HPP diff --git a/lib/asio/impl/read.hpp b/lib/asio/impl/read.hpp new file mode 100644 index 0000000..603a7a9 --- /dev/null +++ b/lib/asio/impl/read.hpp @@ -0,0 +1,715 @@ +// +// impl/read.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_READ_HPP +#define ASIO_IMPL_READ_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <algorithm> +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" +#include "asio/detail/array_fwd.hpp" +#include "asio/detail/base_from_completion_cond.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/consuming_buffers.hpp" +#include "asio/detail/dependent_type.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +namespace detail +{ + template <typename SyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition> + std::size_t read_buffer_sequence(SyncReadStream& s, + const MutableBufferSequence& buffers, const MutableBufferIterator&, + CompletionCondition completion_condition, asio::error_code& ec) + { + ec = asio::error_code(); + asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + tmp.consume(s.read_some(tmp.prepare(max_size), ec)); + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + +template <typename SyncReadStream, typename MutableBufferSequence, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) +{ + return detail::read_buffer_sequence(s, buffers, + asio::buffer_sequence_begin(buffers), completion_condition, ec); +} + +template <typename SyncReadStream, typename MutableBufferSequence> +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec); + asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename MutableBufferSequence> +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + asio::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) +{ + return read(s, buffers, transfer_all(), ec); +} + +template <typename SyncReadStream, typename MutableBufferSequence, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); + asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + >::type*) +{ + typename decay<DynamicBuffer>::type b( + ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + + ec = asio::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 bytes_transferred = s.read_some(b.prepare(bytes_available), ec); + b.commit(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> +inline std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, + ASIO_MOVE_CAST(DynamicBuffer)(buffers), transfer_all(), ec); + asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer> +inline std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + asio::error_code& ec, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + >::type*) +{ + return read(s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), + transfer_all(), ec); +} + +template <typename SyncReadStream, typename DynamicBuffer, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = read(s, + ASIO_MOVE_CAST(DynamicBuffer)(buffers), + completion_condition, ec); + asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_IOSTREAM) + +template <typename SyncReadStream, typename Allocator, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, asio::error_code& ec) +{ + return read(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b) +{ + return read(s, basic_streambuf_ref<Allocator>(b)); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + asio::error_code& ec) +{ + return read(s, basic_streambuf_ref<Allocator>(b), ec); +} + +template <typename SyncReadStream, typename Allocator, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition) +{ + return read(s, basic_streambuf_ref<Allocator>(b), completion_condition); +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) + +namespace detail +{ + template <typename AsyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler> + class read_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, ReadHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffers_(buffers), + start_(0), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + read_op(const read_op& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + handler_(other.handler_) + { + } + + read_op(read_op&& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do + { + stream_.async_read_some(buffers_.prepare(max_size), + ASIO_MOVE_CAST(read_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + if ((!ec && bytes_transferred == 0) || buffers_.empty()) + break; + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); + + handler_(ec, buffers_.total_consumed()); + } + } + + //private: + AsyncReadStream& stream_; + asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> buffers_; + int start_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler> + inline bool asio_handler_is_continuation( + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename AsyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler> + inline void start_read_buffer_sequence_op(AsyncReadStream& stream, + const MutableBufferSequence& buffers, const MutableBufferIterator&, + CompletionCondition completion_condition, ReadHandler& handler) + { + detail::read_op<AsyncReadStream, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>( + stream, buffers, completion_condition, handler)( + asio::error_code(), 0, 1); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_op<AsyncReadStream, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_op<AsyncReadStream, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_op<AsyncReadStream, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_op<AsyncReadStream, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename MutableBufferSequence, + typename CompletionCondition, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::start_read_buffer_sequence_op(s, buffers, + asio::buffer_sequence_begin(buffers), completion_condition, + init.completion_handler); + + return init.result.get(); +} + +template <typename AsyncReadStream, typename MutableBufferSequence, + typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::start_read_buffer_sequence_op(s, buffers, + asio::buffer_sequence_begin(buffers), transfer_all(), + init.completion_handler); + + return init.result.get(); +} + +namespace detail +{ + template <typename AsyncReadStream, typename DynamicBuffer, + typename CompletionCondition, typename ReadHandler> + class read_dynbuf_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + template <typename BufferSequence> + read_dynbuf_op(AsyncReadStream& stream, + ASIO_MOVE_ARG(BufferSequence) buffers, + CompletionCondition completion_condition, ReadHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + start_(0), + total_transferred_(0), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + read_dynbuf_op(const read_dynbuf_op& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + total_transferred_(other.total_transferred_), + handler_(other.handler_) + { + } + + read_dynbuf_op(read_dynbuf_op&& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + stream_(other.stream_), + buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + start_(other.start_), + total_transferred_(other.total_transferred_), + handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size, bytes_available; + 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 (;;) + { + stream_.async_read_some(buffers_.prepare(bytes_available), + ASIO_MOVE_CAST(read_dynbuf_op)(*this)); + return; default: + total_transferred_ += bytes_transferred; + buffers_.commit(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 buffers_; + int start_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename DynamicBuffer, + typename CompletionCondition, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_dynbuf_op<AsyncReadStream, DynamicBuffer, + CompletionCondition, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_dynbuf_op<AsyncReadStream, DynamicBuffer, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer, + typename CompletionCondition, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_dynbuf_op<AsyncReadStream, DynamicBuffer, + CompletionCondition, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename CompletionCondition, + typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_dynbuf_op<AsyncReadStream, DynamicBuffer, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename CompletionCondition, + typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_dynbuf_op<AsyncReadStream, DynamicBuffer, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename CompletionCondition, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_dynbuf_op<AsyncReadStream, + DynamicBuffer, 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 Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer, + typename CompletionCondition, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_dynbuf_op<AsyncReadStream, + DynamicBuffer, 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 Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + >::type*) +{ + return async_read(s, + ASIO_MOVE_CAST(DynamicBuffer)(buffers), + transfer_all(), ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template <typename AsyncReadStream, typename DynamicBuffer, + typename CompletionCondition, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, + ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::read_dynbuf_op<AsyncReadStream, + typename decay<DynamicBuffer>::type, + CompletionCondition, ASIO_HANDLER_TYPE( + ReadHandler, void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), + completion_condition, init.completion_handler)( + asio::error_code(), 0, 1); + + return init.result.get(); +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_IOSTREAM) + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, + ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read(s, basic_streambuf_ref<Allocator>(b), + ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template <typename AsyncReadStream, typename Allocator, + typename CompletionCondition, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, + ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read(s, basic_streambuf_ref<Allocator>(b), + completion_condition, ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_READ_HPP diff --git a/lib/asio/impl/read_at.hpp b/lib/asio/impl/read_at.hpp new file mode 100644 index 0000000..d736d4d --- /dev/null +++ b/lib/asio/impl/read_at.hpp @@ -0,0 +1,640 @@ +// +// impl/read_at.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_READ_AT_HPP +#define ASIO_IMPL_READ_AT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <algorithm> +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" +#include "asio/detail/array_fwd.hpp" +#include "asio/detail/base_from_completion_cond.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/consuming_buffers.hpp" +#include "asio/detail/dependent_type.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" +#include "asio/error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +namespace detail +{ + template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition> + std::size_t read_at_buffer_sequence(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + const MutableBufferIterator&, CompletionCondition completion_condition, + asio::error_code& ec) + { + ec = asio::error_code(); + asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + { + tmp.consume(d.read_some_at(offset + tmp.total_consumed(), + tmp.prepare(max_size), ec)); + } + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + +template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, + typename CompletionCondition> +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec) +{ + return detail::read_at_buffer_sequence(d, offset, buffers, + asio::buffer_sequence_begin(buffers), completion_condition, ec); +} + +template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence> +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_at( + d, offset, buffers, transfer_all(), ec); + asio::detail::throw_error(ec, "read_at"); + return bytes_transferred; +} + +template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence> +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + asio::error_code& ec) +{ + return read_at(d, offset, buffers, transfer_all(), ec); +} + +template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, + typename CompletionCondition> +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_at( + d, offset, buffers, completion_condition, ec); + asio::detail::throw_error(ec, "read_at"); + return bytes_transferred; +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_IOSTREAM) + +template <typename SyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition> +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, asio::error_code& ec) +{ + ec = asio::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 = read_size_helper(b, max_size); + while (bytes_available > 0) + { + std::size_t bytes_transferred = d.read_some_at( + offset + total_transferred, b.prepare(bytes_available), ec); + b.commit(bytes_transferred); + total_transferred += bytes_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = read_size_helper(b, max_size); + } + return total_transferred; +} + +template <typename SyncRandomAccessReadDevice, typename Allocator> +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_at( + d, offset, b, transfer_all(), ec); + asio::detail::throw_error(ec, "read_at"); + return bytes_transferred; +} + +template <typename SyncRandomAccessReadDevice, typename Allocator> +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b, + asio::error_code& ec) +{ + return read_at(d, offset, b, transfer_all(), ec); +} + +template <typename SyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition> +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_at( + d, offset, b, completion_condition, ec); + asio::detail::throw_error(ec, "read_at"); + return bytes_transferred; +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) + +namespace detail +{ + template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> + class read_at_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + read_at_op(AsyncRandomAccessReadDevice& device, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, ReadHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffers_(buffers), + start_(0), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + read_at_op(const read_at_op& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + device_(other.device_), + offset_(other.offset_), + buffers_(other.buffers_), + start_(other.start_), + handler_(other.handler_) + { + } + + read_at_op(read_at_op&& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + device_(other.device_), + offset_(other.offset_), + buffers_(other.buffers_), + start_(other.start_), + handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do + { + device_.async_read_some_at( + offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), + ASIO_MOVE_CAST(read_at_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + if ((!ec && bytes_transferred == 0) || buffers_.empty()) + break; + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); + + handler_(ec, buffers_.total_consumed()); + } + } + + //private: + AsyncRandomAccessReadDevice& device_; + uint64_t offset_; + asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> buffers_; + int start_; + ReadHandler handler_; + }; + + template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + 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, + ReadHandler& handler) + { + detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>( + d, offset, buffers, completion_condition, handler)( + asio::error_code(), 0, 1); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_at_op<AsyncRandomAccessReadDevice, + MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_at_op<AsyncRandomAccessReadDevice, + MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, + typename CompletionCondition, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, + 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::start_read_at_buffer_sequence_op(d, offset, buffers, + asio::buffer_sequence_begin(buffers), completion_condition, + init.completion_handler); + + return init.result.get(); +} + +template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, + typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::start_read_at_buffer_sequence_op(d, offset, buffers, + asio::buffer_sequence_begin(buffers), transfer_all(), + init.completion_handler); + + return init.result.get(); +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_IOSTREAM) + +namespace detail +{ + template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler> + class read_at_streambuf_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + read_at_streambuf_op(AsyncRandomAccessReadDevice& device, + uint64_t offset, basic_streambuf<Allocator>& streambuf, + CompletionCondition completion_condition, ReadHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + streambuf_(streambuf), + start_(0), + total_transferred_(0), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + read_at_streambuf_op(const read_at_streambuf_op& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + device_(other.device_), + offset_(other.offset_), + streambuf_(other.streambuf_), + start_(other.start_), + total_transferred_(other.total_transferred_), + handler_(other.handler_) + { + } + + read_at_streambuf_op(read_at_streambuf_op&& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + device_(other.device_), + offset_(other.offset_), + streambuf_(other.streambuf_), + start_(other.start_), + total_transferred_(other.total_transferred_), + handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size, bytes_available; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + for (;;) + { + device_.async_read_some_at(offset_ + total_transferred_, + streambuf_.prepare(bytes_available), + ASIO_MOVE_CAST(read_at_streambuf_op)(*this)); + return; default: + total_transferred_ += bytes_transferred; + streambuf_.commit(bytes_transferred); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + if ((!ec && bytes_transferred == 0) || bytes_available == 0) + break; + } + + handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + } + } + + //private: + AsyncRandomAccessReadDevice& device_; + uint64_t offset_; + asio::basic_streambuf<Allocator>& streambuf_; + int start_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncRandomAccessReadDevice, + typename Allocator, typename CompletionCondition, typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncRandomAccessReadDevice, + typename Allocator, typename CompletionCondition, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + CompletionCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler, typename Allocator1> +struct associated_allocator< + detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, + Allocator, CompletionCondition, ReadHandler>, + Allocator1> +{ + typedef typename associated_allocator<ReadHandler, Allocator1>::type type; + + static type get( + const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, + Allocator, CompletionCondition, ReadHandler>& h, + const Allocator1& a = Allocator1()) ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a); + } +}; + +template <typename AsyncRandomAccessReadDevice, typename Executor, + typename CompletionCondition, typename ReadHandler, typename Executor1> +struct associated_executor< + detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, + Executor, CompletionCondition, ReadHandler>, + Executor1> +{ + typedef typename associated_executor<ReadHandler, Executor1>::type type; + + static type get( + const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, + Executor, CompletionCondition, ReadHandler>& h, + const Executor1& ex = Executor1()) ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, + 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + CompletionCondition, ASIO_HANDLER_TYPE(ReadHandler, + void (asio::error_code, std::size_t))>( + d, offset, b, completion_condition, init.completion_handler)( + asio::error_code(), 0, 1); + + return init.result.get(); +} + +template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b, + 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, + detail::transfer_all_t, ASIO_HANDLER_TYPE(ReadHandler, + void (asio::error_code, std::size_t))>( + d, offset, b, transfer_all(), init.completion_handler)( + asio::error_code(), 0, 1); + + return init.result.get(); +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_READ_AT_HPP diff --git a/lib/asio/impl/read_until.hpp b/lib/asio/impl/read_until.hpp new file mode 100644 index 0000000..1f39e19 --- /dev/null +++ b/lib/asio/impl/read_until.hpp @@ -0,0 +1,1500 @@ +// +// impl/read_until.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_READ_UNTIL_HPP +#define ASIO_IMPL_READ_UNTIL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <algorithm> +#include <string> +#include <vector> +#include <utility> +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/buffer.hpp" +#include "asio/buffers_iterator.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/limits.hpp" +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +template <typename SyncReadStream, typename DynamicBuffer> +inline std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, char delim) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, + ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec); + asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + char delim, asio::error_code& ec) +{ + typename decay<DynamicBuffer>::type b( + ASIO_MOVE_CAST(DynamicBuffer)(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 buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + 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 = asio::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())); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template <typename SyncReadStream, typename DynamicBuffer> +inline std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + ASIO_STRING_VIEW_PARAM delim) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, + ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec); + 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> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec) +{ + typename decay<DynamicBuffer>::type b( + ASIO_MOVE_CAST(DynamicBuffer)(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 buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + 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 = asio::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())); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if defined(ASIO_HAS_BOOST_REGEX) + +template <typename SyncReadStream, typename DynamicBuffer> +inline std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + const boost::regex& expr) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, + ASIO_MOVE_CAST(DynamicBuffer)(buffers), expr, ec); + asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, typename DynamicBuffer> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + const boost::regex& expr, asio::error_code& ec) +{ + typename decay<DynamicBuffer>::type b( + ASIO_MOVE_CAST(DynamicBuffer)(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 buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + 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 = asio::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 = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +#endif // defined(ASIO_HAS_BOOST_REGEX) + +template <typename SyncReadStream, + typename DynamicBuffer, typename MatchCondition> +inline std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + MatchCondition match_condition, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, + ASIO_MOVE_CAST(DynamicBuffer)(buffers), + match_condition, ec); + asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, + typename DynamicBuffer, typename MatchCondition> +std::size_t read_until(SyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + MatchCondition match_condition, asio::error_code& ec, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + typename decay<DynamicBuffer>::type b( + ASIO_MOVE_CAST(DynamicBuffer)(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 buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + 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 = asio::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())); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +#if !defined(ASIO_NO_IOSTREAM) + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, char delim) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, char delim, + asio::error_code& ec) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + ASIO_STRING_VIEW_PARAM delim) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + ASIO_STRING_VIEW_PARAM delim, asio::error_code& ec) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec); +} + +#if defined(ASIO_HAS_BOOST_REGEX) + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const boost::regex& expr) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), expr); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + asio::error_code& ec) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec); +} + +#endif // defined(ASIO_HAS_BOOST_REGEX) + +template <typename SyncReadStream, typename Allocator, typename MatchCondition> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition); +} + +template <typename SyncReadStream, typename Allocator, typename MatchCondition> +inline std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + MatchCondition match_condition, asio::error_code& ec, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition, ec); +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) + +namespace detail +{ + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + class read_until_delim_op + { + public: + template <typename BufferSequence> + read_until_delim_op(AsyncReadStream& stream, + ASIO_MOVE_ARG(BufferSequence) buffers, + char delim, ReadHandler& handler) + : stream_(stream), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + delim_(delim), + start_(0), + search_position_(0), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + read_until_delim_op(const read_until_delim_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + handler_(other.handler_) + { + } + + read_until_delim_op(read_until_delim_op&& other) + : stream_(other.stream_), + buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::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 bytes_to_read; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = buffers_.data(); + 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 operation to obtain more data. + stream_.async_read_some(buffers_.prepare(bytes_to_read), + ASIO_MOVE_CAST(read_until_delim_op)(*this)); + return; default: + buffers_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const asio::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 buffers_; + char delim_; + int start_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer, + typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + char delim, 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::read_until_delim_op<AsyncReadStream, + typename decay<DynamicBuffer>::type, + ASIO_HANDLER_TYPE(ReadHandler, + void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), + delim, init.completion_handler)(asio::error_code(), 0, 1); + + return init.result.get(); +} + +namespace detail +{ + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + class read_until_delim_string_op + { + public: + template <typename BufferSequence> + read_until_delim_string_op(AsyncReadStream& stream, + ASIO_MOVE_ARG(BufferSequence) buffers, + const std::string& delim, ReadHandler& handler) + : stream_(stream), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + delim_(delim), + start_(0), + search_position_(0), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + read_until_delim_string_op(const read_until_delim_string_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + handler_(other.handler_) + { + } + + read_until_delim_string_op(read_until_delim_string_op&& other) + : stream_(other.stream_), + buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + delim_(ASIO_MOVE_CAST(std::string)(other.delim_)), + start_(other.start_), + search_position_(other.search_position_), + handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::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 bytes_to_read; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = buffers_.data(); + 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 operation to obtain more data. + stream_.async_read_some(buffers_.prepare(bytes_to_read), + ASIO_MOVE_CAST(read_until_delim_string_op)(*this)); + return; default: + buffers_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const asio::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 buffers_; + std::string delim_; + int start_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, 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 Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer, + typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, 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 Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + ASIO_STRING_VIEW_PARAM delim, + 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::read_until_delim_string_op<AsyncReadStream, + typename decay<DynamicBuffer>::type, + ASIO_HANDLER_TYPE(ReadHandler, + void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), + static_cast<std::string>(delim), + init.completion_handler)(asio::error_code(), 0, 1); + + return init.result.get(); +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if defined(ASIO_HAS_BOOST_REGEX) + +namespace detail +{ + template <typename AsyncReadStream, typename DynamicBuffer, + typename RegEx, typename ReadHandler> + class read_until_expr_op + { + public: + template <typename BufferSequence> + read_until_expr_op(AsyncReadStream& stream, + ASIO_MOVE_ARG(BufferSequence) buffers, + const boost::regex& expr, ReadHandler& handler) + : stream_(stream), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + expr_(expr), + start_(0), + search_position_(0), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + read_until_expr_op(const read_until_expr_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + expr_(other.expr_), + start_(other.start_), + search_position_(other.search_position_), + handler_(other.handler_) + { + } + + read_until_expr_op(read_until_expr_op&& other) + : stream_(other.stream_), + buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + expr_(other.expr_), + start_(other.start_), + search_position_(other.search_position_), + handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::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 bytes_to_read; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = buffers_.data(); + 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 operation to obtain more data. + stream_.async_read_some(buffers_.prepare(bytes_to_read), + ASIO_MOVE_CAST(read_until_expr_op)(*this)); + return; default: + buffers_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const asio::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 buffers_; + RegEx expr_; + int start_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename DynamicBuffer, + typename RegEx, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_expr_op<AsyncReadStream, + DynamicBuffer, RegEx, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer, + 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) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer, + typename RegEx, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_expr_op<AsyncReadStream, + DynamicBuffer, RegEx, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename RegEx, typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_until_expr_op<AsyncReadStream, + DynamicBuffer, RegEx, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename RegEx, typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_expr_op<AsyncReadStream, + DynamicBuffer, RegEx, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename RegEx, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_expr_op<AsyncReadStream, + DynamicBuffer, 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 Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer, + typename RegEx, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_expr_op<AsyncReadStream, + DynamicBuffer, 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 Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + const boost::regex& expr, + 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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::read_until_expr_op<AsyncReadStream, + typename decay<DynamicBuffer>::type, + boost::regex, ASIO_HANDLER_TYPE(ReadHandler, + void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), + expr, init.completion_handler)(asio::error_code(), 0, 1); + + return init.result.get(); +} + +#endif // defined(ASIO_HAS_BOOST_REGEX) + +namespace detail +{ + template <typename AsyncReadStream, typename DynamicBuffer, + typename MatchCondition, typename ReadHandler> + class read_until_match_op + { + public: + template <typename BufferSequence> + read_until_match_op(AsyncReadStream& stream, + ASIO_MOVE_ARG(BufferSequence) buffers, + MatchCondition match_condition, ReadHandler& handler) + : stream_(stream), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + match_condition_(match_condition), + start_(0), + search_position_(0), + handler_(ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + read_until_match_op(const read_until_match_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + match_condition_(other.match_condition_), + start_(other.start_), + search_position_(other.search_position_), + handler_(other.handler_) + { + } + + read_until_match_op(read_until_match_op&& other) + : stream_(other.stream_), + buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + match_condition_(other.match_condition_), + start_(other.start_), + search_position_(other.search_position_), + handler_(ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::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 bytes_to_read; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = buffers_.data(); + 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 operation to obtain more data. + stream_.async_read_some(buffers_.prepare(bytes_to_read), + ASIO_MOVE_CAST(read_until_match_op)(*this)); + return; default: + buffers_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const asio::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 buffers_; + MatchCondition match_condition_; + int start_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template <typename AsyncReadStream, typename DynamicBuffer, + typename MatchCondition, typename ReadHandler> + inline void* asio_handler_allocate(std::size_t size, + read_until_match_op<AsyncReadStream, DynamicBuffer, + MatchCondition, ReadHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer, + typename MatchCondition, typename ReadHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_match_op<AsyncReadStream, DynamicBuffer, + MatchCondition, ReadHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncReadStream, typename DynamicBuffer, + typename MatchCondition, typename ReadHandler> + inline bool asio_handler_is_continuation( + read_until_match_op<AsyncReadStream, DynamicBuffer, + MatchCondition, ReadHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename MatchCondition, + typename ReadHandler> + inline void asio_handler_invoke(Function& function, + read_until_match_op<AsyncReadStream, DynamicBuffer, + MatchCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename MatchCondition, + typename ReadHandler> + inline void asio_handler_invoke(const Function& function, + read_until_match_op<AsyncReadStream, DynamicBuffer, + MatchCondition, ReadHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename MatchCondition, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_match_op<AsyncReadStream, + DynamicBuffer, 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 Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer, + typename MatchCondition, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_match_op<AsyncReadStream, + DynamicBuffer, 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 Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename MatchCondition, typename ReadHandler> +ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if<is_match_condition<MatchCondition>::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. + ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::read_until_match_op<AsyncReadStream, + typename decay<DynamicBuffer>::type, + MatchCondition, ASIO_HANDLER_TYPE(ReadHandler, + void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), + match_condition, init.completion_handler)( + asio::error_code(), 0, 1); + + return init.result.get(); +} + +#if !defined(ASIO_NO_IOSTREAM) + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + char delim, ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + delim, ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + ASIO_STRING_VIEW_PARAM delim, + ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + delim, ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#if defined(ASIO_HAS_BOOST_REGEX) + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + expr, ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#endif // defined(ASIO_HAS_BOOST_REGEX) + +template <typename AsyncReadStream, typename Allocator, + typename MatchCondition, typename ReadHandler> +inline ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (asio::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + asio::basic_streambuf<Allocator>& b, + MatchCondition match_condition, ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + match_condition, ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_READ_UNTIL_HPP diff --git a/lib/asio/impl/serial_port_base.hpp b/lib/asio/impl/serial_port_base.hpp new file mode 100644 index 0000000..cdc201d --- /dev/null +++ b/lib/asio/impl/serial_port_base.hpp @@ -0,0 +1,59 @@ +// +// impl/serial_port_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 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 +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_SERIAL_PORT_BASE_HPP +#define ASIO_IMPL_SERIAL_PORT_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +namespace asio { + +inline serial_port_base::baud_rate::baud_rate(unsigned int rate) + : value_(rate) +{ +} + +inline unsigned int serial_port_base::baud_rate::value() const +{ + return value_; +} + +inline serial_port_base::flow_control::type +serial_port_base::flow_control::value() const +{ + return value_; +} + +inline serial_port_base::parity::type serial_port_base::parity::value() const +{ + return value_; +} + +inline serial_port_base::stop_bits::type +serial_port_base::stop_bits::value() const +{ + return value_; +} + +inline unsigned int serial_port_base::character_size::value() const +{ + return value_; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_SERIAL_PORT_BASE_HPP diff --git a/lib/asio/impl/serial_port_base.ipp b/lib/asio/impl/serial_port_base.ipp new file mode 100644 index 0000000..21323ee --- /dev/null +++ b/lib/asio/impl/serial_port_base.ipp @@ -0,0 +1,557 @@ +// +// impl/serial_port_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 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 +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IMPL_SERIAL_PORT_BASE_IPP +#define ASIO_IMPL_SERIAL_PORT_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HAS_SERIAL_PORT) + +#include <stdexcept> +#include "asio/error.hpp" +#include "asio/serial_port_base.hpp" +#include "asio/detail/throw_exception.hpp" + +#if defined(GENERATING_DOCUMENTATION) +# define ASIO_OPTION_STORAGE implementation_defined +#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__) +# define ASIO_OPTION_STORAGE DCB +#else +# define ASIO_OPTION_STORAGE termios +#endif + +#include "asio/detail/push_options.hpp" + +namespace asio { + +ASIO_SYNC_OP_VOID serial_port_base::baud_rate::store( + ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + storage.BaudRate = value_; +#else + speed_t baud; + switch (value_) + { + // Do POSIX-specified rates first. + case 0: baud = B0; break; + case 50: baud = B50; break; + case 75: baud = B75; break; + case 110: baud = B110; break; + case 134: baud = B134; break; + case 150: baud = B150; break; + case 200: baud = B200; break; + case 300: baud = B300; break; + case 600: baud = B600; break; + case 1200: baud = B1200; break; + case 1800: baud = B1800; break; + case 2400: baud = B2400; break; + case 4800: baud = B4800; break; + case 9600: baud = B9600; break; + case 19200: baud = B19200; break; + case 38400: baud = B38400; break; + // And now the extended ones conditionally. +# ifdef B7200 + case 7200: baud = B7200; break; +# endif +# ifdef B14400 + case 14400: baud = B14400; break; +# endif +# ifdef B57600 + case 57600: baud = B57600; break; +# endif +# ifdef B115200 + case 115200: baud = B115200; break; +# endif +# ifdef B230400 + case 230400: baud = B230400; break; +# endif +# ifdef B460800 + case 460800: baud = B460800; break; +# endif +# ifdef B500000 + case 500000: baud = B500000; break; +# endif +# ifdef B576000 + case 576000: baud = B576000; break; +# endif +# ifdef B921600 + case 921600: baud = B921600; break; +# endif +# ifdef B1000000 + case 1000000: baud = B1000000; break; +# endif +# ifdef B1152000 + case 1152000: baud = B1152000; break; +# endif +# ifdef B2000000 + case 2000000: baud = B2000000; break; +# endif +# ifdef B3000000 + case 3000000: baud = B3000000; break; +# endif +# ifdef B3500000 + case 3500000: baud = B3500000; break; +# endif +# ifdef B4000000 + case 4000000: baud = B4000000; break; +# endif + default: + ec = asio::error::invalid_argument; + ASIO_SYNC_OP_VOID_RETURN(ec); + } +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + ::cfsetspeed(&storage, baud); +# else + ::cfsetispeed(&storage, baud); + ::cfsetospeed(&storage, baud); +# endif +#endif + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +ASIO_SYNC_OP_VOID serial_port_base::baud_rate::load( + const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + value_ = storage.BaudRate; +#else + speed_t baud = ::cfgetospeed(&storage); + switch (baud) + { + // First do those specified by POSIX. + case B0: value_ = 0; break; + case B50: value_ = 50; break; + case B75: value_ = 75; break; + case B110: value_ = 110; break; + case B134: value_ = 134; break; + case B150: value_ = 150; break; + case B200: value_ = 200; break; + case B300: value_ = 300; break; + case B600: value_ = 600; break; + case B1200: value_ = 1200; break; + case B1800: value_ = 1800; break; + case B2400: value_ = 2400; break; + case B4800: value_ = 4800; break; + case B9600: value_ = 9600; break; + case B19200: value_ = 19200; break; + case B38400: value_ = 38400; break; + // Now conditionally handle a bunch of extended rates. +# ifdef B7200 + case B7200: value_ = 7200; break; +# endif +# ifdef B14400 + case B14400: value_ = 14400; break; +# endif +# ifdef B57600 + case B57600: value_ = 57600; break; +# endif +# ifdef B115200 + case B115200: value_ = 115200; break; +# endif +# ifdef B230400 + case B230400: value_ = 230400; break; +# endif +# ifdef B460800 + case B460800: value_ = 460800; break; +# endif +# ifdef B500000 + case B500000: value_ = 500000; break; +# endif +# ifdef B576000 + case B576000: value_ = 576000; break; +# endif +# ifdef B921600 + case B921600: value_ = 921600; break; +# endif +# ifdef B1000000 + case B1000000: value_ = 1000000; break; +# endif +# ifdef B1152000 + case B1152000: value_ = 1152000; break; +# endif +# ifdef B2000000 + case B2000000: value_ = 2000000; break; +# endif +# ifdef B3000000 + case B3000000: value_ = 3000000; break; +# endif +# ifdef B3500000 + case B3500000: value_ = 3500000; break; +# endif +# ifdef B4000000 + case B4000000: value_ = 4000000; break; +# endif + default: + value_ = 0; + ec = asio::error::invalid_argument; + ASIO_SYNC_OP_VOID_RETURN(ec); + } +#endif + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +serial_port_base::flow_control::flow_control( + serial_port_base::flow_control::type t) + : value_(t) +{ + if (t != none && t != software && t != hardware) + { + std::out_of_range ex("invalid flow_control value"); + asio::detail::throw_exception(ex); + } +} + +ASIO_SYNC_OP_VOID serial_port_base::flow_control::store( + ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + storage.fOutxCtsFlow = FALSE; + storage.fOutxDsrFlow = FALSE; + storage.fTXContinueOnXoff = TRUE; + storage.fDtrControl = DTR_CONTROL_ENABLE; + storage.fDsrSensitivity = FALSE; + storage.fOutX = FALSE; + storage.fInX = FALSE; + storage.fRtsControl = RTS_CONTROL_ENABLE; + switch (value_) + { + case none: + break; + case software: + storage.fOutX = TRUE; + storage.fInX = TRUE; + break; + case hardware: + storage.fOutxCtsFlow = TRUE; + storage.fRtsControl = RTS_CONTROL_HANDSHAKE; + break; + default: + break; + } +#else + switch (value_) + { + case none: + storage.c_iflag &= ~(IXOFF | IXON); +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + storage.c_cflag &= ~CRTSCTS; +# elif defined(__QNXNTO__) + storage.c_cflag &= ~(IHFLOW | OHFLOW); +# endif + break; + case software: + storage.c_iflag |= IXOFF | IXON; +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + storage.c_cflag &= ~CRTSCTS; +# elif defined(__QNXNTO__) + storage.c_cflag &= ~(IHFLOW | OHFLOW); +# endif + break; + case hardware: +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + storage.c_iflag &= ~(IXOFF | IXON); + storage.c_cflag |= CRTSCTS; + break; +# elif defined(__QNXNTO__) + storage.c_iflag &= ~(IXOFF | IXON); + storage.c_cflag |= (IHFLOW | OHFLOW); + break; +# else + ec = asio::error::operation_not_supported; + ASIO_SYNC_OP_VOID_RETURN(ec); +# endif + default: + break; + } +#endif + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +ASIO_SYNC_OP_VOID serial_port_base::flow_control::load( + const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + if (storage.fOutX && storage.fInX) + { + value_ = software; + } + else if (storage.fOutxCtsFlow && storage.fRtsControl == RTS_CONTROL_HANDSHAKE) + { + value_ = hardware; + } + else + { + value_ = none; + } +#else + if (storage.c_iflag & (IXOFF | IXON)) + { + value_ = software; + } +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + else if (storage.c_cflag & CRTSCTS) + { + value_ = hardware; + } +# elif defined(__QNXNTO__) + else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW) + { + value_ = hardware; + } +# endif + else + { + value_ = none; + } +#endif + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +serial_port_base::parity::parity(serial_port_base::parity::type t) + : value_(t) +{ + if (t != none && t != odd && t != even) + { + std::out_of_range ex("invalid parity value"); + asio::detail::throw_exception(ex); + } +} + +ASIO_SYNC_OP_VOID serial_port_base::parity::store( + ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + switch (value_) + { + case none: + storage.fParity = FALSE; + storage.Parity = NOPARITY; + break; + case odd: + storage.fParity = TRUE; + storage.Parity = ODDPARITY; + break; + case even: + storage.fParity = TRUE; + storage.Parity = EVENPARITY; + break; + default: + break; + } +#else + switch (value_) + { + case none: + storage.c_iflag |= IGNPAR; + storage.c_cflag &= ~(PARENB | PARODD); + break; + case even: + storage.c_iflag &= ~(IGNPAR | PARMRK); + storage.c_iflag |= INPCK; + storage.c_cflag |= PARENB; + storage.c_cflag &= ~PARODD; + break; + case odd: + storage.c_iflag &= ~(IGNPAR | PARMRK); + storage.c_iflag |= INPCK; + storage.c_cflag |= (PARENB | PARODD); + break; + default: + break; + } +#endif + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +ASIO_SYNC_OP_VOID serial_port_base::parity::load( + const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + if (storage.Parity == EVENPARITY) + { + value_ = even; + } + else if (storage.Parity == ODDPARITY) + { + value_ = odd; + } + else + { + value_ = none; + } +#else + if (storage.c_cflag & PARENB) + { + if (storage.c_cflag & PARODD) + { + value_ = odd; + } + else + { + value_ = even; + } + } + else + { + value_ = none; + } +#endif + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +serial_port_base::stop_bits::stop_bits( + serial_port_base::stop_bits::type t) + : value_(t) +{ + if (t != one && t != onepointfive && t != two) + { + std::out_of_range ex("invalid stop_bits value"); + asio::detail::throw_exception(ex); + } +} + +ASIO_SYNC_OP_VOID serial_port_base::stop_bits::store( + ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + switch (value_) + { + case one: + storage.StopBits = ONESTOPBIT; + break; + case onepointfive: + storage.StopBits = ONE5STOPBITS; + break; + case two: + storage.StopBits = TWOSTOPBITS; + break; + default: + break; + } +#else + switch (value_) + { + case one: + storage.c_cflag &= ~CSTOPB; + break; + case two: + storage.c_cflag |= CSTOPB; + break; + default: + ec = asio::error::operation_not_supported; + ASIO_SYNC_OP_VOID_RETURN(ec); + } +#endif + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +ASIO_SYNC_OP_VOID serial_port_base::stop_bits::load( + const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + if (storage.StopBits == ONESTOPBIT) + { + value_ = one; + } + else if (storage.StopBits == ONE5STOPBITS) + { + value_ = onepointfive; + } + else if (storage.StopBits == TWOSTOPBITS) + { + value_ = two; + } + else + { + value_ = one; + } +#else + value_ = (storage.c_cflag & CSTOPB) ? two : one; +#endif + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +serial_port_base::character_size::character_size(unsigned int t) + : value_(t) +{ + if (t < 5 || t > 8) + { + std::out_of_range ex("invalid character_size value"); + asio::detail::throw_exception(ex); + } +} + +ASIO_SYNC_OP_VOID serial_port_base::character_size::store( + ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + storage.ByteSize = value_; +#else + storage.c_cflag &= ~CSIZE; + switch (value_) + { + case 5: storage.c_cflag |= CS5; break; + case 6: storage.c_cflag |= CS6; break; + case 7: storage.c_cflag |= CS7; break; + case 8: storage.c_cflag |= CS8; break; + default: break; + } +#endif + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +ASIO_SYNC_OP_VOID serial_port_base::character_size::load( + const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) +{ +#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) + value_ = storage.ByteSize; +#else + +#pragma GCC diagnostic ignored "-Wduplicated-branches" + if ((storage.c_cflag & CSIZE) == CS5) { value_ = 5; } + else if ((storage.c_cflag & CSIZE) == CS6) { value_ = 6; } + else if ((storage.c_cflag & CSIZE) == CS7) { value_ = 7; } + else if ((storage.c_cflag & CSIZE) == CS8) { value_ = 8; } + else + { + // Hmmm, use 8 for now. + value_ = 8; + } +#pragma GCC diagnostic pop +#endif + ec = asio::error_code(); + ASIO_SYNC_OP_VOID_RETURN(ec); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#undef ASIO_OPTION_STORAGE + +#endif // defined(ASIO_HAS_SERIAL_PORT) + +#endif // ASIO_IMPL_SERIAL_PORT_BASE_IPP diff --git a/lib/asio/impl/spawn.hpp b/lib/asio/impl/spawn.hpp new file mode 100644 index 0000000..5594ad9 --- /dev/null +++ b/lib/asio/impl/spawn.hpp @@ -0,0 +1,535 @@ +// +// impl/spawn.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_SPAWN_HPP +#define ASIO_IMPL_SPAWN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/async_result.hpp" +#include "asio/bind_executor.hpp" +#include "asio/detail/atomic_count.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/memory.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/system_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + + template <typename Handler, typename T> + class coro_handler + { + public: + coro_handler(basic_yield_context<Handler> ctx) + : coro_(ctx.coro_.lock()), + ca_(ctx.ca_), + handler_(ctx.handler_), + ready_(0), + ec_(ctx.ec_), + value_(0) + { + } + + void operator()(T value) + { + *ec_ = asio::error_code(); + *value_ = ASIO_MOVE_CAST(T)(value); + if (--*ready_ == 0) + (*coro_)(); + } + + void operator()(asio::error_code ec, T value) + { + *ec_ = ec; + *value_ = ASIO_MOVE_CAST(T)(value); + if (--*ready_ == 0) + (*coro_)(); + } + + //private: + shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_; + typename basic_yield_context<Handler>::caller_type& ca_; + Handler handler_; + atomic_count* ready_; + asio::error_code* ec_; + T* value_; + }; + + template <typename Handler> + class coro_handler<Handler, void> + { + public: + coro_handler(basic_yield_context<Handler> ctx) + : coro_(ctx.coro_.lock()), + ca_(ctx.ca_), + handler_(ctx.handler_), + ready_(0), + ec_(ctx.ec_) + { + } + + void operator()() + { + *ec_ = asio::error_code(); + if (--*ready_ == 0) + (*coro_)(); + } + + void operator()(asio::error_code ec) + { + *ec_ = ec; + if (--*ready_ == 0) + (*coro_)(); + } + + //private: + shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_; + typename basic_yield_context<Handler>::caller_type& ca_; + Handler handler_; + atomic_count* ready_; + asio::error_code* ec_; + }; + + template <typename Handler, typename T> + inline void* asio_handler_allocate(std::size_t size, + coro_handler<Handler, T>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename Handler, typename T> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + coro_handler<Handler, T>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Handler, typename T> + inline bool asio_handler_is_continuation(coro_handler<Handler, T>*) + { + return true; + } + + template <typename Function, typename Handler, typename T> + inline void asio_handler_invoke(Function& function, + coro_handler<Handler, T>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename Handler, typename T> + inline void asio_handler_invoke(const Function& function, + coro_handler<Handler, T>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Handler, typename T> + class coro_async_result + { + public: + typedef coro_handler<Handler, T> completion_handler_type; + typedef T return_type; + + explicit coro_async_result(completion_handler_type& h) + : handler_(h), + ca_(h.ca_), + ready_(2) + { + h.ready_ = &ready_; + out_ec_ = h.ec_; + if (!out_ec_) h.ec_ = &ec_; + h.value_ = &value_; + } + + return_type get() + { + // Must not hold shared_ptr to coro while suspended. + handler_.coro_.reset(); + + if (--ready_ != 0) + ca_(); + if (!out_ec_ && ec_) throw asio::system_error(ec_); + return ASIO_MOVE_CAST(return_type)(value_); + } + + private: + completion_handler_type& handler_; + typename basic_yield_context<Handler>::caller_type& ca_; + atomic_count ready_; + asio::error_code* out_ec_; + asio::error_code ec_; + return_type value_; + }; + + template <typename Handler> + class coro_async_result<Handler, void> + { + public: + typedef coro_handler<Handler, void> completion_handler_type; + typedef void return_type; + + explicit coro_async_result(completion_handler_type& h) + : handler_(h), + ca_(h.ca_), + ready_(2) + { + h.ready_ = &ready_; + out_ec_ = h.ec_; + if (!out_ec_) h.ec_ = &ec_; + } + + void get() + { + // Must not hold shared_ptr to coro while suspended. + handler_.coro_.reset(); + + if (--ready_ != 0) + ca_(); + if (!out_ec_ && ec_) throw asio::system_error(ec_); + } + + private: + completion_handler_type& handler_; + typename basic_yield_context<Handler>::caller_type& ca_; + atomic_count ready_; + asio::error_code* out_ec_; + asio::error_code ec_; + }; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Handler, typename ReturnType> +class async_result<basic_yield_context<Handler>, ReturnType()> + : public detail::coro_async_result<Handler, void> +{ +public: + explicit async_result( + typename detail::coro_async_result<Handler, + void>::completion_handler_type& h) + : detail::coro_async_result<Handler, void>(h) + { + } +}; + +template <typename Handler, typename ReturnType, typename Arg1> +class async_result<basic_yield_context<Handler>, ReturnType(Arg1)> + : public detail::coro_async_result<Handler, typename decay<Arg1>::type> +{ +public: + explicit async_result( + typename detail::coro_async_result<Handler, + typename decay<Arg1>::type>::completion_handler_type& h) + : detail::coro_async_result<Handler, typename decay<Arg1>::type>(h) + { + } +}; + +template <typename Handler, typename ReturnType> +class async_result<basic_yield_context<Handler>, + ReturnType(asio::error_code)> + : public detail::coro_async_result<Handler, void> +{ +public: + explicit async_result( + typename detail::coro_async_result<Handler, + void>::completion_handler_type& h) + : detail::coro_async_result<Handler, void>(h) + { + } +}; + +template <typename Handler, typename ReturnType, typename Arg2> +class async_result<basic_yield_context<Handler>, + ReturnType(asio::error_code, Arg2)> + : public detail::coro_async_result<Handler, typename decay<Arg2>::type> +{ +public: + explicit async_result( + typename detail::coro_async_result<Handler, + typename decay<Arg2>::type>::completion_handler_type& h) + : detail::coro_async_result<Handler, typename decay<Arg2>::type>(h) + { + } +}; + +#if !defined(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(asio::error_code)> +{ + typedef detail::coro_handler<Handler, void> type; +}; + +template <typename Handler, typename ReturnType, typename Arg2> +struct handler_type<basic_yield_context<Handler>, + ReturnType(asio::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(ASIO_NO_DEPRECATED) + +template <typename Handler, typename T, typename Allocator> +struct associated_allocator<detail::coro_handler<Handler, T>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const detail::coro_handler<Handler, T>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Handler, typename T, typename Executor> +struct associated_executor<detail::coro_handler<Handler, T>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const detail::coro_handler<Handler, T>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +namespace detail { + + template <typename Handler, typename Function> + struct spawn_data : private noncopyable + { + template <typename Hand, typename Func> + spawn_data(ASIO_MOVE_ARG(Hand) handler, + bool call_handler, ASIO_MOVE_ARG(Func) function) + : handler_(ASIO_MOVE_CAST(Hand)(handler)), + call_handler_(call_handler), + function_(ASIO_MOVE_CAST(Func)(function)) + { + } + + weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_; + Handler handler_; + bool call_handler_; + Function function_; + }; + + template <typename Handler, typename Function> + struct coro_entry_point + { + void operator()(typename basic_yield_context<Handler>::caller_type& ca) + { + shared_ptr<spawn_data<Handler, Function> > data(data_); +#if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) + ca(); // Yield until coroutine pointer has been initialised. +#endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) + const basic_yield_context<Handler> yield( + data->coro_, ca, data->handler_); + + (data->function_)(yield); + if (data->call_handler_) + (data->handler_)(); + } + + shared_ptr<spawn_data<Handler, Function> > data_; + }; + + template <typename Handler, typename Function> + struct spawn_helper + { + void operator()() + { + typedef typename basic_yield_context<Handler>::callee_type callee_type; + coro_entry_point<Handler, Function> entry_point = { data_ }; + shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_)); + data_->coro_ = coro; + (*coro)(); + } + + shared_ptr<spawn_data<Handler, Function> > data_; + boost::coroutines::attributes attributes_; + }; + + template <typename Function, typename Handler, typename Function1> + inline void asio_handler_invoke(Function& function, + spawn_helper<Handler, Function1>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->data_->handler_); + } + + template <typename Function, typename Handler, typename Function1> + inline void asio_handler_invoke(const Function& function, + spawn_helper<Handler, Function1>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->data_->handler_); + } + + inline void default_spawn_handler() {} + +} // namespace detail + +template <typename Function> +inline void spawn(ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes) +{ + typedef typename decay<Function>::type function_type; + + typename associated_executor<function_type>::type ex( + (get_associated_executor)(function)); + + asio::spawn(ex, ASIO_MOVE_CAST(Function)(function), attributes); +} + +template <typename Handler, typename Function> +void spawn(ASIO_MOVE_ARG(Handler) handler, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes, + typename enable_if<!is_executor<typename decay<Handler>::type>::value && + !is_convertible<Handler&, execution_context&>::value>::type*) +{ + typedef typename decay<Handler>::type handler_type; + typedef typename decay<Function>::type function_type; + + typename associated_executor<handler_type>::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator<handler_type>::type a( + (get_associated_allocator)(handler)); + + detail::spawn_helper<handler_type, function_type> helper; + helper.data_.reset( + new detail::spawn_data<handler_type, function_type>( + ASIO_MOVE_CAST(Handler)(handler), true, + ASIO_MOVE_CAST(Function)(function))); + helper.attributes_ = attributes; + + ex.dispatch(helper, a); +} + +template <typename Handler, typename Function> +void spawn(basic_yield_context<Handler> ctx, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes) +{ + typedef typename decay<Function>::type function_type; + + Handler handler(ctx.handler_); // Explicit copy that might be moved from. + + typename associated_executor<Handler>::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator<Handler>::type a( + (get_associated_allocator)(handler)); + + detail::spawn_helper<Handler, function_type> helper; + helper.data_.reset( + new detail::spawn_data<Handler, function_type>( + ASIO_MOVE_CAST(Handler)(handler), false, + ASIO_MOVE_CAST(Function)(function))); + helper.attributes_ = attributes; + + ex.dispatch(helper, a); +} + +template <typename Function, typename Executor> +inline void spawn(const Executor& ex, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes, + typename enable_if<is_executor<Executor>::value>::type*) +{ + asio::spawn(asio::strand<Executor>(ex), + ASIO_MOVE_CAST(Function)(function), attributes); +} + +template <typename Function, typename Executor> +inline void spawn(const strand<Executor>& ex, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes) +{ + asio::spawn(asio::bind_executor( + ex, &detail::default_spawn_handler), + ASIO_MOVE_CAST(Function)(function), attributes); +} + +template <typename Function> +inline void spawn(const asio::io_context::strand& s, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes) +{ + asio::spawn(asio::bind_executor( + s, &detail::default_spawn_handler), + ASIO_MOVE_CAST(Function)(function), attributes); +} + +template <typename Function, typename ExecutionContext> +inline void spawn(ExecutionContext& ctx, + ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type*) +{ + asio::spawn(ctx.get_executor(), + ASIO_MOVE_CAST(Function)(function), attributes); +} + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_SPAWN_HPP diff --git a/lib/asio/impl/src.cpp b/lib/asio/impl/src.cpp new file mode 100644 index 0000000..e8a5953 --- /dev/null +++ b/lib/asio/impl/src.cpp @@ -0,0 +1,25 @@ +// +// impl/src.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#if defined(_MSC_VER) \ + || defined(__BORLANDC__) \ + || defined(__DMC__) +# pragma message ( \ + "This file is deprecated. " \ + "Please #include <asio/impl/src.hpp> instead.") +#elif defined(__GNUC__) \ + || defined(__HP_aCC) \ + || defined(__SUNPRO_CC) \ + || defined(__IBMCPP__) +# warning "This file is deprecated." +# warning "Please #include <asio/impl/src.hpp> instead." +#endif + +#include "asio/impl/src.hpp" diff --git a/lib/asio/impl/src.hpp b/lib/asio/impl/src.hpp new file mode 100644 index 0000000..a72637b --- /dev/null +++ b/lib/asio/impl/src.hpp @@ -0,0 +1,82 @@ +// +// impl/src.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_SRC_HPP +#define ASIO_IMPL_SRC_HPP + +#define ASIO_SOURCE + +#include "asio/detail/config.hpp" + +#if defined(ASIO_HEADER_ONLY) +# error Do not compile Asio library source with ASIO_HEADER_ONLY defined +#endif + +#include "asio/impl/error.ipp" +#include "asio/impl/error_code.ipp" +#include "asio/impl/execution_context.ipp" +#include "asio/impl/executor.ipp" +#include "asio/impl/handler_alloc_hook.ipp" +#include "asio/impl/io_context.ipp" +#include "asio/impl/serial_port_base.ipp" +#include "asio/impl/system_context.ipp" +#include "asio/impl/thread_pool.ipp" +#include "asio/detail/impl/buffer_sequence_adapter.ipp" +#include "asio/detail/impl/descriptor_ops.ipp" +#include "asio/detail/impl/dev_poll_reactor.ipp" +#include "asio/detail/impl/epoll_reactor.ipp" +#include "asio/detail/impl/eventfd_select_interrupter.ipp" +#include "asio/detail/impl/handler_tracking.ipp" +#include "asio/detail/impl/kqueue_reactor.ipp" +#include "asio/detail/impl/null_event.ipp" +#include "asio/detail/impl/pipe_select_interrupter.ipp" +#include "asio/detail/impl/posix_event.ipp" +#include "asio/detail/impl/posix_mutex.ipp" +#include "asio/detail/impl/posix_thread.ipp" +#include "asio/detail/impl/posix_tss_ptr.ipp" +#include "asio/detail/impl/reactive_descriptor_service.ipp" +#include "asio/detail/impl/reactive_serial_port_service.ipp" +#include "asio/detail/impl/reactive_socket_service_base.ipp" +#include "asio/detail/impl/resolver_service_base.ipp" +#include "asio/detail/impl/scheduler.ipp" +#include "asio/detail/impl/select_reactor.ipp" +#include "asio/detail/impl/service_registry.ipp" +#include "asio/detail/impl/signal_set_service.ipp" +#include "asio/detail/impl/socket_ops.ipp" +#include "asio/detail/impl/socket_select_interrupter.ipp" +#include "asio/detail/impl/strand_executor_service.ipp" +#include "asio/detail/impl/strand_service.ipp" +#include "asio/detail/impl/throw_error.ipp" +#include "asio/detail/impl/timer_queue_ptime.ipp" +#include "asio/detail/impl/timer_queue_set.ipp" +#include "asio/detail/impl/win_iocp_handle_service.ipp" +#include "asio/detail/impl/win_iocp_io_context.ipp" +#include "asio/detail/impl/win_iocp_serial_port_service.ipp" +#include "asio/detail/impl/win_iocp_socket_service_base.ipp" +#include "asio/detail/impl/win_event.ipp" +#include "asio/detail/impl/win_mutex.ipp" +#include "asio/detail/impl/win_object_handle_service.ipp" +#include "asio/detail/impl/win_static_mutex.ipp" +#include "asio/detail/impl/win_thread.ipp" +#include "asio/detail/impl/win_tss_ptr.ipp" +#include "asio/detail/impl/winrt_ssocket_service_base.ipp" +#include "asio/detail/impl/winrt_timer_scheduler.ipp" +#include "asio/detail/impl/winsock_init.ipp" +#include "asio/generic/detail/impl/endpoint.ipp" +#include "asio/ip/impl/address.ipp" +#include "asio/ip/impl/address_v4.ipp" +#include "asio/ip/impl/address_v6.ipp" +#include "asio/ip/impl/host_name.ipp" +#include "asio/ip/impl/network_v4.ipp" +#include "asio/ip/impl/network_v6.ipp" +#include "asio/ip/detail/impl/endpoint.ipp" +#include "asio/local/detail/impl/endpoint.ipp" + +#endif // ASIO_IMPL_SRC_HPP diff --git a/lib/asio/impl/system_context.hpp b/lib/asio/impl/system_context.hpp new file mode 100644 index 0000000..87ffe76 --- /dev/null +++ b/lib/asio/impl/system_context.hpp @@ -0,0 +1,34 @@ +// +// impl/system_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_SYSTEM_CONTEXT_HPP +#define ASIO_IMPL_SYSTEM_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/system_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +inline system_context::executor_type +system_context::get_executor() ASIO_NOEXCEPT +{ + return system_executor(); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_SYSTEM_CONTEXT_HPP diff --git a/lib/asio/impl/system_context.ipp b/lib/asio/impl/system_context.ipp new file mode 100644 index 0000000..8ad5e41 --- /dev/null +++ b/lib/asio/impl/system_context.ipp @@ -0,0 +1,73 @@ +// +// impl/system_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_SYSTEM_CONTEXT_IPP +#define ASIO_IMPL_SYSTEM_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/system_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +struct system_context::thread_function +{ + detail::scheduler* scheduler_; + + void operator()() + { + asio::error_code ec; + scheduler_->run(ec); + } +}; + +system_context::system_context() + : scheduler_(use_service<detail::scheduler>(*this)) +{ + scheduler_.work_started(); + + thread_function f = { &scheduler_ }; + std::size_t num_threads = detail::thread::hardware_concurrency() * 2; + threads_.create_threads(f, num_threads ? num_threads : 2); +} + +system_context::~system_context() +{ + scheduler_.work_finished(); + scheduler_.stop(); + threads_.join(); +} + +void system_context::stop() +{ + scheduler_.stop(); +} + +bool system_context::stopped() const ASIO_NOEXCEPT +{ + return scheduler_.stopped(); +} + +void system_context::join() +{ + scheduler_.work_finished(); + threads_.join(); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_SYSTEM_CONTEXT_IPP diff --git a/lib/asio/impl/system_executor.hpp b/lib/asio/impl/system_executor.hpp new file mode 100644 index 0000000..ac4861f --- /dev/null +++ b/lib/asio/impl/system_executor.hpp @@ -0,0 +1,85 @@ +// +// impl/system_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_SYSTEM_EXECUTOR_HPP +#define ASIO_IMPL_SYSTEM_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/executor_op.hpp" +#include "asio/detail/global.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/system_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +inline system_context& system_executor::context() const ASIO_NOEXCEPT +{ + return detail::global<system_context>(); +} + +template <typename Function, typename Allocator> +void system_executor::dispatch( + ASIO_MOVE_ARG(Function) f, const Allocator&) const +{ + typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f)); + asio_handler_invoke_helpers::invoke(tmp, tmp); +} + +template <typename Function, typename Allocator> +void system_executor::post( + ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + system_context& ctx = detail::global<system_context>(); + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a); + + ASIO_HANDLER_CREATION((ctx, *p.p, + "system_executor", &this->context(), 0, "post")); + + ctx.scheduler_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template <typename Function, typename Allocator> +void system_executor::defer( + ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + system_context& ctx = detail::global<system_context>(); + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a); + + ASIO_HANDLER_CREATION((ctx, *p.p, + "system_executor", &this->context(), 0, "defer")); + + ctx.scheduler_.post_immediate_completion(p.p, true); + p.v = p.p = 0; +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_SYSTEM_EXECUTOR_HPP diff --git a/lib/asio/impl/thread_pool.hpp b/lib/asio/impl/thread_pool.hpp new file mode 100644 index 0000000..058e377 --- /dev/null +++ b/lib/asio/impl/thread_pool.hpp @@ -0,0 +1,127 @@ +// +// impl/thread_pool.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_THREAD_POOL_HPP +#define ASIO_IMPL_THREAD_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/executor_op.hpp" +#include "asio/detail/fenced_block.hpp" +#include "asio/detail/recycling_allocator.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution_context.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +inline thread_pool::executor_type +thread_pool::get_executor() ASIO_NOEXCEPT +{ + return executor_type(*this); +} + +inline thread_pool& +thread_pool::executor_type::context() const ASIO_NOEXCEPT +{ + return pool_; +} + +inline void +thread_pool::executor_type::on_work_started() const ASIO_NOEXCEPT +{ + pool_.scheduler_.work_started(); +} + +inline void thread_pool::executor_type::on_work_finished() +const ASIO_NOEXCEPT +{ + pool_.scheduler_.work_finished(); +} + +template <typename Function, typename Allocator> +void thread_pool::executor_type::dispatch( + ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Invoke immediately if we are already inside the thread pool. + if (pool_.scheduler_.can_dispatch()) + { + // Make a local, non-const copy of the function. + function_type tmp(ASIO_MOVE_CAST(Function)(f)); + + detail::fenced_block b(detail::fenced_block::full); + asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a); + + ASIO_HANDLER_CREATION((pool_, *p.p, + "thread_pool", &this->context(), 0, "dispatch")); + + pool_.scheduler_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template <typename Function, typename Allocator> +void thread_pool::executor_type::post( + ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a); + + ASIO_HANDLER_CREATION((pool_, *p.p, + "thread_pool", &this->context(), 0, "post")); + + pool_.scheduler_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template <typename Function, typename Allocator> +void thread_pool::executor_type::defer( + ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a); + + ASIO_HANDLER_CREATION((pool_, *p.p, + "thread_pool", &this->context(), 0, "defer")); + + pool_.scheduler_.post_immediate_completion(p.p, true); + p.v = p.p = 0; +} + +inline bool +thread_pool::executor_type::running_in_this_thread() const ASIO_NOEXCEPT +{ + return pool_.scheduler_.can_dispatch(); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_THREAD_POOL_HPP diff --git a/lib/asio/impl/thread_pool.ipp b/lib/asio/impl/thread_pool.ipp new file mode 100644 index 0000000..89583c1 --- /dev/null +++ b/lib/asio/impl/thread_pool.ipp @@ -0,0 +1,76 @@ +// +// impl/thread_pool.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_THREAD_POOL_IPP +#define ASIO_IMPL_THREAD_POOL_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/thread_pool.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +struct thread_pool::thread_function +{ + detail::scheduler* scheduler_; + + void operator()() + { + asio::error_code ec; + scheduler_->run(ec); + } +}; + +thread_pool::thread_pool() + : scheduler_(use_service<detail::scheduler>(*this)) +{ + scheduler_.work_started(); + + thread_function f = { &scheduler_ }; + std::size_t num_threads = detail::thread::hardware_concurrency() * 2; + threads_.create_threads(f, num_threads ? num_threads : 2); +} + +thread_pool::thread_pool(std::size_t num_threads) + : scheduler_(use_service<detail::scheduler>(*this)) +{ + scheduler_.work_started(); + + thread_function f = { &scheduler_ }; + threads_.create_threads(f, num_threads); +} + +thread_pool::~thread_pool() +{ + stop(); + join(); +} + +void thread_pool::stop() +{ + scheduler_.stop(); +} + +void thread_pool::join() +{ + scheduler_.work_finished(); + threads_.join(); +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_THREAD_POOL_IPP diff --git a/lib/asio/impl/use_future.hpp b/lib/asio/impl/use_future.hpp new file mode 100644 index 0000000..51eb7e2 --- /dev/null +++ b/lib/asio/impl/use_future.hpp @@ -0,0 +1,938 @@ +// +// impl/use_future.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_USE_FUTURE_HPP +#define ASIO_IMPL_USE_FUTURE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <future> +#include <tuple> +#include "asio/async_result.hpp" +#include "asio/detail/memory.hpp" +#include "asio/error_code.hpp" +#include "asio/packaged_task.hpp" +#include "asio/system_error.hpp" +#include "asio/system_executor.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename T, typename F, typename... Args> +inline void promise_invoke_and_set(std::promise<T>& p, + F& f, ASIO_MOVE_ARG(Args)... args) +{ +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) + { + p.set_value(f(ASIO_MOVE_CAST(Args)(args)...)); + } +#if !defined(ASIO_NO_EXCEPTIONS) + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) +} + +template <typename F, typename... Args> +inline void promise_invoke_and_set(std::promise<void>& p, + F& f, ASIO_MOVE_ARG(Args)... args) +{ +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) + { + f(ASIO_MOVE_CAST(Args)(args)...); + p.set_value(); + } +#if !defined(ASIO_NO_EXCEPTIONS) + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) +} + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename T, typename F> +inline void promise_invoke_and_set(std::promise<T>& p, F& f) +{ +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) + { + p.set_value(f()); + } +#if !defined(ASIO_NO_EXCEPTIONS) + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) +} + +template <typename F, typename Args> +inline void promise_invoke_and_set(std::promise<void>& p, F& f) +{ +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) + { + f(); + p.set_value(); +#if !defined(ASIO_NO_EXCEPTIONS) + } + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) +} + +#if defined(ASIO_NO_EXCEPTIONS) + +#define ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \ + template <typename T, typename F, ASIO_VARIADIC_TPARAMS(n)> \ + inline void promise_invoke_and_set(std::promise<T>& p, \ + F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + p.set_value(f(ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + \ + template <typename F, ASIO_VARIADIC_TPARAMS(n)> \ + inline void promise_invoke_and_set(std::promise<void>& p, \ + F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + f(ASIO_VARIADIC_MOVE_ARGS(n)); \ + p.set_value(); \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_PROMISE_INVOKE_DEF) +#undef ASIO_PRIVATE_PROMISE_INVOKE_DEF + +#else // defined(ASIO_NO_EXCEPTIONS) + +#define ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \ + template <typename T, typename F, ASIO_VARIADIC_TPARAMS(n)> \ + inline void promise_invoke_and_set(std::promise<T>& p, \ + F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + try \ + { \ + p.set_value(f(ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + catch (...) \ + { \ + p.set_exception(std::current_exception()); \ + } \ + } \ + \ + template <typename F, ASIO_VARIADIC_TPARAMS(n)> \ + inline void promise_invoke_and_set(std::promise<void>& p, \ + F& f, ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + try \ + { \ + f(ASIO_VARIADIC_MOVE_ARGS(n)); \ + p.set_value(); \ + } \ + catch (...) \ + { \ + p.set_exception(std::current_exception()); \ + } \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_PROMISE_INVOKE_DEF) +#undef ASIO_PRIVATE_PROMISE_INVOKE_DEF + +#endif // defined(ASIO_NO_EXCEPTIONS) + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +// A function object adapter to invoke a nullary function object and capture +// any exception thrown into a promise. +template <typename T, typename F> +class promise_invoker +{ +public: + promise_invoker(const shared_ptr<std::promise<T> >& p, + ASIO_MOVE_ARG(F) f) + : p_(p), f_(ASIO_MOVE_CAST(F)(f)) + { + } + + void operator()() + { +#if !defined(ASIO_NO_EXCEPTIONS) + try +#endif // !defined(ASIO_NO_EXCEPTIONS) + { + f_(); + } +#if !defined(ASIO_NO_EXCEPTIONS) + catch (...) + { + p_->set_exception(std::current_exception()); + } +#endif // !defined(ASIO_NO_EXCEPTIONS) + } + +private: + shared_ptr<std::promise<T> > p_; + typename decay<F>::type f_; +}; + +// An executor that adapts the system_executor to capture any exeption thrown +// by a submitted function object and save it into a promise. +template <typename T> +class promise_executor +{ +public: + explicit promise_executor(const shared_ptr<std::promise<T> >& p) + : p_(p) + { + } + + execution_context& context() const ASIO_NOEXCEPT + { + return system_executor().context(); + } + + void on_work_started() const ASIO_NOEXCEPT {} + void on_work_finished() const ASIO_NOEXCEPT {} + + template <typename F, typename A> + void dispatch(ASIO_MOVE_ARG(F) f, const A&) const + { + promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f))(); + } + + template <typename F, typename A> + void post(ASIO_MOVE_ARG(F) f, const A& a) const + { + system_executor().post( + promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f)), a); + } + + template <typename F, typename A> + void defer(ASIO_MOVE_ARG(F) f, const A& a) const + { + system_executor().defer( + promise_invoker<T, F>(p_, ASIO_MOVE_CAST(F)(f)), a); + } + + friend bool operator==(const promise_executor& a, + const promise_executor& b) ASIO_NOEXCEPT + { + return a.p_ == b.p_; + } + + friend bool operator!=(const promise_executor& a, + const promise_executor& b) ASIO_NOEXCEPT + { + return a.p_ != b.p_; + } + +private: + shared_ptr<std::promise<T> > p_; +}; + +// The base class for all completion handlers that create promises. +template <typename T> +class promise_creator +{ +public: + typedef promise_executor<T> executor_type; + + executor_type get_executor() const ASIO_NOEXCEPT + { + return executor_type(p_); + } + + typedef std::future<T> future_type; + + future_type get_future() + { + return p_->get_future(); + } + +protected: + template <typename Allocator> + void create_promise(const Allocator& a) + { + ASIO_REBIND_ALLOC(Allocator, char) b(a); + p_ = std::allocate_shared<std::promise<T>>(b, std::allocator_arg, b); + } + + shared_ptr<std::promise<T> > p_; +}; + +// For completion signature void(). +class promise_handler_0 + : public promise_creator<void> +{ +public: + void operator()() + { + this->p_->set_value(); + } +}; + +// For completion signature void(error_code). +class promise_handler_ec_0 + : public promise_creator<void> +{ +public: + void operator()(const asio::error_code& ec) + { + if (ec) + { + this->p_->set_exception( + std::make_exception_ptr( + asio::system_error(ec))); + } + else + { + this->p_->set_value(); + } + } +}; + +// For completion signature void(exception_ptr). +class promise_handler_ex_0 + : public promise_creator<void> +{ +public: + void operator()(const std::exception_ptr& ex) + { + if (ex) + { + this->p_->set_exception(ex); + } + else + { + this->p_->set_value(); + } + } +}; + +// For completion signature void(T). +template <typename T> +class promise_handler_1 + : public promise_creator<T> +{ +public: + template <typename Arg> + void operator()(ASIO_MOVE_ARG(Arg) arg) + { + this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg)); + } +}; + +// For completion signature void(error_code, T). +template <typename T> +class promise_handler_ec_1 + : public promise_creator<T> +{ +public: + template <typename Arg> + void operator()(const asio::error_code& ec, + ASIO_MOVE_ARG(Arg) arg) + { + if (ec) + { + this->p_->set_exception( + std::make_exception_ptr( + asio::system_error(ec))); + } + else + this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg)); + } +}; + +// For completion signature void(exception_ptr, T). +template <typename T> +class promise_handler_ex_1 + : public promise_creator<T> +{ +public: + template <typename Arg> + void operator()(const std::exception_ptr& ex, + ASIO_MOVE_ARG(Arg) arg) + { + if (ex) + this->p_->set_exception(ex); + else + this->p_->set_value(ASIO_MOVE_CAST(Arg)(arg)); + } +}; + +// For completion signature void(T1, ..., Tn); +template <typename T> +class promise_handler_n + : public promise_creator<T> +{ +public: +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename... Args> + void operator()(ASIO_MOVE_ARG(Args)... args) + { + this->p_->set_value( + std::forward_as_tuple( + ASIO_MOVE_CAST(Args)(args)...)); + } + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#define ASIO_PRIVATE_CALL_OP_DEF(n) \ + template <ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + this->p_->set_value( \ + std::forward_as_tuple( \ + ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF) +#undef ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) +}; + +// For completion signature void(error_code, T1, ..., Tn); +template <typename T> +class promise_handler_ec_n + : public promise_creator<T> +{ +public: +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename... Args> + void operator()(const asio::error_code& ec, + ASIO_MOVE_ARG(Args)... args) + { + if (ec) + { + this->p_->set_exception( + std::make_exception_ptr( + asio::system_error(ec))); + } + else + { + this->p_->set_value( + std::forward_as_tuple( + ASIO_MOVE_CAST(Args)(args)...)); + } + } + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#define ASIO_PRIVATE_CALL_OP_DEF(n) \ + template <ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(const asio::error_code& ec, \ + ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + if (ec) \ + { \ + this->p_->set_exception( \ + std::make_exception_ptr( \ + asio::system_error(ec))); \ + } \ + else \ + { \ + this->p_->set_value( \ + std::forward_as_tuple( \ + ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF) +#undef ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) +}; + +// For completion signature void(exception_ptr, T1, ..., Tn); +template <typename T> +class promise_handler_ex_n + : public promise_creator<T> +{ +public: +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename... Args> + void operator()(const std::exception_ptr& ex, + ASIO_MOVE_ARG(Args)... args) + { + if (ex) + this->p_->set_exception(ex); + else + { + this->p_->set_value( + std::forward_as_tuple( + ASIO_MOVE_CAST(Args)(args)...)); + } + } + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#define ASIO_PRIVATE_CALL_OP_DEF(n) \ + template <ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(const std::exception_ptr& ex, \ + ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + if (ex) \ + this->p_->set_exception(ex); \ + else \ + { \ + this->p_->set_value( \ + std::forward_as_tuple( \ + ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF) +#undef ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) +}; + +// Helper template to choose the appropriate concrete promise handler +// implementation based on the supplied completion signature. +template <typename> class promise_handler_selector; + +template <> +class promise_handler_selector<void()> + : public promise_handler_0 {}; + +template <> +class promise_handler_selector<void(asio::error_code)> + : public promise_handler_ec_0 {}; + +template <> +class promise_handler_selector<void(std::exception_ptr)> + : public promise_handler_ex_0 {}; + +template <typename Arg> +class promise_handler_selector<void(Arg)> + : public promise_handler_1<Arg> {}; + +template <typename Arg> +class promise_handler_selector<void(asio::error_code, Arg)> + : public promise_handler_ec_1<Arg> {}; + +template <typename Arg> +class promise_handler_selector<void(std::exception_ptr, Arg)> + : public promise_handler_ex_1<Arg> {}; + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename... Arg> +class promise_handler_selector<void(Arg...)> + : public promise_handler_n<std::tuple<Arg...> > {}; + +template <typename... Arg> +class promise_handler_selector<void(asio::error_code, Arg...)> + : public promise_handler_ec_n<std::tuple<Arg...> > {}; + +template <typename... Arg> +class promise_handler_selector<void(std::exception_ptr, Arg...)> + : public promise_handler_ex_n<std::tuple<Arg...> > {}; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#define ASIO_PRIVATE_PROMISE_SELECTOR_DEF(n) \ + template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \ + class promise_handler_selector< \ + void(Arg, ASIO_VARIADIC_TARGS(n))> \ + : public promise_handler_n< \ + std::tuple<Arg, ASIO_VARIADIC_TARGS(n)> > {}; \ + \ + template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \ + class promise_handler_selector< \ + void(asio::error_code, Arg, ASIO_VARIADIC_TARGS(n))> \ + : public promise_handler_ec_n< \ + std::tuple<Arg, ASIO_VARIADIC_TARGS(n)> > {}; \ + \ + template <typename Arg, ASIO_VARIADIC_TPARAMS(n)> \ + class promise_handler_selector< \ + void(std::exception_ptr, Arg, ASIO_VARIADIC_TARGS(n))> \ + : public promise_handler_ex_n< \ + std::tuple<Arg, ASIO_VARIADIC_TARGS(n)> > {}; \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_PROMISE_SELECTOR_DEF) +#undef ASIO_PRIVATE_PROMISE_SELECTOR_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +// Completion handlers produced from the use_future completion token, when not +// using use_future::operator(). +template <typename Signature, typename Allocator> +class promise_handler + : public promise_handler_selector<Signature> +{ +public: + typedef Allocator allocator_type; + typedef void result_type; + + promise_handler(use_future_t<Allocator> u) + : allocator_(u.get_allocator()) + { + this->create_promise(allocator_); + } + + allocator_type get_allocator() const ASIO_NOEXCEPT + { + return allocator_; + } + +private: + Allocator allocator_; +}; + +template <typename Function, typename Signature, typename Allocator> +inline void asio_handler_invoke(Function& f, + promise_handler<Signature, Allocator>* h) +{ + typename promise_handler<Signature, Allocator>::executor_type + ex(h->get_executor()); + ex.dispatch(ASIO_MOVE_CAST(Function)(f), std::allocator<void>()); +} + +template <typename Function, typename Signature, typename Allocator> +inline void asio_handler_invoke(const Function& f, + promise_handler<Signature, Allocator>* h) +{ + typename promise_handler<Signature, Allocator>::executor_type + ex(h->get_executor()); + ex.dispatch(f, std::allocator<void>()); +} + +// Helper base class for async_result specialisation. +template <typename Signature, typename Allocator> +class promise_async_result +{ +public: + typedef promise_handler<Signature, Allocator> completion_handler_type; + typedef typename completion_handler_type::future_type return_type; + + explicit promise_async_result(completion_handler_type& h) + : future_(h.get_future()) + { + } + + return_type get() + { + return ASIO_MOVE_CAST(return_type)(future_); + } + +private: + return_type future_; +}; + +// Return value from use_future::operator(). +template <typename Function, typename Allocator> +class packaged_token +{ +public: + packaged_token(Function f, const Allocator& a) + : function_(ASIO_MOVE_CAST(Function)(f)), + allocator_(a) + { + } + +//private: + Function function_; + Allocator allocator_; +}; + +// Completion handlers produced from the use_future completion token, when +// using use_future::operator(). +template <typename Function, typename Allocator, typename Result> +class packaged_handler + : public promise_creator<Result> +{ +public: + typedef Allocator allocator_type; + typedef void result_type; + + packaged_handler(packaged_token<Function, Allocator> t) + : function_(ASIO_MOVE_CAST(Function)(t.function_)), + allocator_(t.allocator_) + { + this->create_promise(allocator_); + } + + allocator_type get_allocator() const ASIO_NOEXCEPT + { + return allocator_; + } + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename... Args> + void operator()(ASIO_MOVE_ARG(Args)... args) + { + (promise_invoke_and_set)(*this->p_, + function_, ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + + void operator()() + { + (promise_invoke_and_set)(*this->p_, function_); + } + +#define ASIO_PRIVATE_CALL_OP_DEF(n) \ + template <ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + (promise_invoke_and_set)(*this->p_, \ + function_, ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CALL_OP_DEF) +#undef ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +private: + Function function_; + Allocator allocator_; +}; + +template <typename Function, + typename Function1, typename Allocator, typename Result> +inline void asio_handler_invoke(Function& f, + packaged_handler<Function1, Allocator, Result>* h) +{ + typename packaged_handler<Function1, Allocator, Result>::executor_type + ex(h->get_executor()); + ex.dispatch(ASIO_MOVE_CAST(Function)(f), std::allocator<void>()); +} + +template <typename Function, + typename Function1, typename Allocator, typename Result> +inline void asio_handler_invoke(const Function& f, + packaged_handler<Function1, Allocator, Result>* h) +{ + typename packaged_handler<Function1, Allocator, Result>::executor_type + ex(h->get_executor()); + ex.dispatch(f, std::allocator<void>()); +} + +// Helper base class for async_result specialisation. +template <typename Function, typename Allocator, typename Result> +class packaged_async_result +{ +public: + typedef packaged_handler<Function, Allocator, Result> completion_handler_type; + typedef typename completion_handler_type::future_type return_type; + + explicit packaged_async_result(completion_handler_type& h) + : future_(h.get_future()) + { + } + + return_type get() + { + return ASIO_MOVE_CAST(return_type)(future_); + } + +private: + return_type future_; +}; + +} // namespace detail + +template <typename Allocator> template <typename Function> +inline detail::packaged_token<typename decay<Function>::type, Allocator> +use_future_t<Allocator>::operator()(ASIO_MOVE_ARG(Function) f) const +{ + return detail::packaged_token<typename decay<Function>::type, Allocator>( + ASIO_MOVE_CAST(Function)(f), allocator_); +} + +#if !defined(GENERATING_DOCUMENTATION) + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename Allocator, typename Result, typename... Args> +class async_result<use_future_t<Allocator>, Result(Args...)> + : public detail::promise_async_result< + void(typename decay<Args>::type...), Allocator> +{ +public: + explicit async_result( + typename detail::promise_async_result<void(typename decay<Args>::type...), + Allocator>::completion_handler_type& h) + : detail::promise_async_result< + void(typename decay<Args>::type...), Allocator>(h) + { + } +}; + +template <typename Function, typename Allocator, + typename Result, typename... Args> +class async_result<detail::packaged_token<Function, Allocator>, Result(Args...)> + : public detail::packaged_async_result<Function, Allocator, + typename result_of<Function(Args...)>::type> +{ +public: + explicit async_result( + typename detail::packaged_async_result<Function, Allocator, + typename result_of<Function(Args...)>::type>::completion_handler_type& h) + : detail::packaged_async_result<Function, Allocator, + typename result_of<Function(Args...)>::type>(h) + { + } +}; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename Allocator, typename Result> +class async_result<use_future_t<Allocator>, Result()> + : public detail::promise_async_result<void(), Allocator> +{ +public: + explicit async_result( + typename detail::promise_async_result< + void(), Allocator>::completion_handler_type& h) + : detail::promise_async_result<void(), Allocator>(h) + { + } +}; + +template <typename Function, typename Allocator, typename Result> +class async_result<detail::packaged_token<Function, Allocator>, Result()> + : public detail::packaged_async_result<Function, Allocator, + typename result_of<Function()>::type> +{ +public: + explicit async_result( + typename detail::packaged_async_result<Function, Allocator, + typename result_of<Function()>::type>::completion_handler_type& h) + : detail::packaged_async_result<Function, Allocator, + typename result_of<Function()>::type>(h) + { + } +}; + +#define ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \ + template <typename Allocator, \ + typename Result, ASIO_VARIADIC_TPARAMS(n)> \ + class async_result<use_future_t<Allocator>, \ + Result(ASIO_VARIADIC_TARGS(n))> \ + : public detail::promise_async_result< \ + void(ASIO_VARIADIC_DECAY(n)), Allocator> \ + { \ + public: \ + explicit async_result( \ + typename detail::promise_async_result< \ + void(ASIO_VARIADIC_DECAY(n)), \ + Allocator>::completion_handler_type& h) \ + : detail::promise_async_result< \ + void(ASIO_VARIADIC_DECAY(n)), Allocator>(h) \ + { \ + } \ + }; \ + \ + template <typename Function, typename Allocator, \ + typename Result, ASIO_VARIADIC_TPARAMS(n)> \ + class async_result<detail::packaged_token<Function, Allocator>, \ + Result(ASIO_VARIADIC_TARGS(n))> \ + : public detail::packaged_async_result<Function, Allocator, \ + typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type> \ + { \ + public: \ + explicit async_result( \ + typename detail::packaged_async_result<Function, Allocator, \ + typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type \ + >::completion_handler_type& h) \ + : detail::packaged_async_result<Function, Allocator, \ + typename result_of<Function(ASIO_VARIADIC_TARGS(n))>::type>(h) \ + { \ + } \ + }; \ + /**/ + ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_RESULT_DEF) +#undef ASIO_PRIVATE_ASYNC_RESULT_DEF + +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +#if !defined(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(ASIO_NO_DEPRECATED) + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_USE_FUTURE_HPP diff --git a/lib/asio/impl/write.hpp b/lib/asio/impl/write.hpp new file mode 100644 index 0000000..d07e8d3 --- /dev/null +++ b/lib/asio/impl/write.hpp @@ -0,0 +1,674 @@ +// +// impl/write.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_WRITE_HPP +#define ASIO_IMPL_WRITE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" +#include "asio/detail/array_fwd.hpp" +#include "asio/detail/base_from_completion_cond.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/consuming_buffers.hpp" +#include "asio/detail/dependent_type.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +namespace detail +{ + template <typename SyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition> + std::size_t write_buffer_sequence(SyncWriteStream& s, + const ConstBufferSequence& buffers, const ConstBufferIterator&, + CompletionCondition completion_condition, asio::error_code& ec) + { + ec = asio::error_code(); + asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + tmp.consume(s.write_some(tmp.prepare(max_size), ec)); + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + +template <typename SyncWriteStream, typename ConstBufferSequence, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) +{ + return detail::write_buffer_sequence(s, buffers, + asio::buffer_sequence_begin(buffers), completion_condition, ec); +} + +template <typename SyncWriteStream, typename ConstBufferSequence> +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec); + asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename ConstBufferSequence> +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + asio::error_code& ec, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) +{ + return write(s, buffers, transfer_all(), ec); +} + +template <typename SyncWriteStream, typename ConstBufferSequence, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, buffers, completion_condition, ec); + asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename DynamicBuffer, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, asio::error_code& ec, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + >::type*) +{ + typename decay<DynamicBuffer>::type b( + ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + + std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec); + b.consume(bytes_transferred); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename DynamicBuffer> +inline std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, + ASIO_MOVE_CAST(DynamicBuffer)(buffers), + transfer_all(), ec); + asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +template <typename SyncWriteStream, typename DynamicBuffer> +inline std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + asio::error_code& ec, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + >::type*) +{ + return write(s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), + transfer_all(), ec); +} + +template <typename SyncWriteStream, typename DynamicBuffer, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + >::type*) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, + ASIO_MOVE_CAST(DynamicBuffer)(buffers), + completion_condition, ec); + asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_IOSTREAM) + +template <typename SyncWriteStream, typename Allocator, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, asio::error_code& ec) +{ + return write(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); +} + +template <typename SyncWriteStream, typename Allocator> +inline std::size_t write(SyncWriteStream& s, + asio::basic_streambuf<Allocator>& b) +{ + return write(s, basic_streambuf_ref<Allocator>(b)); +} + +template <typename SyncWriteStream, typename Allocator> +inline std::size_t write(SyncWriteStream& s, + asio::basic_streambuf<Allocator>& b, + asio::error_code& ec) +{ + return write(s, basic_streambuf_ref<Allocator>(b), ec); +} + +template <typename SyncWriteStream, typename Allocator, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition) +{ + return write(s, basic_streambuf_ref<Allocator>(b), completion_condition); +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) + +namespace detail +{ + template <typename AsyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler> + class write_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, WriteHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffers_(buffers), + start_(0), + handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + write_op(const write_op& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + handler_(other.handler_) + { + } + + write_op(write_op&& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do + { + stream_.async_write_some(buffers_.prepare(max_size), + ASIO_MOVE_CAST(write_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + if ((!ec && bytes_transferred == 0) || buffers_.empty()) + break; + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); + + handler_(ec, buffers_.total_consumed()); + } + } + + //private: + AsyncWriteStream& stream_; + asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> buffers_; + int start_; + WriteHandler handler_; + }; + + template <typename AsyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, + CompletionCondition, WriteHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, + CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler> + inline bool asio_handler_is_continuation( + write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, + CompletionCondition, WriteHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncWriteStream, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> + inline void asio_handler_invoke(Function& function, + write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, + CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncWriteStream, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, + CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename AsyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler> + inline void start_write_buffer_sequence_op(AsyncWriteStream& stream, + const ConstBufferSequence& buffers, const ConstBufferIterator&, + CompletionCondition completion_condition, WriteHandler& handler) + { + detail::write_op<AsyncWriteStream, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>( + stream, buffers, completion_condition, handler)( + asio::error_code(), 0, 1); + } + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::write_op<AsyncWriteStream, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>, + Allocator> +{ + typedef typename associated_allocator<WriteHandler, Allocator>::type type; + + static type get( + const detail::write_op<AsyncWriteStream, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler, typename Executor> +struct associated_executor< + detail::write_op<AsyncWriteStream, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>, + Executor> +{ + typedef typename associated_executor<WriteHandler, Executor>::type type; + + static type get( + const detail::write_op<AsyncWriteStream, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncWriteStream, typename ConstBufferSequence, + typename CompletionCondition, typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + 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. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::start_write_buffer_sequence_op(s, buffers, + asio::buffer_sequence_begin(buffers), completion_condition, + init.completion_handler); + + return init.result.get(); +} + +template <typename AsyncWriteStream, typename ConstBufferSequence, + typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + 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. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::start_write_buffer_sequence_op(s, buffers, + asio::buffer_sequence_begin(buffers), transfer_all(), + init.completion_handler); + + return init.result.get(); +} + +namespace detail +{ + template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler> + class write_dynbuf_op + { + public: + template <typename BufferSequence> + write_dynbuf_op(AsyncWriteStream& stream, + ASIO_MOVE_ARG(BufferSequence) buffers, + CompletionCondition completion_condition, WriteHandler& handler) + : stream_(stream), + buffers_(ASIO_MOVE_CAST(BufferSequence)(buffers)), + completion_condition_( + ASIO_MOVE_CAST(CompletionCondition)(completion_condition)), + handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + write_dynbuf_op(const write_dynbuf_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + completion_condition_(other.completion_condition_), + handler_(other.handler_) + { + } + + write_dynbuf_op(write_dynbuf_op&& other) + : stream_(other.stream_), + buffers_(ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + completion_condition_( + ASIO_MOVE_CAST(CompletionCondition)( + other.completion_condition_)), + handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + switch (start) + { + case 1: + async_write(stream_, buffers_.data(), completion_condition_, + ASIO_MOVE_CAST(write_dynbuf_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + handler_(ec, static_cast<const std::size_t&>(bytes_transferred)); + } + } + + //private: + AsyncWriteStream& stream_; + DynamicBuffer buffers_; + CompletionCondition completion_condition_; + WriteHandler handler_; + }; + + template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + CompletionCondition, WriteHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler> + inline bool asio_handler_is_continuation( + write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + CompletionCondition, WriteHandler>* this_handler) + { + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncWriteStream, + typename DynamicBuffer, typename CompletionCondition, + typename WriteHandler> + inline void asio_handler_invoke(Function& function, + write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncWriteStream, + typename DynamicBuffer, typename CompletionCondition, + typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::write_dynbuf_op<AsyncWriteStream, + DynamicBuffer, 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 Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler, typename Executor> +struct associated_executor< + detail::write_dynbuf_op<AsyncWriteStream, + DynamicBuffer, 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 Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncWriteStream, + typename DynamicBuffer, typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::type>::value + >::type*) +{ + return async_write(s, + ASIO_MOVE_CAST(DynamicBuffer)(buffers), + transfer_all(), ASIO_MOVE_CAST(WriteHandler)(handler)); +} + +template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, + ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer<typename decay<DynamicBuffer>::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. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::write_dynbuf_op<AsyncWriteStream, + typename decay<DynamicBuffer>::type, + CompletionCondition, ASIO_HANDLER_TYPE( + WriteHandler, void (asio::error_code, std::size_t))>( + s, ASIO_MOVE_CAST(DynamicBuffer)(buffers), + completion_condition, init.completion_handler)( + asio::error_code(), 0, 1); + + return init.result.get(); +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_IOSTREAM) + +template <typename AsyncWriteStream, typename Allocator, typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + asio::basic_streambuf<Allocator>& b, + ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_write(s, basic_streambuf_ref<Allocator>(b), + ASIO_MOVE_CAST(WriteHandler)(handler)); +} + +template <typename AsyncWriteStream, typename Allocator, + typename CompletionCondition, typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, + ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_write(s, basic_streambuf_ref<Allocator>(b), + completion_condition, ASIO_MOVE_CAST(WriteHandler)(handler)); +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_WRITE_HPP diff --git a/lib/asio/impl/write_at.hpp b/lib/asio/impl/write_at.hpp new file mode 100644 index 0000000..cc6f336 --- /dev/null +++ b/lib/asio/impl/write_at.hpp @@ -0,0 +1,572 @@ +// +// impl/write_at.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the 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 ASIO_IMPL_WRITE_AT_HPP +#define ASIO_IMPL_WRITE_AT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" +#include "asio/detail/array_fwd.hpp" +#include "asio/detail/base_from_completion_cond.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/consuming_buffers.hpp" +#include "asio/detail/dependent_type.hpp" +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_cont_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_type_requirements.hpp" +#include "asio/detail/throw_error.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +namespace detail +{ + template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition> + std::size_t write_at_buffer_sequence(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + const ConstBufferIterator&, CompletionCondition completion_condition, + asio::error_code& ec) + { + ec = asio::error_code(); + asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + { + tmp.consume(d.write_some_at(offset + tmp.total_consumed(), + tmp.prepare(max_size), ec)); + } + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + +template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename CompletionCondition> +std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec) +{ + return detail::write_at_buffer_sequence(d, offset, buffers, + asio::buffer_sequence_begin(buffers), completion_condition, ec); +} + +template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence> +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers) +{ + asio::error_code ec; + std::size_t bytes_transferred = write_at( + d, offset, buffers, transfer_all(), ec); + asio::detail::throw_error(ec, "write_at"); + return bytes_transferred; +} + +template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence> +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + asio::error_code& ec) +{ + return write_at(d, offset, buffers, transfer_all(), ec); +} + +template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename CompletionCondition> +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = write_at( + d, offset, buffers, completion_condition, ec); + asio::detail::throw_error(ec, "write_at"); + return bytes_transferred; +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_IOSTREAM) + +template <typename SyncRandomAccessWriteDevice, typename Allocator, + typename CompletionCondition> +std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, asio::error_code& ec) +{ + std::size_t bytes_transferred = write_at( + d, offset, b.data(), completion_condition, ec); + b.consume(bytes_transferred); + return bytes_transferred; +} + +template <typename SyncRandomAccessWriteDevice, typename Allocator> +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b) +{ + asio::error_code ec; + std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec); + asio::detail::throw_error(ec, "write_at"); + return bytes_transferred; +} + +template <typename SyncRandomAccessWriteDevice, typename Allocator> +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b, + asio::error_code& ec) +{ + return write_at(d, offset, b, transfer_all(), ec); +} + +template <typename SyncRandomAccessWriteDevice, typename Allocator, + typename CompletionCondition> +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = write_at( + d, offset, b, completion_condition, ec); + asio::detail::throw_error(ec, "write_at"); + return bytes_transferred; +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) + +namespace detail +{ + template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> + class write_at_op + : detail::base_from_completion_cond<CompletionCondition> + { + public: + write_at_op(AsyncRandomAccessWriteDevice& device, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, WriteHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffers_(buffers), + start_(0), + handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + write_at_op(const write_at_op& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + device_(other.device_), + offset_(other.offset_), + buffers_(other.buffers_), + start_(other.start_), + handler_(other.handler_) + { + } + + write_at_op(write_at_op&& other) + : detail::base_from_completion_cond<CompletionCondition>(other), + device_(other.device_), + offset_(other.offset_), + buffers_(other.buffers_), + start_(other.start_), + handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do + { + device_.async_write_some_at( + offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), + ASIO_MOVE_CAST(write_at_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + if ((!ec && bytes_transferred == 0) || buffers_.empty()) + break; + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); + + handler_(ec, buffers_.total_consumed()); + } + } + + //private: + AsyncRandomAccessWriteDevice& device_; + uint64_t offset_; + asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> buffers_; + int start_; + WriteHandler handler_; + }; + + template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> + inline bool asio_handler_is_continuation( + write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) + { + return this_handler->start_ == 0 ? true + : asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> + inline void asio_handler_invoke(Function& function, + write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + 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, + WriteHandler& handler) + { + detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>( + d, offset, buffers, completion_condition, handler)( + asio::error_code(), 0, 1); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>, + Allocator> +{ + typedef typename associated_allocator<WriteHandler, Allocator>::type type; + + static type get( + const detail::write_at_op<AsyncRandomAccessWriteDevice, + ConstBufferSequence, ConstBufferIterator, + CompletionCondition, WriteHandler>& h, + const Allocator& a = Allocator()) ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler, typename Executor> +struct associated_executor< + detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>, + Executor> +{ + typedef typename associated_executor<WriteHandler, Executor>::type type; + + static type get( + const detail::write_at_op<AsyncRandomAccessWriteDevice, + ConstBufferSequence, ConstBufferIterator, + CompletionCondition, WriteHandler>& h, + const Executor& ex = Executor()) ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename CompletionCondition, typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, + 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. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::start_write_at_buffer_sequence_op(d, offset, buffers, + asio::buffer_sequence_begin(buffers), completion_condition, + init.completion_handler); + + return init.result.get(); +} + +template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + 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. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + detail::start_write_at_buffer_sequence_op(d, offset, buffers, + asio::buffer_sequence_begin(buffers), transfer_all(), + init.completion_handler); + + return init.result.get(); +} + +#if !defined(ASIO_NO_EXTENSIONS) +#if !defined(ASIO_NO_IOSTREAM) + +namespace detail +{ + template <typename Allocator, typename WriteHandler> + class write_at_streambuf_op + { + public: + write_at_streambuf_op( + asio::basic_streambuf<Allocator>& streambuf, + WriteHandler& handler) + : streambuf_(streambuf), + handler_(ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(ASIO_HAS_MOVE) + write_at_streambuf_op(const write_at_streambuf_op& other) + : streambuf_(other.streambuf_), + handler_(other.handler_) + { + } + + write_at_streambuf_op(write_at_streambuf_op&& other) + : streambuf_(other.streambuf_), + handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + void operator()(const asio::error_code& ec, + const std::size_t bytes_transferred) + { + streambuf_.consume(bytes_transferred); + handler_(ec, bytes_transferred); + } + + //private: + asio::basic_streambuf<Allocator>& streambuf_; + WriteHandler handler_; + }; + + template <typename Allocator, typename WriteHandler> + inline void* asio_handler_allocate(std::size_t size, + write_at_streambuf_op<Allocator, WriteHandler>* this_handler) + { + return asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename Allocator, typename WriteHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_at_streambuf_op<Allocator, WriteHandler>* this_handler) + { + asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Allocator, typename WriteHandler> + inline bool asio_handler_is_continuation( + write_at_streambuf_op<Allocator, WriteHandler>* this_handler) + { + return asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename Allocator, typename WriteHandler> + inline void asio_handler_invoke(Function& function, + write_at_streambuf_op<Allocator, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename Allocator, typename WriteHandler> + inline void asio_handler_invoke(const Function& function, + write_at_streambuf_op<Allocator, WriteHandler>* this_handler) + { + asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Allocator, typename WriteHandler> + inline write_at_streambuf_op<Allocator, WriteHandler> + make_write_at_streambuf_op( + asio::basic_streambuf<Allocator>& b, WriteHandler handler) + { + return write_at_streambuf_op<Allocator, WriteHandler>(b, handler); + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Allocator, typename WriteHandler, typename Allocator1> +struct associated_allocator< + detail::write_at_streambuf_op<Allocator, WriteHandler>, + Allocator1> +{ + typedef typename associated_allocator<WriteHandler, Allocator1>::type type; + + static type get( + const detail::write_at_streambuf_op<Allocator, WriteHandler>& h, + const Allocator1& a = Allocator1()) ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator1>::get(h.handler_, a); + } +}; + +template <typename Executor, typename WriteHandler, typename Executor1> +struct associated_executor< + detail::write_at_streambuf_op<Executor, WriteHandler>, + Executor1> +{ + typedef typename associated_executor<WriteHandler, Executor1>::type type; + + static type get( + const detail::write_at_streambuf_op<Executor, WriteHandler>& h, + const Executor1& ex = Executor1()) ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor1>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncRandomAccessWriteDevice, typename Allocator, + typename CompletionCondition, typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, + 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. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + async_write_at(d, offset, b.data(), completion_condition, + detail::write_at_streambuf_op<Allocator, ASIO_HANDLER_TYPE( + WriteHandler, void (asio::error_code, std::size_t))>( + b, init.completion_handler)); + + return init.result.get(); +} + +template <typename AsyncRandomAccessWriteDevice, typename Allocator, + typename WriteHandler> +inline ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (asio::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, asio::basic_streambuf<Allocator>& b, + 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. + ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (asio::error_code, std::size_t)> init(handler); + + async_write_at(d, offset, b.data(), transfer_all(), + detail::write_at_streambuf_op<Allocator, ASIO_HANDLER_TYPE( + WriteHandler, void (asio::error_code, std::size_t))>( + b, init.completion_handler)); + + return init.result.get(); +} + +#endif // !defined(ASIO_NO_IOSTREAM) +#endif // !defined(ASIO_NO_EXTENSIONS) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IMPL_WRITE_AT_HPP |