// // detail/consuming_buffers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2022 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 #include "asio/buffer.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/limits.hpp" #include "asio/registered_buffer.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Helper template to determine the maximum number of prepared buffers. template struct prepared_buffers_max { enum { value = buffer_sequence_adapter_base::max_buffers }; }; template struct prepared_buffers_max > { enum { value = N }; }; #if defined(ASIO_HAS_STD_ARRAY) template struct prepared_buffers_max > { enum { value = N }; }; #endif // defined(ASIO_HAS_STD_ARRAY) // A buffer sequence used to represent a subsequence of the buffers. template 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 class consuming_buffers { public: typedef prepared_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 class consuming_single_buffer { public: // Construct to represent the entire list of buffers. template 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 : public consuming_single_buffer { public: explicit consuming_buffers(const mutable_buffer& buffer) : consuming_single_buffer(buffer) { } }; template <> class consuming_buffers : public consuming_single_buffer { public: explicit consuming_buffers(const mutable_buffer& buffer) : consuming_single_buffer(buffer) { } }; template <> class consuming_buffers : public consuming_single_buffer { public: explicit consuming_buffers(const const_buffer& buffer) : consuming_single_buffer(buffer) { } }; #if !defined(ASIO_NO_DEPRECATED) template <> class consuming_buffers : public consuming_single_buffer { public: explicit consuming_buffers(const mutable_buffers_1& buffer) : consuming_single_buffer(buffer) { } }; template <> class consuming_buffers : public consuming_single_buffer { public: explicit consuming_buffers(const mutable_buffers_1& buffer) : consuming_single_buffer(buffer) { } }; template <> class consuming_buffers : public consuming_single_buffer { public: explicit consuming_buffers(const const_buffers_1& buffer) : consuming_single_buffer(buffer) { } }; #endif // !defined(ASIO_NO_DEPRECATED) template <> class consuming_buffers : public consuming_single_buffer { public: explicit consuming_buffers(const mutable_registered_buffer& buffer) : consuming_single_buffer(buffer) { } }; template <> class consuming_buffers : public consuming_single_buffer { public: explicit consuming_buffers(const mutable_registered_buffer& buffer) : consuming_single_buffer(buffer) { } }; template <> class consuming_buffers : public consuming_single_buffer { public: explicit consuming_buffers(const const_registered_buffer& buffer) : consuming_single_buffer(buffer) { } }; template class consuming_buffers, typename boost::array::const_iterator> { public: // Construct to represent the entire list of buffers. explicit consuming_buffers(const boost::array& 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 prepare(std::size_t max_size) { boost::array 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 buffers_; std::size_t total_consumed_; }; #if defined(ASIO_HAS_STD_ARRAY) template class consuming_buffers, typename std::array::const_iterator> { public: // Construct to represent the entire list of buffers. explicit consuming_buffers(const std::array& 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 prepare(std::size_t max_size) { std::array 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 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 class consuming_buffers : 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