Chris@16: // Chris@16: // detail/consuming_buffers.hpp Chris@16: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Chris@16: // Chris@101: // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: Chris@16: #ifndef BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP Chris@16: #define BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: # pragma once Chris@16: #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace asio { Chris@16: namespace detail { Chris@16: Chris@16: // A proxy iterator for a sub-range in a list of buffers. Chris@16: template Chris@16: class consuming_buffers_iterator Chris@16: { Chris@16: public: Chris@16: /// The type used for the distance between two iterators. Chris@16: typedef std::ptrdiff_t difference_type; Chris@16: Chris@16: /// The type of the value pointed to by the iterator. Chris@16: typedef Buffer value_type; Chris@16: Chris@16: /// The type of the result of applying operator->() to the iterator. Chris@16: typedef const Buffer* pointer; Chris@16: Chris@16: /// The type of the result of applying operator*() to the iterator. Chris@16: typedef const Buffer& reference; Chris@16: Chris@16: /// The iterator category. Chris@16: typedef std::forward_iterator_tag iterator_category; Chris@16: Chris@16: // Default constructor creates an end iterator. Chris@16: consuming_buffers_iterator() Chris@16: : at_end_(true) Chris@16: { Chris@16: } Chris@16: Chris@16: // Construct with a buffer for the first entry and an iterator Chris@16: // range for the remaining entries. Chris@16: consuming_buffers_iterator(bool at_end, const Buffer& first, Chris@16: Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder, Chris@16: std::size_t max_size) Chris@16: : at_end_(max_size > 0 ? at_end : true), Chris@16: first_(buffer(first, max_size)), Chris@16: begin_remainder_(begin_remainder), Chris@16: end_remainder_(end_remainder), Chris@16: offset_(0), Chris@16: max_size_(max_size) Chris@16: { Chris@16: } Chris@16: Chris@16: // Dereference an iterator. Chris@16: const Buffer& operator*() const Chris@16: { Chris@16: return dereference(); Chris@16: } Chris@16: Chris@16: // Dereference an iterator. Chris@16: const Buffer* operator->() const Chris@16: { Chris@16: return &dereference(); Chris@16: } Chris@16: Chris@16: // Increment operator (prefix). Chris@16: consuming_buffers_iterator& operator++() Chris@16: { Chris@16: increment(); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // Increment operator (postfix). Chris@16: consuming_buffers_iterator operator++(int) Chris@16: { Chris@16: consuming_buffers_iterator tmp(*this); Chris@16: ++*this; Chris@16: return tmp; Chris@16: } Chris@16: Chris@16: // Test two iterators for equality. Chris@16: friend bool operator==(const consuming_buffers_iterator& a, Chris@16: const consuming_buffers_iterator& b) Chris@16: { Chris@16: return a.equal(b); Chris@16: } Chris@16: Chris@16: // Test two iterators for inequality. Chris@16: friend bool operator!=(const consuming_buffers_iterator& a, Chris@16: const consuming_buffers_iterator& b) Chris@16: { Chris@16: return !a.equal(b); Chris@16: } Chris@16: Chris@16: private: Chris@16: void increment() Chris@16: { Chris@16: if (!at_end_) Chris@16: { Chris@16: if (begin_remainder_ == end_remainder_ Chris@16: || offset_ + buffer_size(first_) >= max_size_) Chris@16: { Chris@16: at_end_ = true; Chris@16: } Chris@16: else Chris@16: { Chris@16: offset_ += buffer_size(first_); Chris@16: first_ = buffer(*begin_remainder_++, max_size_ - offset_); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: bool equal(const consuming_buffers_iterator& other) const Chris@16: { Chris@16: if (at_end_ && other.at_end_) Chris@16: return true; Chris@16: return !at_end_ && !other.at_end_ Chris@16: && buffer_cast(first_) Chris@16: == buffer_cast(other.first_) Chris@16: && buffer_size(first_) == buffer_size(other.first_) Chris@16: && begin_remainder_ == other.begin_remainder_ Chris@16: && end_remainder_ == other.end_remainder_; Chris@16: } Chris@16: Chris@16: const Buffer& dereference() const Chris@16: { Chris@16: return first_; Chris@16: } Chris@16: Chris@16: bool at_end_; Chris@16: Buffer first_; Chris@16: Buffer_Iterator begin_remainder_; Chris@16: Buffer_Iterator end_remainder_; Chris@16: std::size_t offset_; Chris@16: std::size_t max_size_; Chris@16: }; Chris@16: Chris@16: // A proxy for a sub-range in a list of buffers. Chris@16: template Chris@16: class consuming_buffers Chris@16: { Chris@16: public: Chris@16: // The type for each element in the list of buffers. Chris@16: typedef Buffer value_type; Chris@16: Chris@16: // A forward-only iterator type that may be used to read elements. Chris@16: typedef consuming_buffers_iterator Chris@16: const_iterator; Chris@16: Chris@16: // Construct to represent the entire list of buffers. Chris@16: consuming_buffers(const Buffers& buffers) Chris@16: : buffers_(buffers), Chris@16: at_end_(buffers_.begin() == buffers_.end()), Chris@16: begin_remainder_(buffers_.begin()), Chris@16: max_size_((std::numeric_limits::max)()) Chris@16: { Chris@16: if (!at_end_) Chris@16: { Chris@16: first_ = *buffers_.begin(); Chris@16: ++begin_remainder_; Chris@16: } Chris@16: } Chris@16: Chris@16: // Copy constructor. Chris@16: consuming_buffers(const consuming_buffers& other) Chris@16: : buffers_(other.buffers_), Chris@16: at_end_(other.at_end_), Chris@16: first_(other.first_), Chris@16: begin_remainder_(buffers_.begin()), Chris@16: max_size_(other.max_size_) Chris@16: { Chris@16: typename Buffers::const_iterator first = other.buffers_.begin(); Chris@16: typename Buffers::const_iterator second = other.begin_remainder_; Chris@16: std::advance(begin_remainder_, std::distance(first, second)); Chris@16: } Chris@16: Chris@16: // Assignment operator. Chris@16: consuming_buffers& operator=(const consuming_buffers& other) Chris@16: { Chris@16: buffers_ = other.buffers_; Chris@16: at_end_ = other.at_end_; Chris@16: first_ = other.first_; Chris@16: begin_remainder_ = buffers_.begin(); Chris@16: typename Buffers::const_iterator first = other.buffers_.begin(); Chris@16: typename Buffers::const_iterator second = other.begin_remainder_; Chris@16: std::advance(begin_remainder_, std::distance(first, second)); Chris@16: max_size_ = other.max_size_; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // Get a forward-only iterator to the first element. Chris@16: const_iterator begin() const Chris@16: { Chris@16: return const_iterator(at_end_, first_, Chris@16: begin_remainder_, buffers_.end(), max_size_); Chris@16: } Chris@16: Chris@16: // Get a forward-only iterator for one past the last element. Chris@16: const_iterator end() const Chris@16: { Chris@16: return const_iterator(); Chris@16: } Chris@16: Chris@16: // Set the maximum size for a single transfer. Chris@16: void prepare(std::size_t max_size) Chris@16: { Chris@16: max_size_ = max_size; Chris@16: } Chris@16: Chris@16: // Consume the specified number of bytes from the buffers. Chris@16: void consume(std::size_t size) Chris@16: { Chris@16: // Remove buffers from the start until the specified size is reached. Chris@16: while (size > 0 && !at_end_) Chris@16: { Chris@16: if (buffer_size(first_) <= size) Chris@16: { Chris@16: size -= buffer_size(first_); Chris@16: if (begin_remainder_ == buffers_.end()) Chris@16: at_end_ = true; Chris@16: else Chris@16: first_ = *begin_remainder_++; Chris@16: } Chris@16: else Chris@16: { Chris@16: first_ = first_ + size; Chris@16: size = 0; Chris@16: } Chris@16: } Chris@16: Chris@16: // Remove any more empty buffers at the start. Chris@16: while (!at_end_ && buffer_size(first_) == 0) Chris@16: { Chris@16: if (begin_remainder_ == buffers_.end()) Chris@16: at_end_ = true; Chris@16: else Chris@16: first_ = *begin_remainder_++; Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: Buffers buffers_; Chris@16: bool at_end_; Chris@16: Buffer first_; Chris@16: typename Buffers::const_iterator begin_remainder_; Chris@16: std::size_t max_size_; Chris@16: }; Chris@16: Chris@16: // Specialisation for null_buffers to ensure that the null_buffers type is Chris@16: // always passed through to the underlying read or write operation. Chris@16: template Chris@16: class consuming_buffers Chris@16: : public boost::asio::null_buffers Chris@16: { Chris@16: public: Chris@16: consuming_buffers(const boost::asio::null_buffers&) Chris@16: { Chris@16: // No-op. Chris@16: } Chris@16: Chris@16: void prepare(std::size_t) Chris@16: { Chris@16: // No-op. Chris@16: } Chris@16: Chris@16: void consume(std::size_t) Chris@16: { Chris@16: // No-op. Chris@16: } Chris@16: }; Chris@16: Chris@16: } // namespace detail Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP