2 // buffers_iterator.hpp
3 // ~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef BOOST_ASIO_BUFFERS_ITERATOR_HPP
12 #define BOOST_ASIO_BUFFERS_ITERATOR_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/config.hpp>
21 #include <boost/asio/buffer.hpp>
22 #include <boost/asio/detail/assert.hpp>
23 #include <boost/asio/detail/type_traits.hpp>
25 #include <boost/asio/detail/push_options.hpp>
32 template <bool IsMutable>
33 struct buffers_iterator_types_helper;
36 struct buffers_iterator_types_helper<false>
38 typedef const_buffer buffer_type;
39 template <typename ByteType>
42 typedef typename add_const<ByteType>::type type;
47 struct buffers_iterator_types_helper<true>
49 typedef mutable_buffer buffer_type;
50 template <typename ByteType>
53 typedef ByteType type;
57 template <typename BufferSequence, typename ByteType>
58 struct buffers_iterator_types
62 is_mutable = is_convertible<
63 typename BufferSequence::value_type,
64 mutable_buffer>::value
66 typedef buffers_iterator_types_helper<is_mutable> helper;
67 typedef typename helper::buffer_type buffer_type;
68 typedef typename helper::template byte_type<ByteType>::type byte_type;
69 typedef typename BufferSequence::const_iterator const_iterator;
72 template <typename ByteType>
73 struct buffers_iterator_types<mutable_buffer, ByteType>
75 typedef mutable_buffer buffer_type;
76 typedef ByteType byte_type;
77 typedef const mutable_buffer* const_iterator;
80 template <typename ByteType>
81 struct buffers_iterator_types<const_buffer, ByteType>
83 typedef const_buffer buffer_type;
84 typedef typename add_const<ByteType>::type byte_type;
85 typedef const const_buffer* const_iterator;
88 #if !defined(BOOST_ASIO_NO_DEPRECATED)
90 template <typename ByteType>
91 struct buffers_iterator_types<mutable_buffers_1, ByteType>
93 typedef mutable_buffer buffer_type;
94 typedef ByteType byte_type;
95 typedef const mutable_buffer* const_iterator;
98 template <typename ByteType>
99 struct buffers_iterator_types<const_buffers_1, ByteType>
101 typedef const_buffer buffer_type;
102 typedef typename add_const<ByteType>::type byte_type;
103 typedef const const_buffer* const_iterator;
106 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
109 /// A random access iterator over the bytes in a buffer sequence.
110 template <typename BufferSequence, typename ByteType = char>
111 class buffers_iterator
114 typedef typename detail::buffers_iterator_types<
115 BufferSequence, ByteType>::buffer_type buffer_type;
117 typedef typename detail::buffers_iterator_types<BufferSequence,
118 ByteType>::const_iterator buffer_sequence_iterator_type;
121 /// The type used for the distance between two iterators.
122 typedef std::ptrdiff_t difference_type;
124 /// The type of the value pointed to by the iterator.
125 typedef ByteType value_type;
127 #if defined(GENERATING_DOCUMENTATION)
128 /// The type of the result of applying operator->() to the iterator.
130 * If the buffer sequence stores buffer objects that are convertible to
131 * mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a
132 * pointer to a const ByteType.
134 typedef const_or_non_const_ByteType* pointer;
135 #else // defined(GENERATING_DOCUMENTATION)
136 typedef typename detail::buffers_iterator_types<
137 BufferSequence, ByteType>::byte_type* pointer;
138 #endif // defined(GENERATING_DOCUMENTATION)
140 #if defined(GENERATING_DOCUMENTATION)
141 /// The type of the result of applying operator*() to the iterator.
143 * If the buffer sequence stores buffer objects that are convertible to
144 * mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a
145 * reference to a const ByteType.
147 typedef const_or_non_const_ByteType& reference;
148 #else // defined(GENERATING_DOCUMENTATION)
149 typedef typename detail::buffers_iterator_types<
150 BufferSequence, ByteType>::byte_type& reference;
151 #endif // defined(GENERATING_DOCUMENTATION)
153 /// The iterator category.
154 typedef std::random_access_iterator_tag iterator_category;
156 /// Default constructor. Creates an iterator in an undefined state.
159 current_buffer_position_(0),
167 /// Construct an iterator representing the beginning of the buffers' data.
168 static buffers_iterator begin(const BufferSequence& buffers)
169 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
170 __attribute__ ((__noinline__))
171 #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
173 buffers_iterator new_iter;
174 new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers);
175 new_iter.current_ = boost::asio::buffer_sequence_begin(buffers);
176 new_iter.end_ = boost::asio::buffer_sequence_end(buffers);
177 while (new_iter.current_ != new_iter.end_)
179 new_iter.current_buffer_ = *new_iter.current_;
180 if (new_iter.current_buffer_.size() > 0)
187 /// Construct an iterator representing the end of the buffers' data.
188 static buffers_iterator end(const BufferSequence& buffers)
189 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
190 __attribute__ ((__noinline__))
191 #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
193 buffers_iterator new_iter;
194 new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers);
195 new_iter.current_ = boost::asio::buffer_sequence_begin(buffers);
196 new_iter.end_ = boost::asio::buffer_sequence_end(buffers);
197 while (new_iter.current_ != new_iter.end_)
199 buffer_type buffer = *new_iter.current_;
200 new_iter.position_ += buffer.size();
206 /// Dereference an iterator.
207 reference operator*() const
209 return dereference();
212 /// Dereference an iterator.
213 pointer operator->() const
215 return &dereference();
218 /// Access an individual element.
219 reference operator[](std::ptrdiff_t difference) const
221 buffers_iterator tmp(*this);
222 tmp.advance(difference);
226 /// Increment operator (prefix).
227 buffers_iterator& operator++()
233 /// Increment operator (postfix).
234 buffers_iterator operator++(int)
236 buffers_iterator tmp(*this);
241 /// Decrement operator (prefix).
242 buffers_iterator& operator--()
248 /// Decrement operator (postfix).
249 buffers_iterator operator--(int)
251 buffers_iterator tmp(*this);
256 /// Addition operator.
257 buffers_iterator& operator+=(std::ptrdiff_t difference)
263 /// Subtraction operator.
264 buffers_iterator& operator-=(std::ptrdiff_t difference)
266 advance(-difference);
270 /// Addition operator.
271 friend buffers_iterator operator+(const buffers_iterator& iter,
272 std::ptrdiff_t difference)
274 buffers_iterator tmp(iter);
275 tmp.advance(difference);
279 /// Addition operator.
280 friend buffers_iterator operator+(std::ptrdiff_t difference,
281 const buffers_iterator& iter)
283 buffers_iterator tmp(iter);
284 tmp.advance(difference);
288 /// Subtraction operator.
289 friend buffers_iterator operator-(const buffers_iterator& iter,
290 std::ptrdiff_t difference)
292 buffers_iterator tmp(iter);
293 tmp.advance(-difference);
297 /// Subtraction operator.
298 friend std::ptrdiff_t operator-(const buffers_iterator& a,
299 const buffers_iterator& b)
301 return b.distance_to(a);
304 /// Test two iterators for equality.
305 friend bool operator==(const buffers_iterator& a, const buffers_iterator& b)
310 /// Test two iterators for inequality.
311 friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b)
316 /// Compare two iterators.
317 friend bool operator<(const buffers_iterator& a, const buffers_iterator& b)
319 return a.distance_to(b) > 0;
322 /// Compare two iterators.
323 friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b)
328 /// Compare two iterators.
329 friend bool operator>(const buffers_iterator& a, const buffers_iterator& b)
334 /// Compare two iterators.
335 friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b)
341 // Dereference the iterator.
342 reference dereference() const
344 return static_cast<pointer>(
345 current_buffer_.data())[current_buffer_position_];
348 // Compare two iterators for equality.
349 bool equal(const buffers_iterator& other) const
351 return position_ == other.position_;
354 // Increment the iterator.
357 BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
360 // Check if the increment can be satisfied by the current buffer.
361 ++current_buffer_position_;
362 if (current_buffer_position_ != current_buffer_.size())
365 // Find the next non-empty buffer.
367 current_buffer_position_ = 0;
368 while (current_ != end_)
370 current_buffer_ = *current_;
371 if (current_buffer_.size() > 0)
377 // Decrement the iterator.
380 BOOST_ASIO_ASSERT(position_ > 0 && "iterator out of bounds");
383 // Check if the decrement can be satisfied by the current buffer.
384 if (current_buffer_position_ != 0)
386 --current_buffer_position_;
390 // Find the previous non-empty buffer.
391 buffer_sequence_iterator_type iter = current_;
392 while (iter != begin_)
395 buffer_type buffer = *iter;
396 std::size_t buffer_size = buffer.size();
400 current_buffer_ = buffer;
401 current_buffer_position_ = buffer_size - 1;
407 // Advance the iterator by the specified distance.
408 void advance(std::ptrdiff_t n)
412 BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
415 std::ptrdiff_t current_buffer_balance
416 = current_buffer_.size() - current_buffer_position_;
418 // Check if the advance can be satisfied by the current buffer.
419 if (current_buffer_balance > n)
422 current_buffer_position_ += n;
427 n -= current_buffer_balance;
428 position_ += current_buffer_balance;
430 // Move to next buffer. If it is empty then it will be skipped on the
431 // next iteration of this loop.
432 if (++current_ == end_)
434 BOOST_ASIO_ASSERT(n == 0 && "iterator out of bounds");
435 current_buffer_ = buffer_type();
436 current_buffer_position_ = 0;
439 current_buffer_ = *current_;
440 current_buffer_position_ = 0;
445 std::size_t abs_n = -n;
446 BOOST_ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds");
449 // Check if the advance can be satisfied by the current buffer.
450 if (current_buffer_position_ >= abs_n)
453 current_buffer_position_ -= abs_n;
458 abs_n -= current_buffer_position_;
459 position_ -= current_buffer_position_;
461 // Check if we've reached the beginning of the buffers.
462 if (current_ == begin_)
464 BOOST_ASIO_ASSERT(abs_n == 0 && "iterator out of bounds");
465 current_buffer_position_ = 0;
469 // Find the previous non-empty buffer.
470 buffer_sequence_iterator_type iter = current_;
471 while (iter != begin_)
474 buffer_type buffer = *iter;
475 std::size_t buffer_size = buffer.size();
479 current_buffer_ = buffer;
480 current_buffer_position_ = buffer_size;
488 // Determine the distance between two iterators.
489 std::ptrdiff_t distance_to(const buffers_iterator& other) const
491 return other.position_ - position_;
494 buffer_type current_buffer_;
495 std::size_t current_buffer_position_;
496 buffer_sequence_iterator_type begin_;
497 buffer_sequence_iterator_type current_;
498 buffer_sequence_iterator_type end_;
499 std::size_t position_;
502 /// Construct an iterator representing the beginning of the buffers' data.
503 template <typename BufferSequence>
504 inline buffers_iterator<BufferSequence> buffers_begin(
505 const BufferSequence& buffers)
507 return buffers_iterator<BufferSequence>::begin(buffers);
510 /// Construct an iterator representing the end of the buffers' data.
511 template <typename BufferSequence>
512 inline buffers_iterator<BufferSequence> buffers_end(
513 const BufferSequence& buffers)
515 return buffers_iterator<BufferSequence>::end(buffers);
521 #include <boost/asio/detail/pop_options.hpp>
523 #endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP