diff options
Diffstat (limited to 'lib/asio/detail/consuming_buffers.hpp')
-rw-r--r-- | lib/asio/detail/consuming_buffers.hpp | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/lib/asio/detail/consuming_buffers.hpp b/lib/asio/detail/consuming_buffers.hpp new file mode 100644 index 0000000..8127ae7 --- /dev/null +++ b/lib/asio/detail/consuming_buffers.hpp @@ -0,0 +1,414 @@ +// +// detail/consuming_buffers.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_DETAIL_CONSUMING_BUFFERS_HPP +#define ASIO_DETAIL_CONSUMING_BUFFERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include <cstddef> +#include "asio/buffer.hpp" +#include "asio/detail/buffer_sequence_adapter.hpp" +#include "asio/detail/limits.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +// Helper template to determine the maximum number of prepared buffers. +template <typename Buffers> +struct prepared_buffers_max +{ + enum { value = buffer_sequence_adapter_base::max_buffers }; +}; + +template <typename Elem, std::size_t N> +struct prepared_buffers_max<boost::array<Elem, N> > +{ + enum { value = N }; +}; + +#if defined(ASIO_HAS_STD_ARRAY) + +template <typename Elem, std::size_t N> +struct prepared_buffers_max<std::array<Elem, N> > +{ + enum { value = N }; +}; + +#endif // defined(ASIO_HAS_STD_ARRAY) + +// A buffer sequence used to represent a subsequence of the buffers. +template <typename Buffer, std::size_t MaxBuffers> +struct prepared_buffers +{ + typedef Buffer value_type; + typedef const Buffer* const_iterator; + + enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 }; + + prepared_buffers() : count(0) {} + const_iterator begin() const { return elems; } + const_iterator end() const { return elems + count; } + + Buffer elems[max_buffers]; + std::size_t count; +}; + +// A proxy for a sub-range in a list of buffers. +template <typename Buffer, typename Buffers, typename Buffer_Iterator> +class consuming_buffers +{ +public: + typedef prepared_buffers<Buffer, prepared_buffers_max<Buffers>::value> + prepared_buffers_type; + + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const Buffers& buffers) + : buffers_(buffers), + total_consumed_(0), + next_elem_(0), + next_elem_offset_(0) + { + using asio::buffer_size; + total_size_ = buffer_size(buffers); + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= total_size_; + } + + // Get the buffer for a single transfer, with a size. + prepared_buffers_type prepare(std::size_t max_size) + { + prepared_buffers_type result; + + Buffer_Iterator next = asio::buffer_sequence_begin(buffers_); + Buffer_Iterator end = asio::buffer_sequence_end(buffers_); + + std::advance(next, next_elem_); + std::size_t elem_offset = next_elem_offset_; + while (next != end && max_size > 0 && (result.count) < result.max_buffers) + { + Buffer next_buf = Buffer(*next) + elem_offset; + result.elems[result.count] = asio::buffer(next_buf, max_size); + max_size -= result.elems[result.count].size(); + elem_offset = 0; + if (result.elems[result.count].size() > 0) + ++result.count; + ++next; + } + + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + + Buffer_Iterator next = asio::buffer_sequence_begin(buffers_); + Buffer_Iterator end = asio::buffer_sequence_end(buffers_); + + std::advance(next, next_elem_); + while (next != end && size > 0) + { + Buffer next_buf = Buffer(*next) + next_elem_offset_; + if (size < next_buf.size()) + { + next_elem_offset_ += size; + size = 0; + } + else + { + size -= next_buf.size(); + next_elem_offset_ = 0; + ++next_elem_; + ++next; + } + } + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + Buffers buffers_; + std::size_t total_size_; + std::size_t total_consumed_; + std::size_t next_elem_; + std::size_t next_elem_offset_; +}; + +// Base class of all consuming_buffers specialisations for single buffers. +template <typename Buffer> +class consuming_single_buffer +{ +public: + // Construct to represent the entire list of buffers. + template <typename Buffer1> + explicit consuming_single_buffer(const Buffer1& buffer) + : buffer_(buffer), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= buffer_.size(); + } + + // Get the buffer for a single transfer, with a size. + Buffer prepare(std::size_t max_size) + { + return asio::buffer(buffer_ + total_consumed_, max_size); + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + Buffer buffer_; + std::size_t total_consumed_; +}; + +template <> +class consuming_buffers<mutable_buffer, mutable_buffer, const mutable_buffer*> + : public consuming_single_buffer<ASIO_MUTABLE_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffer& buffer) + : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer) + { + } +}; + +template <> +class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*> + : public consuming_single_buffer<ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffer& buffer) + : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) + { + } +}; + +template <> +class consuming_buffers<const_buffer, const_buffer, const const_buffer*> + : public consuming_single_buffer<ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const const_buffer& buffer) + : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) + { + } +}; + +#if !defined(ASIO_NO_DEPRECATED) + +template <> +class consuming_buffers<mutable_buffer, + mutable_buffers_1, const mutable_buffer*> + : public consuming_single_buffer<ASIO_MUTABLE_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffers_1& buffer) + : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer) + { + } +}; + +template <> +class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*> + : public consuming_single_buffer<ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffers_1& buffer) + : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) + { + } +}; + +template <> +class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*> + : public consuming_single_buffer<ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const const_buffers_1& buffer) + : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer) + { + } +}; + +#endif // !defined(ASIO_NO_DEPRECATED) + +template <typename Buffer, typename Elem> +class consuming_buffers<Buffer, boost::array<Elem, 2>, + typename boost::array<Elem, 2>::const_iterator> +{ +public: + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const boost::array<Elem, 2>& buffers) + : buffers_(buffers), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= + Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); + } + + // Get the buffer for a single transfer, with a size. + boost::array<Buffer, 2> prepare(std::size_t max_size) + { + boost::array<Buffer, 2> result = {{ + Buffer(buffers_[0]), Buffer(buffers_[1]) }}; + std::size_t buffer0_size = result[0].size(); + result[0] = asio::buffer(result[0] + total_consumed_, max_size); + result[1] = asio::buffer( + result[1] + (total_consumed_ < buffer0_size + ? 0 : total_consumed_ - buffer0_size), + max_size - result[0].size()); + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + boost::array<Elem, 2> buffers_; + std::size_t total_consumed_; +}; + +#if defined(ASIO_HAS_STD_ARRAY) + +template <typename Buffer, typename Elem> +class consuming_buffers<Buffer, std::array<Elem, 2>, + typename std::array<Elem, 2>::const_iterator> +{ +public: + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const std::array<Elem, 2>& buffers) + : buffers_(buffers), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= + Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); + } + + // Get the buffer for a single transfer, with a size. + std::array<Buffer, 2> prepare(std::size_t max_size) + { + std::array<Buffer, 2> result = {{ + Buffer(buffers_[0]), Buffer(buffers_[1]) }}; + std::size_t buffer0_size = result[0].size(); + result[0] = asio::buffer(result[0] + total_consumed_, max_size); + result[1] = asio::buffer( + result[1] + (total_consumed_ < buffer0_size + ? 0 : total_consumed_ - buffer0_size), + max_size - result[0].size()); + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + std::array<Elem, 2> buffers_; + std::size_t total_consumed_; +}; + +#endif // defined(ASIO_HAS_STD_ARRAY) + +// Specialisation for null_buffers to ensure that the null_buffers type is +// always passed through to the underlying read or write operation. +template <typename Buffer> +class consuming_buffers<Buffer, null_buffers, const mutable_buffer*> + : public asio::null_buffers +{ +public: + consuming_buffers(const null_buffers&) + { + // No-op. + } + + bool empty() + { + return false; + } + + null_buffers prepare(std::size_t) + { + return null_buffers(); + } + + void consume(std::size_t) + { + // No-op. + } + + std::size_t total_consumed() const + { + return 0; + } +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP |