1 //
2 // buffers_iterator.hpp
3 // ~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
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)
9 //
10
11 #ifndef ASIO_BUFFERS_ITERATOR_HPP
12 #define ASIO_BUFFERS_ITERATOR_HPP
13
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18 #include "asio/detail/config.hpp"
19 #include <cstddef>
20 #include <iterator>
21 #include "asio/buffer.hpp"
22 #include "asio/detail/assert.hpp"
23 #include "asio/detail/type_traits.hpp"
24
25 #include "asio/detail/push_options.hpp"
26
27 namespace asio {
28
29 namespace detail
30 {
31 template <bool IsMutable>
32 struct buffers_iterator_types_helper;
33
34 template <>
35 struct buffers_iterator_types_helper<false>
36 {
37 typedef const_buffer buffer_type;
38 template <typename ByteType>
39 struct byte_type
40 {
41 typedef typename add_const<ByteType>::type type;
42 };
43 };
44
45 template <>
46 struct buffers_iterator_types_helper<true>
47 {
48 typedef mutable_buffer buffer_type;
49 template <typename ByteType>
50 struct byte_type
51 {
52 typedef ByteType type;
53 };
54 };
55
56 template <typename BufferSequence, typename ByteType>
57 struct buffers_iterator_types
58 {
59 enum
60 {
61 is_mutable = is_convertible<
62 typename BufferSequence::value_type,
63 mutable_buffer>::value
64 };
65 typedef buffers_iterator_types_helper<is_mutable> helper;
66 typedef typename helper::buffer_type buffer_type;
67 typedef typename helper::template byte_type<ByteType>::type byte_type;
68 typedef typename BufferSequence::const_iterator const_iterator;
69 };
70
71 template <typename ByteType>
72 struct buffers_iterator_types<mutable_buffer, ByteType>
73 {
74 typedef mutable_buffer buffer_type;
75 typedef ByteType byte_type;
76 typedef const mutable_buffer* const_iterator;
77 };
78
79 template <typename ByteType>
80 struct buffers_iterator_types<const_buffer, ByteType>
81 {
82 typedef const_buffer buffer_type;
83 typedef typename add_const<ByteType>::type byte_type;
84 typedef const const_buffer* const_iterator;
85 };
86
87 #if !defined(ASIO_NO_DEPRECATED)
88
89 template <typename ByteType>
90 struct buffers_iterator_types<mutable_buffers_1, ByteType>
91 {
92 typedef mutable_buffer buffer_type;
93 typedef ByteType byte_type;
94 typedef const mutable_buffer* const_iterator;
95 };
96
97 template <typename ByteType>
98 struct buffers_iterator_types<const_buffers_1, ByteType>
99 {
100 typedef const_buffer buffer_type;
101 typedef typename add_const<ByteType>::type byte_type;
102 typedef const const_buffer* const_iterator;
103 };
104
105 #endif // !defined(ASIO_NO_DEPRECATED)
106 }
107
108 /// A random access iterator over the bytes in a buffer sequence.
109 template <typename BufferSequence, typename ByteType = char>
110 class buffers_iterator
111 {
112 private:
113 typedef typename detail::buffers_iterator_types<
114 BufferSequence, ByteType>::buffer_type buffer_type;
115
116 typedef typename detail::buffers_iterator_types<BufferSequence,
117 ByteType>::const_iterator buffer_sequence_iterator_type;
118
119 public:
120 /// The type used for the distance between two iterators.
121 typedef std::ptrdiff_t difference_type;
122
123 /// The type of the value pointed to by the iterator.
124 typedef ByteType value_type;
125
126 #if defined(GENERATING_DOCUMENTATION)
127 /// The type of the result of applying operator->() to the iterator.
128 /**
129 * If the buffer sequence stores buffer objects that are convertible to
130 * mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a
131 * pointer to a const ByteType.
132 */
133 typedef const_or_non_const_ByteType* pointer;
134 #else // defined(GENERATING_DOCUMENTATION)
135 typedef typename detail::buffers_iterator_types<
136 BufferSequence, ByteType>::byte_type* pointer;
137 #endif // defined(GENERATING_DOCUMENTATION)
138
139 #if defined(GENERATING_DOCUMENTATION)
140 /// The type of the result of applying operator*() to the iterator.
141 /**
142 * If the buffer sequence stores buffer objects that are convertible to
143 * mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a
144 * reference to a const ByteType.
145 */
146 typedef const_or_non_const_ByteType& reference;
147 #else // defined(GENERATING_DOCUMENTATION)
148 typedef typename detail::buffers_iterator_types<
149 BufferSequence, ByteType>::byte_type& reference;
150 #endif // defined(GENERATING_DOCUMENTATION)
151
152 /// The iterator category.
153 typedef std::random_access_iterator_tag iterator_category;
154
155 /// Default constructor. Creates an iterator in an undefined state.
buffers_iterator()156 buffers_iterator()
157 : current_buffer_(),
158 current_buffer_position_(0),
159 begin_(),
160 current_(),
161 end_(),
162 position_(0)
163 {
164 }
165
166 /// Construct an iterator representing the beginning of the buffers' data.
begin(const BufferSequence & buffers)167 static buffers_iterator begin(const BufferSequence& buffers)
168 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
169 __attribute__ ((__noinline__))
170 #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
171 {
172 buffers_iterator new_iter;
173 new_iter.begin_ = asio::buffer_sequence_begin(buffers);
174 new_iter.current_ = asio::buffer_sequence_begin(buffers);
175 new_iter.end_ = asio::buffer_sequence_end(buffers);
176 while (new_iter.current_ != new_iter.end_)
177 {
178 new_iter.current_buffer_ = *new_iter.current_;
179 if (new_iter.current_buffer_.size() > 0)
180 break;
181 ++new_iter.current_;
182 }
183 return new_iter;
184 }
185
186 /// Construct an iterator representing the end of the buffers' data.
end(const BufferSequence & buffers)187 static buffers_iterator end(const BufferSequence& buffers)
188 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
189 __attribute__ ((__noinline__))
190 #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
191 {
192 buffers_iterator new_iter;
193 new_iter.begin_ = asio::buffer_sequence_begin(buffers);
194 new_iter.current_ = asio::buffer_sequence_begin(buffers);
195 new_iter.end_ = asio::buffer_sequence_end(buffers);
196 while (new_iter.current_ != new_iter.end_)
197 {
198 buffer_type buffer = *new_iter.current_;
199 new_iter.position_ += buffer.size();
200 ++new_iter.current_;
201 }
202 return new_iter;
203 }
204
205 /// Dereference an iterator.
operator *() const206 reference operator*() const
207 {
208 return dereference();
209 }
210
211 /// Dereference an iterator.
operator ->() const212 pointer operator->() const
213 {
214 return &dereference();
215 }
216
217 /// Access an individual element.
operator [](std::ptrdiff_t difference) const218 reference operator[](std::ptrdiff_t difference) const
219 {
220 buffers_iterator tmp(*this);
221 tmp.advance(difference);
222 return *tmp;
223 }
224
225 /// Increment operator (prefix).
operator ++()226 buffers_iterator& operator++()
227 {
228 increment();
229 return *this;
230 }
231
232 /// Increment operator (postfix).
operator ++(int)233 buffers_iterator operator++(int)
234 {
235 buffers_iterator tmp(*this);
236 ++*this;
237 return tmp;
238 }
239
240 /// Decrement operator (prefix).
operator --()241 buffers_iterator& operator--()
242 {
243 decrement();
244 return *this;
245 }
246
247 /// Decrement operator (postfix).
operator --(int)248 buffers_iterator operator--(int)
249 {
250 buffers_iterator tmp(*this);
251 --*this;
252 return tmp;
253 }
254
255 /// Addition operator.
operator +=(std::ptrdiff_t difference)256 buffers_iterator& operator+=(std::ptrdiff_t difference)
257 {
258 advance(difference);
259 return *this;
260 }
261
262 /// Subtraction operator.
operator -=(std::ptrdiff_t difference)263 buffers_iterator& operator-=(std::ptrdiff_t difference)
264 {
265 advance(-difference);
266 return *this;
267 }
268
269 /// Addition operator.
operator +(const buffers_iterator & iter,std::ptrdiff_t difference)270 friend buffers_iterator operator+(const buffers_iterator& iter,
271 std::ptrdiff_t difference)
272 {
273 buffers_iterator tmp(iter);
274 tmp.advance(difference);
275 return tmp;
276 }
277
278 /// Addition operator.
operator +(std::ptrdiff_t difference,const buffers_iterator & iter)279 friend buffers_iterator operator+(std::ptrdiff_t difference,
280 const buffers_iterator& iter)
281 {
282 buffers_iterator tmp(iter);
283 tmp.advance(difference);
284 return tmp;
285 }
286
287 /// Subtraction operator.
operator -(const buffers_iterator & iter,std::ptrdiff_t difference)288 friend buffers_iterator operator-(const buffers_iterator& iter,
289 std::ptrdiff_t difference)
290 {
291 buffers_iterator tmp(iter);
292 tmp.advance(-difference);
293 return tmp;
294 }
295
296 /// Subtraction operator.
operator -(const buffers_iterator & a,const buffers_iterator & b)297 friend std::ptrdiff_t operator-(const buffers_iterator& a,
298 const buffers_iterator& b)
299 {
300 return b.distance_to(a);
301 }
302
303 /// Test two iterators for equality.
operator ==(const buffers_iterator & a,const buffers_iterator & b)304 friend bool operator==(const buffers_iterator& a, const buffers_iterator& b)
305 {
306 return a.equal(b);
307 }
308
309 /// Test two iterators for inequality.
operator !=(const buffers_iterator & a,const buffers_iterator & b)310 friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b)
311 {
312 return !a.equal(b);
313 }
314
315 /// Compare two iterators.
operator <(const buffers_iterator & a,const buffers_iterator & b)316 friend bool operator<(const buffers_iterator& a, const buffers_iterator& b)
317 {
318 return a.distance_to(b) > 0;
319 }
320
321 /// Compare two iterators.
operator <=(const buffers_iterator & a,const buffers_iterator & b)322 friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b)
323 {
324 return !(b < a);
325 }
326
327 /// Compare two iterators.
operator >(const buffers_iterator & a,const buffers_iterator & b)328 friend bool operator>(const buffers_iterator& a, const buffers_iterator& b)
329 {
330 return b < a;
331 }
332
333 /// Compare two iterators.
operator >=(const buffers_iterator & a,const buffers_iterator & b)334 friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b)
335 {
336 return !(a < b);
337 }
338
339 private:
340 // Dereference the iterator.
dereference() const341 reference dereference() const
342 {
343 return static_cast<pointer>(
344 current_buffer_.data())[current_buffer_position_];
345 }
346
347 // Compare two iterators for equality.
equal(const buffers_iterator & other) const348 bool equal(const buffers_iterator& other) const
349 {
350 return position_ == other.position_;
351 }
352
353 // Increment the iterator.
increment()354 void increment()
355 {
356 ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
357 ++position_;
358
359 // Check if the increment can be satisfied by the current buffer.
360 ++current_buffer_position_;
361 if (current_buffer_position_ != current_buffer_.size())
362 return;
363
364 // Find the next non-empty buffer.
365 ++current_;
366 current_buffer_position_ = 0;
367 while (current_ != end_)
368 {
369 current_buffer_ = *current_;
370 if (current_buffer_.size() > 0)
371 return;
372 ++current_;
373 }
374 }
375
376 // Decrement the iterator.
decrement()377 void decrement()
378 {
379 ASIO_ASSERT(position_ > 0 && "iterator out of bounds");
380 --position_;
381
382 // Check if the decrement can be satisfied by the current buffer.
383 if (current_buffer_position_ != 0)
384 {
385 --current_buffer_position_;
386 return;
387 }
388
389 // Find the previous non-empty buffer.
390 buffer_sequence_iterator_type iter = current_;
391 while (iter != begin_)
392 {
393 --iter;
394 buffer_type buffer = *iter;
395 std::size_t buffer_size = buffer.size();
396 if (buffer_size > 0)
397 {
398 current_ = iter;
399 current_buffer_ = buffer;
400 current_buffer_position_ = buffer_size - 1;
401 return;
402 }
403 }
404 }
405
406 // Advance the iterator by the specified distance.
advance(std::ptrdiff_t n)407 void advance(std::ptrdiff_t n)
408 {
409 if (n > 0)
410 {
411 ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
412 for (;;)
413 {
414 std::ptrdiff_t current_buffer_balance
415 = current_buffer_.size() - current_buffer_position_;
416
417 // Check if the advance can be satisfied by the current buffer.
418 if (current_buffer_balance > n)
419 {
420 position_ += n;
421 current_buffer_position_ += n;
422 return;
423 }
424
425 // Update position.
426 n -= current_buffer_balance;
427 position_ += current_buffer_balance;
428
429 // Move to next buffer. If it is empty then it will be skipped on the
430 // next iteration of this loop.
431 if (++current_ == end_)
432 {
433 ASIO_ASSERT(n == 0 && "iterator out of bounds");
434 current_buffer_ = buffer_type();
435 current_buffer_position_ = 0;
436 return;
437 }
438 current_buffer_ = *current_;
439 current_buffer_position_ = 0;
440 }
441 }
442 else if (n < 0)
443 {
444 std::size_t abs_n = -n;
445 ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds");
446 for (;;)
447 {
448 // Check if the advance can be satisfied by the current buffer.
449 if (current_buffer_position_ >= abs_n)
450 {
451 position_ -= abs_n;
452 current_buffer_position_ -= abs_n;
453 return;
454 }
455
456 // Update position.
457 abs_n -= current_buffer_position_;
458 position_ -= current_buffer_position_;
459
460 // Check if we've reached the beginning of the buffers.
461 if (current_ == begin_)
462 {
463 ASIO_ASSERT(abs_n == 0 && "iterator out of bounds");
464 current_buffer_position_ = 0;
465 return;
466 }
467
468 // Find the previous non-empty buffer.
469 buffer_sequence_iterator_type iter = current_;
470 while (iter != begin_)
471 {
472 --iter;
473 buffer_type buffer = *iter;
474 std::size_t buffer_size = buffer.size();
475 if (buffer_size > 0)
476 {
477 current_ = iter;
478 current_buffer_ = buffer;
479 current_buffer_position_ = buffer_size;
480 break;
481 }
482 }
483 }
484 }
485 }
486
487 // Determine the distance between two iterators.
distance_to(const buffers_iterator & other) const488 std::ptrdiff_t distance_to(const buffers_iterator& other) const
489 {
490 return other.position_ - position_;
491 }
492
493 buffer_type current_buffer_;
494 std::size_t current_buffer_position_;
495 buffer_sequence_iterator_type begin_;
496 buffer_sequence_iterator_type current_;
497 buffer_sequence_iterator_type end_;
498 std::size_t position_;
499 };
500
501 /// Construct an iterator representing the beginning of the buffers' data.
502 template <typename BufferSequence>
buffers_begin(const BufferSequence & buffers)503 inline buffers_iterator<BufferSequence> buffers_begin(
504 const BufferSequence& buffers)
505 {
506 return buffers_iterator<BufferSequence>::begin(buffers);
507 }
508
509 /// Construct an iterator representing the end of the buffers' data.
510 template <typename BufferSequence>
buffers_end(const BufferSequence & buffers)511 inline buffers_iterator<BufferSequence> buffers_end(
512 const BufferSequence& buffers)
513 {
514 return buffers_iterator<BufferSequence>::end(buffers);
515 }
516
517 } // namespace asio
518
519 #include "asio/detail/pop_options.hpp"
520
521 #endif // ASIO_BUFFERS_ITERATOR_HPP
522