1 //
2 // buffers_iterator.hpp
3 // ~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2015 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   };
69 }
70 
71 /// A random access iterator over the bytes in a buffer sequence.
72 template <typename BufferSequence, typename ByteType = char>
73 class buffers_iterator
74 {
75 private:
76   typedef typename detail::buffers_iterator_types<
77       BufferSequence, ByteType>::buffer_type buffer_type;
78 
79 public:
80   /// The type used for the distance between two iterators.
81   typedef std::ptrdiff_t difference_type;
82 
83   /// The type of the value pointed to by the iterator.
84   typedef ByteType value_type;
85 
86 #if defined(GENERATING_DOCUMENTATION)
87   /// The type of the result of applying operator->() to the iterator.
88   /**
89    * If the buffer sequence stores buffer objects that are convertible to
90    * mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a
91    * pointer to a const ByteType.
92    */
93   typedef const_or_non_const_ByteType* pointer;
94 #else // defined(GENERATING_DOCUMENTATION)
95   typedef typename detail::buffers_iterator_types<
96       BufferSequence, ByteType>::byte_type* pointer;
97 #endif // defined(GENERATING_DOCUMENTATION)
98 
99 #if defined(GENERATING_DOCUMENTATION)
100   /// The type of the result of applying operator*() to the iterator.
101   /**
102    * If the buffer sequence stores buffer objects that are convertible to
103    * mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a
104    * reference to a const ByteType.
105    */
106   typedef const_or_non_const_ByteType& reference;
107 #else // defined(GENERATING_DOCUMENTATION)
108   typedef typename detail::buffers_iterator_types<
109       BufferSequence, ByteType>::byte_type& reference;
110 #endif // defined(GENERATING_DOCUMENTATION)
111 
112   /// The iterator category.
113   typedef std::random_access_iterator_tag iterator_category;
114 
115   /// Default constructor. Creates an iterator in an undefined state.
buffers_iterator()116   buffers_iterator()
117     : current_buffer_(),
118       current_buffer_position_(0),
119       begin_(),
120       current_(),
121       end_(),
122       position_(0)
123   {
124   }
125 
126   /// Construct an iterator representing the beginning of the buffers' data.
begin(const BufferSequence & buffers)127   static buffers_iterator begin(const BufferSequence& buffers)
128 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
129     __attribute__ ((__noinline__))
130 #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
131   {
132     buffers_iterator new_iter;
133     new_iter.begin_ = buffers.begin();
134     new_iter.current_ = buffers.begin();
135     new_iter.end_ = buffers.end();
136     while (new_iter.current_ != new_iter.end_)
137     {
138       new_iter.current_buffer_ = *new_iter.current_;
139       if (new_iter.current_buffer_.size() > 0)
140         break;
141       ++new_iter.current_;
142     }
143     return new_iter;
144   }
145 
146   /// Construct an iterator representing the end of the buffers' data.
end(const BufferSequence & buffers)147   static buffers_iterator end(const BufferSequence& buffers)
148 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
149     __attribute__ ((__noinline__))
150 #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
151   {
152     buffers_iterator new_iter;
153     new_iter.begin_ = buffers.begin();
154     new_iter.current_ = buffers.begin();
155     new_iter.end_ = buffers.end();
156     while (new_iter.current_ != new_iter.end_)
157     {
158       buffer_type buffer = *new_iter.current_;
159       new_iter.position_ += buffer.size();
160       ++new_iter.current_;
161     }
162     return new_iter;
163   }
164 
165   /// Dereference an iterator.
operator *() const166   reference operator*() const
167   {
168     return dereference();
169   }
170 
171   /// Dereference an iterator.
operator ->() const172   pointer operator->() const
173   {
174     return &dereference();
175   }
176 
177   /// Access an individual element.
operator [](std::ptrdiff_t difference) const178   reference operator[](std::ptrdiff_t difference) const
179   {
180     buffers_iterator tmp(*this);
181     tmp.advance(difference);
182     return *tmp;
183   }
184 
185   /// Increment operator (prefix).
operator ++()186   buffers_iterator& operator++()
187   {
188     increment();
189     return *this;
190   }
191 
192   /// Increment operator (postfix).
operator ++(int)193   buffers_iterator operator++(int)
194   {
195     buffers_iterator tmp(*this);
196     ++*this;
197     return tmp;
198   }
199 
200   /// Decrement operator (prefix).
operator --()201   buffers_iterator& operator--()
202   {
203     decrement();
204     return *this;
205   }
206 
207   /// Decrement operator (postfix).
operator --(int)208   buffers_iterator operator--(int)
209   {
210     buffers_iterator tmp(*this);
211     --*this;
212     return tmp;
213   }
214 
215   /// Addition operator.
operator +=(std::ptrdiff_t difference)216   buffers_iterator& operator+=(std::ptrdiff_t difference)
217   {
218     advance(difference);
219     return *this;
220   }
221 
222   /// Subtraction operator.
operator -=(std::ptrdiff_t difference)223   buffers_iterator& operator-=(std::ptrdiff_t difference)
224   {
225     advance(-difference);
226     return *this;
227   }
228 
229   /// Addition operator.
operator +(const buffers_iterator & iter,std::ptrdiff_t difference)230   friend buffers_iterator operator+(const buffers_iterator& iter,
231       std::ptrdiff_t difference)
232   {
233     buffers_iterator tmp(iter);
234     tmp.advance(difference);
235     return tmp;
236   }
237 
238   /// Addition operator.
operator +(std::ptrdiff_t difference,const buffers_iterator & iter)239   friend buffers_iterator operator+(std::ptrdiff_t difference,
240       const buffers_iterator& iter)
241   {
242     buffers_iterator tmp(iter);
243     tmp.advance(difference);
244     return tmp;
245   }
246 
247   /// Subtraction operator.
operator -(const buffers_iterator & iter,std::ptrdiff_t difference)248   friend buffers_iterator operator-(const buffers_iterator& iter,
249       std::ptrdiff_t difference)
250   {
251     buffers_iterator tmp(iter);
252     tmp.advance(-difference);
253     return tmp;
254   }
255 
256   /// Subtraction operator.
operator -(const buffers_iterator & a,const buffers_iterator & b)257   friend std::ptrdiff_t operator-(const buffers_iterator& a,
258       const buffers_iterator& b)
259   {
260     return b.distance_to(a);
261   }
262 
263   /// Test two iterators for equality.
operator ==(const buffers_iterator & a,const buffers_iterator & b)264   friend bool operator==(const buffers_iterator& a, const buffers_iterator& b)
265   {
266     return a.equal(b);
267   }
268 
269   /// Test two iterators for inequality.
operator !=(const buffers_iterator & a,const buffers_iterator & b)270   friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b)
271   {
272     return !a.equal(b);
273   }
274 
275   /// Compare two iterators.
operator <(const buffers_iterator & a,const buffers_iterator & b)276   friend bool operator<(const buffers_iterator& a, const buffers_iterator& b)
277   {
278     return a.distance_to(b) > 0;
279   }
280 
281   /// Compare two iterators.
operator <=(const buffers_iterator & a,const buffers_iterator & b)282   friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b)
283   {
284     return !(b < a);
285   }
286 
287   /// Compare two iterators.
operator >(const buffers_iterator & a,const buffers_iterator & b)288   friend bool operator>(const buffers_iterator& a, const buffers_iterator& b)
289   {
290     return b < a;
291   }
292 
293   /// Compare two iterators.
operator >=(const buffers_iterator & a,const buffers_iterator & b)294   friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b)
295   {
296     return !(a < b);
297   }
298 
299 private:
300   // Dereference the iterator.
dereference() const301   reference dereference() const
302   {
303     return static_cast<pointer>(
304         current_buffer_.data())[current_buffer_position_];
305   }
306 
307   // Compare two iterators for equality.
equal(const buffers_iterator & other) const308   bool equal(const buffers_iterator& other) const
309   {
310     return position_ == other.position_;
311   }
312 
313   // Increment the iterator.
increment()314   void increment()
315   {
316     ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
317     ++position_;
318 
319     // Check if the increment can be satisfied by the current buffer.
320     ++current_buffer_position_;
321     if (current_buffer_position_ != current_buffer_.size())
322       return;
323 
324     // Find the next non-empty buffer.
325     ++current_;
326     current_buffer_position_ = 0;
327     while (current_ != end_)
328     {
329       current_buffer_ = *current_;
330       if (current_buffer_.size() > 0)
331         return;
332       ++current_;
333     }
334   }
335 
336   // Decrement the iterator.
decrement()337   void decrement()
338   {
339     ASIO_ASSERT(position_ > 0 && "iterator out of bounds");
340     --position_;
341 
342     // Check if the decrement can be satisfied by the current buffer.
343     if (current_buffer_position_ != 0)
344     {
345       --current_buffer_position_;
346       return;
347     }
348 
349     // Find the previous non-empty buffer.
350     typename BufferSequence::const_iterator iter = current_;
351     while (iter != begin_)
352     {
353       --iter;
354       buffer_type buffer = *iter;
355       std::size_t buffer_size = buffer.size();
356       if (buffer_size > 0)
357       {
358         current_ = iter;
359         current_buffer_ = buffer;
360         current_buffer_position_ = buffer_size - 1;
361         return;
362       }
363     }
364   }
365 
366   // Advance the iterator by the specified distance.
advance(std::ptrdiff_t n)367   void advance(std::ptrdiff_t n)
368   {
369     if (n > 0)
370     {
371       ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
372       for (;;)
373       {
374         std::ptrdiff_t current_buffer_balance
375           = current_buffer_.size() - current_buffer_position_;
376 
377         // Check if the advance can be satisfied by the current buffer.
378         if (current_buffer_balance > n)
379         {
380           position_ += n;
381           current_buffer_position_ += n;
382           return;
383         }
384 
385         // Update position.
386         n -= current_buffer_balance;
387         position_ += current_buffer_balance;
388 
389         // Move to next buffer. If it is empty then it will be skipped on the
390         // next iteration of this loop.
391         if (++current_ == end_)
392         {
393           ASIO_ASSERT(n == 0 && "iterator out of bounds");
394           current_buffer_ = buffer_type();
395           current_buffer_position_ = 0;
396           return;
397         }
398         current_buffer_ = *current_;
399         current_buffer_position_ = 0;
400       }
401     }
402     else if (n < 0)
403     {
404       std::size_t abs_n = -n;
405       ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds");
406       for (;;)
407       {
408         // Check if the advance can be satisfied by the current buffer.
409         if (current_buffer_position_ >= abs_n)
410         {
411           position_ -= abs_n;
412           current_buffer_position_ -= abs_n;
413           return;
414         }
415 
416         // Update position.
417         abs_n -= current_buffer_position_;
418         position_ -= current_buffer_position_;
419 
420         // Check if we've reached the beginning of the buffers.
421         if (current_ == begin_)
422         {
423           ASIO_ASSERT(abs_n == 0 && "iterator out of bounds");
424           current_buffer_position_ = 0;
425           return;
426         }
427 
428         // Find the previous non-empty buffer.
429         typename BufferSequence::const_iterator iter = current_;
430         while (iter != begin_)
431         {
432           --iter;
433           buffer_type buffer = *iter;
434           std::size_t buffer_size = buffer.size();
435           if (buffer_size > 0)
436           {
437             current_ = iter;
438             current_buffer_ = buffer;
439             current_buffer_position_ = buffer_size;
440             break;
441           }
442         }
443       }
444     }
445   }
446 
447   // Determine the distance between two iterators.
distance_to(const buffers_iterator & other) const448   std::ptrdiff_t distance_to(const buffers_iterator& other) const
449   {
450     return other.position_ - position_;
451   }
452 
453   buffer_type current_buffer_;
454   std::size_t current_buffer_position_;
455   typename BufferSequence::const_iterator begin_;
456   typename BufferSequence::const_iterator current_;
457   typename BufferSequence::const_iterator end_;
458   std::size_t position_;
459 };
460 
461 /// Construct an iterator representing the beginning of the buffers' data.
462 template <typename BufferSequence>
buffers_begin(const BufferSequence & buffers)463 inline buffers_iterator<BufferSequence> buffers_begin(
464     const BufferSequence& buffers)
465 {
466   return buffers_iterator<BufferSequence>::begin(buffers);
467 }
468 
469 /// Construct an iterator representing the end of the buffers' data.
470 template <typename BufferSequence>
buffers_end(const BufferSequence & buffers)471 inline buffers_iterator<BufferSequence> buffers_end(
472     const BufferSequence& buffers)
473 {
474   return buffers_iterator<BufferSequence>::end(buffers);
475 }
476 
477 } // namespace asio
478 
479 #include "asio/detail/pop_options.hpp"
480 
481 #endif // ASIO_BUFFERS_ITERATOR_HPP
482