Chris@16: // Chris@16: // buffers_iterator.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_BUFFERS_ITERATOR_HPP Chris@16: #define BOOST_ASIO_BUFFERS_ITERATOR_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: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace asio { Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct buffers_iterator_types_helper; Chris@16: Chris@16: template <> Chris@16: struct buffers_iterator_types_helper Chris@16: { Chris@16: typedef const_buffer buffer_type; Chris@16: template Chris@16: struct byte_type Chris@16: { Chris@16: typedef typename add_const::type type; Chris@16: }; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct buffers_iterator_types_helper Chris@16: { Chris@16: typedef mutable_buffer buffer_type; Chris@16: template Chris@16: struct byte_type Chris@16: { Chris@16: typedef ByteType type; Chris@16: }; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct buffers_iterator_types Chris@16: { Chris@16: enum Chris@16: { Chris@16: is_mutable = is_convertible< Chris@16: typename BufferSequence::value_type, Chris@16: mutable_buffer>::value Chris@16: }; Chris@16: typedef buffers_iterator_types_helper helper; Chris@16: typedef typename helper::buffer_type buffer_type; Chris@16: typedef typename helper::template byte_type::type byte_type; Chris@16: }; Chris@16: } Chris@16: Chris@16: /// A random access iterator over the bytes in a buffer sequence. Chris@16: template Chris@16: class buffers_iterator Chris@16: { Chris@16: private: Chris@16: typedef typename detail::buffers_iterator_types< Chris@16: BufferSequence, ByteType>::buffer_type buffer_type; 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 ByteType value_type; Chris@16: Chris@16: #if defined(GENERATING_DOCUMENTATION) Chris@16: /// The type of the result of applying operator->() to the iterator. Chris@16: /** Chris@16: * If the buffer sequence stores buffer objects that are convertible to Chris@16: * mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a Chris@16: * pointer to a const ByteType. Chris@16: */ Chris@16: typedef const_or_non_const_ByteType* pointer; Chris@16: #else // defined(GENERATING_DOCUMENTATION) Chris@16: typedef typename detail::buffers_iterator_types< Chris@16: BufferSequence, ByteType>::byte_type* pointer; Chris@16: #endif // defined(GENERATING_DOCUMENTATION) Chris@16: Chris@16: #if defined(GENERATING_DOCUMENTATION) Chris@16: /// The type of the result of applying operator*() to the iterator. Chris@16: /** Chris@16: * If the buffer sequence stores buffer objects that are convertible to Chris@16: * mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a Chris@16: * reference to a const ByteType. Chris@16: */ Chris@16: typedef const_or_non_const_ByteType& reference; Chris@16: #else // defined(GENERATING_DOCUMENTATION) Chris@16: typedef typename detail::buffers_iterator_types< Chris@16: BufferSequence, ByteType>::byte_type& reference; Chris@16: #endif // defined(GENERATING_DOCUMENTATION) Chris@16: Chris@16: /// The iterator category. Chris@16: typedef std::random_access_iterator_tag iterator_category; Chris@16: Chris@16: /// Default constructor. Creates an iterator in an undefined state. Chris@16: buffers_iterator() Chris@16: : current_buffer_(), Chris@16: current_buffer_position_(0), Chris@16: begin_(), Chris@16: current_(), Chris@16: end_(), Chris@16: position_(0) Chris@16: { Chris@16: } Chris@16: Chris@16: /// Construct an iterator representing the beginning of the buffers' data. Chris@16: static buffers_iterator begin(const BufferSequence& buffers) Chris@16: #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) Chris@16: __attribute__ ((__noinline__)) Chris@16: #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) Chris@16: { Chris@16: buffers_iterator new_iter; Chris@16: new_iter.begin_ = buffers.begin(); Chris@16: new_iter.current_ = buffers.begin(); Chris@16: new_iter.end_ = buffers.end(); Chris@16: while (new_iter.current_ != new_iter.end_) Chris@16: { Chris@16: new_iter.current_buffer_ = *new_iter.current_; Chris@16: if (boost::asio::buffer_size(new_iter.current_buffer_) > 0) Chris@16: break; Chris@16: ++new_iter.current_; Chris@16: } Chris@16: return new_iter; Chris@16: } Chris@16: Chris@16: /// Construct an iterator representing the end of the buffers' data. Chris@16: static buffers_iterator end(const BufferSequence& buffers) Chris@16: #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) Chris@16: __attribute__ ((__noinline__)) Chris@16: #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) Chris@16: { Chris@16: buffers_iterator new_iter; Chris@16: new_iter.begin_ = buffers.begin(); Chris@16: new_iter.current_ = buffers.begin(); Chris@16: new_iter.end_ = buffers.end(); Chris@16: while (new_iter.current_ != new_iter.end_) Chris@16: { Chris@16: buffer_type buffer = *new_iter.current_; Chris@16: new_iter.position_ += boost::asio::buffer_size(buffer); Chris@16: ++new_iter.current_; Chris@16: } Chris@16: return new_iter; Chris@16: } Chris@16: Chris@16: /// Dereference an iterator. Chris@16: reference operator*() const Chris@16: { Chris@16: return dereference(); Chris@16: } Chris@16: Chris@16: /// Dereference an iterator. Chris@16: pointer operator->() const Chris@16: { Chris@16: return &dereference(); Chris@16: } Chris@16: Chris@16: /// Access an individual element. Chris@16: reference operator[](std::ptrdiff_t difference) const Chris@16: { Chris@16: buffers_iterator tmp(*this); Chris@16: tmp.advance(difference); Chris@16: return *tmp; Chris@16: } Chris@16: Chris@16: /// Increment operator (prefix). Chris@16: buffers_iterator& operator++() Chris@16: { Chris@16: increment(); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: /// Increment operator (postfix). Chris@16: buffers_iterator operator++(int) Chris@16: { Chris@16: buffers_iterator tmp(*this); Chris@16: ++*this; Chris@16: return tmp; Chris@16: } Chris@16: Chris@16: /// Decrement operator (prefix). Chris@16: buffers_iterator& operator--() Chris@16: { Chris@16: decrement(); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: /// Decrement operator (postfix). Chris@16: buffers_iterator operator--(int) Chris@16: { Chris@16: buffers_iterator tmp(*this); Chris@16: --*this; Chris@16: return tmp; Chris@16: } Chris@16: Chris@16: /// Addition operator. Chris@16: buffers_iterator& operator+=(std::ptrdiff_t difference) Chris@16: { Chris@16: advance(difference); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: /// Subtraction operator. Chris@16: buffers_iterator& operator-=(std::ptrdiff_t difference) Chris@16: { Chris@16: advance(-difference); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: /// Addition operator. Chris@16: friend buffers_iterator operator+(const buffers_iterator& iter, Chris@16: std::ptrdiff_t difference) Chris@16: { Chris@16: buffers_iterator tmp(iter); Chris@16: tmp.advance(difference); Chris@16: return tmp; Chris@16: } Chris@16: Chris@16: /// Addition operator. Chris@16: friend buffers_iterator operator+(std::ptrdiff_t difference, Chris@16: const buffers_iterator& iter) Chris@16: { Chris@16: buffers_iterator tmp(iter); Chris@16: tmp.advance(difference); Chris@16: return tmp; Chris@16: } Chris@16: Chris@16: /// Subtraction operator. Chris@16: friend buffers_iterator operator-(const buffers_iterator& iter, Chris@16: std::ptrdiff_t difference) Chris@16: { Chris@16: buffers_iterator tmp(iter); Chris@16: tmp.advance(-difference); Chris@16: return tmp; Chris@16: } Chris@16: Chris@16: /// Subtraction operator. Chris@16: friend std::ptrdiff_t operator-(const buffers_iterator& a, Chris@16: const buffers_iterator& b) Chris@16: { Chris@16: return b.distance_to(a); Chris@16: } Chris@16: Chris@16: /// Test two iterators for equality. Chris@16: friend bool operator==(const buffers_iterator& a, const 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 buffers_iterator& a, const buffers_iterator& b) Chris@16: { Chris@16: return !a.equal(b); Chris@16: } Chris@16: Chris@16: /// Compare two iterators. Chris@16: friend bool operator<(const buffers_iterator& a, const buffers_iterator& b) Chris@16: { Chris@16: return a.distance_to(b) > 0; Chris@16: } Chris@16: Chris@16: /// Compare two iterators. Chris@16: friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b) Chris@16: { Chris@16: return !(b < a); Chris@16: } Chris@16: Chris@16: /// Compare two iterators. Chris@16: friend bool operator>(const buffers_iterator& a, const buffers_iterator& b) Chris@16: { Chris@16: return b < a; Chris@16: } Chris@16: Chris@16: /// Compare two iterators. Chris@16: friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b) Chris@16: { Chris@16: return !(a < b); Chris@16: } Chris@16: Chris@16: private: Chris@16: // Dereference the iterator. Chris@16: reference dereference() const Chris@16: { Chris@16: return buffer_cast(current_buffer_)[current_buffer_position_]; Chris@16: } Chris@16: Chris@16: // Compare two iterators for equality. Chris@16: bool equal(const buffers_iterator& other) const Chris@16: { Chris@16: return position_ == other.position_; Chris@16: } Chris@16: Chris@16: // Increment the iterator. Chris@16: void increment() Chris@16: { Chris@16: BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds"); Chris@16: ++position_; Chris@16: Chris@16: // Check if the increment can be satisfied by the current buffer. Chris@16: ++current_buffer_position_; Chris@16: if (current_buffer_position_ != boost::asio::buffer_size(current_buffer_)) Chris@16: return; Chris@16: Chris@16: // Find the next non-empty buffer. Chris@16: ++current_; Chris@16: current_buffer_position_ = 0; Chris@16: while (current_ != end_) Chris@16: { Chris@16: current_buffer_ = *current_; Chris@16: if (boost::asio::buffer_size(current_buffer_) > 0) Chris@16: return; Chris@16: ++current_; Chris@16: } Chris@16: } Chris@16: Chris@16: // Decrement the iterator. Chris@16: void decrement() Chris@16: { Chris@16: BOOST_ASIO_ASSERT(position_ > 0 && "iterator out of bounds"); Chris@16: --position_; Chris@16: Chris@16: // Check if the decrement can be satisfied by the current buffer. Chris@16: if (current_buffer_position_ != 0) Chris@16: { Chris@16: --current_buffer_position_; Chris@16: return; Chris@16: } Chris@16: Chris@16: // Find the previous non-empty buffer. Chris@16: typename BufferSequence::const_iterator iter = current_; Chris@16: while (iter != begin_) Chris@16: { Chris@16: --iter; Chris@16: buffer_type buffer = *iter; Chris@16: std::size_t buffer_size = boost::asio::buffer_size(buffer); Chris@16: if (buffer_size > 0) Chris@16: { Chris@16: current_ = iter; Chris@16: current_buffer_ = buffer; Chris@16: current_buffer_position_ = buffer_size - 1; Chris@16: return; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: // Advance the iterator by the specified distance. Chris@16: void advance(std::ptrdiff_t n) Chris@16: { Chris@16: if (n > 0) Chris@16: { Chris@16: BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds"); Chris@16: for (;;) Chris@16: { Chris@16: std::ptrdiff_t current_buffer_balance Chris@16: = boost::asio::buffer_size(current_buffer_) Chris@16: - current_buffer_position_; Chris@16: Chris@16: // Check if the advance can be satisfied by the current buffer. Chris@16: if (current_buffer_balance > n) Chris@16: { Chris@16: position_ += n; Chris@16: current_buffer_position_ += n; Chris@16: return; Chris@16: } Chris@16: Chris@16: // Update position. Chris@16: n -= current_buffer_balance; Chris@16: position_ += current_buffer_balance; Chris@16: Chris@16: // Move to next buffer. If it is empty then it will be skipped on the Chris@16: // next iteration of this loop. Chris@16: if (++current_ == end_) Chris@16: { Chris@16: BOOST_ASIO_ASSERT(n == 0 && "iterator out of bounds"); Chris@16: current_buffer_ = buffer_type(); Chris@16: current_buffer_position_ = 0; Chris@16: return; Chris@16: } Chris@16: current_buffer_ = *current_; Chris@16: current_buffer_position_ = 0; Chris@16: } Chris@16: } Chris@16: else if (n < 0) Chris@16: { Chris@16: std::size_t abs_n = -n; Chris@16: BOOST_ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds"); Chris@16: for (;;) Chris@16: { Chris@16: // Check if the advance can be satisfied by the current buffer. Chris@16: if (current_buffer_position_ >= abs_n) Chris@16: { Chris@16: position_ -= abs_n; Chris@16: current_buffer_position_ -= abs_n; Chris@16: return; Chris@16: } Chris@16: Chris@16: // Update position. Chris@16: abs_n -= current_buffer_position_; Chris@16: position_ -= current_buffer_position_; Chris@16: Chris@16: // Check if we've reached the beginning of the buffers. Chris@16: if (current_ == begin_) Chris@16: { Chris@16: BOOST_ASIO_ASSERT(abs_n == 0 && "iterator out of bounds"); Chris@16: current_buffer_position_ = 0; Chris@16: return; Chris@16: } Chris@16: Chris@16: // Find the previous non-empty buffer. Chris@16: typename BufferSequence::const_iterator iter = current_; Chris@16: while (iter != begin_) Chris@16: { Chris@16: --iter; Chris@16: buffer_type buffer = *iter; Chris@16: std::size_t buffer_size = boost::asio::buffer_size(buffer); Chris@16: if (buffer_size > 0) Chris@16: { Chris@16: current_ = iter; Chris@16: current_buffer_ = buffer; Chris@16: current_buffer_position_ = buffer_size; Chris@16: break; Chris@16: } Chris@16: } Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: // Determine the distance between two iterators. Chris@16: std::ptrdiff_t distance_to(const buffers_iterator& other) const Chris@16: { Chris@16: return other.position_ - position_; Chris@16: } Chris@16: Chris@16: buffer_type current_buffer_; Chris@16: std::size_t current_buffer_position_; Chris@16: typename BufferSequence::const_iterator begin_; Chris@16: typename BufferSequence::const_iterator current_; Chris@16: typename BufferSequence::const_iterator end_; Chris@16: std::size_t position_; Chris@16: }; Chris@16: Chris@16: /// Construct an iterator representing the beginning of the buffers' data. Chris@16: template Chris@16: inline buffers_iterator buffers_begin( Chris@16: const BufferSequence& buffers) Chris@16: { Chris@16: return buffers_iterator::begin(buffers); Chris@16: } Chris@16: Chris@16: /// Construct an iterator representing the end of the buffers' data. Chris@16: template Chris@16: inline buffers_iterator buffers_end( Chris@16: const BufferSequence& buffers) Chris@16: { Chris@16: return buffers_iterator::end(buffers); Chris@16: } Chris@16: Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP