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

source code of boost/libs/asio/include/boost/asio/buffers_iterator.hpp