452 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			452 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | //
 | ||
|  | // detail/consuming_buffers.hpp
 | ||
|  | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | ||
|  | //
 | ||
|  | // Copyright (c) 2003-2023 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/registered_buffer.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 <> | ||
|  | class consuming_buffers<mutable_buffer, | ||
|  |     mutable_registered_buffer, const mutable_buffer*> | ||
|  |   : public consuming_single_buffer<mutable_registered_buffer> | ||
|  | { | ||
|  | public: | ||
|  |   explicit consuming_buffers(const mutable_registered_buffer& buffer) | ||
|  |     : consuming_single_buffer<mutable_registered_buffer>(buffer) | ||
|  |   { | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | template <> | ||
|  | class consuming_buffers<const_buffer, | ||
|  |     mutable_registered_buffer, const mutable_buffer*> | ||
|  |   : public consuming_single_buffer<mutable_registered_buffer> | ||
|  | { | ||
|  | public: | ||
|  |   explicit consuming_buffers(const mutable_registered_buffer& buffer) | ||
|  |     : consuming_single_buffer<mutable_registered_buffer>(buffer) | ||
|  |   { | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | template <> | ||
|  | class consuming_buffers<const_buffer, | ||
|  |     const_registered_buffer, const const_buffer*> | ||
|  |   : public consuming_single_buffer<const_registered_buffer> | ||
|  | { | ||
|  | public: | ||
|  |   explicit consuming_buffers(const const_registered_buffer& buffer) | ||
|  |     : consuming_single_buffer<const_registered_buffer>(buffer) | ||
|  |   { | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | 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
 |