root/buffers_iterator.hpp

Revision 8b52aac5c11be152741738156c3df510ba6c804d, 8.9 KB (checked in by Antti-Juhani Kaijanaho <ajk@…>, 2 years ago)

Add a workaround to support Boost 1.35

Signed-off-by: Antti-Juhani Kaijanaho <ajk@…>

  • Property mode set to 100644
Line 
1//
2// buffers_iterator.hpp
3// ~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2008 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/push_options.hpp>
19
20#include <boost/asio/detail/push_options.hpp>
21#include <cstddef>
22#include <boost/assert.hpp>
23#include <boost/config.hpp>
24#include <boost/detail/workaround.hpp>
25#include <boost/iterator/iterator_facade.hpp>
26#include <boost/type_traits/is_convertible.hpp>
27#include <boost/type_traits/add_const.hpp>
28#include <boost/asio/detail/pop_options.hpp>
29
30#include <boost/asio/buffer.hpp>
31
32namespace boost {
33namespace asio {
34
35namespace detail
36{
37  template <bool IsMutable>
38  struct buffers_iterator_types_helper;
39
40  template <>
41  struct buffers_iterator_types_helper<false>
42  {
43    typedef const_buffer buffer_type;
44    template <typename ByteType>
45    struct byte_type
46    {
47      typedef typename boost::add_const<ByteType>::type type;
48    };
49  };
50
51  template <>
52  struct buffers_iterator_types_helper<true>
53  {
54    typedef mutable_buffer buffer_type;
55    template <typename ByteType>
56    struct byte_type
57    {
58      typedef ByteType type;
59    };
60  };
61
62  template <typename BufferSequence, typename ByteType>
63  struct buffers_iterator_types
64  {
65    enum
66    {
67      is_mutable = boost::is_convertible<
68        typename BufferSequence::value_type, mutable_buffer>::value
69    };
70    typedef buffers_iterator_types_helper<is_mutable> helper;
71    typedef typename helper::buffer_type buffer_type;
72    typedef typename helper::template byte_type<ByteType>::type byte_type;
73  };
74}
75
76/// A random access iterator over the bytes in a buffer sequence.
77template <typename BufferSequence, typename ByteType = char>
78class buffers_iterator
79  : public boost::iterator_facade<
80        buffers_iterator<BufferSequence, ByteType>,
81        typename detail::buffers_iterator_types<
82          BufferSequence, ByteType>::byte_type,
83        boost::random_access_traversal_tag>
84{
85private:
86  typedef typename detail::buffers_iterator_types<
87      BufferSequence, ByteType>::buffer_type buffer_type;
88  typedef typename detail::buffers_iterator_types<
89      BufferSequence, ByteType>::byte_type byte_type;
90
91public:
92  /// Default constructor. Creates an iterator in an undefined state.
93  buffers_iterator()
94    : current_buffer_(),
95      current_buffer_position_(0),
96      begin_(),
97      current_(),
98      end_(),
99      position_(0)
100  {
101  }
102
103  /// Construct an iterator representing the beginning of the buffers' data.
104  static buffers_iterator begin(const BufferSequence& buffers)
105#if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3)
106    __attribute__ ((noinline))
107#endif
108  {
109    buffers_iterator new_iter;
110    new_iter.begin_ = buffers.begin();
111    new_iter.current_ = buffers.begin();
112    new_iter.end_ = buffers.end();
113    while (new_iter.current_ != new_iter.end_)
114    {
115      new_iter.current_buffer_ = *new_iter.current_;
116      if (boost::asio::buffer_size(new_iter.current_buffer_) > 0)
117        break;
118      ++new_iter.current_;
119    }
120    return new_iter;
121  }
122
123  /// Construct an iterator representing the end of the buffers' data.
124  static buffers_iterator end(const BufferSequence& buffers)
125#if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3)
126    __attribute__ ((noinline))
127#endif
128  {
129    buffers_iterator new_iter;
130    new_iter.begin_ = buffers.begin();
131    new_iter.current_ = buffers.begin();
132    new_iter.end_ = buffers.end();
133    while (new_iter.current_ != new_iter.end_)
134    {
135      buffer_type buffer = *new_iter.current_;
136      new_iter.position_ += boost::asio::buffer_size(buffer);
137      ++new_iter.current_;
138    }
139    return new_iter;
140  }
141
142private:
143  friend class boost::iterator_core_access;
144
145  // Dereference the iterator.
146  byte_type& dereference() const
147  {
148    return buffer_cast<byte_type*>(current_buffer_)[current_buffer_position_];
149  }
150
151  // Compare two iterators for equality.
152  bool equal(const buffers_iterator& other) const
153  {
154    return position_ == other.position_;
155  }
156
157  // Increment the iterator.
158  void increment()
159  {
160    BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
161    ++position_;
162
163    // Check if the increment can be satisfied by the current buffer.
164    ++current_buffer_position_;
165    if (current_buffer_position_ != boost::asio::buffer_size(current_buffer_))
166      return;
167
168    // Find the next non-empty buffer.
169    ++current_;
170    current_buffer_position_ = 0;
171    while (current_ != end_)
172    {
173      current_buffer_ = *current_;
174      if (boost::asio::buffer_size(current_buffer_) > 0)
175        return;
176      ++current_;
177    }
178  }
179
180  // Decrement the iterator.
181  void decrement()
182  {
183    BOOST_ASSERT(position_ > 0 && "iterator out of bounds");
184    --position_;
185
186    // Check if the decrement can be satisfied by the current buffer.
187    if (current_buffer_position_ != 0)
188    {
189      --current_buffer_position_;
190      return;
191    }
192
193    // Find the previous non-empty buffer.
194    typename BufferSequence::const_iterator iter = current_;
195    while (iter != begin_)
196    {
197      --iter;
198      buffer_type buffer = *iter;
199      std::size_t buffer_size = boost::asio::buffer_size(buffer);
200      if (buffer_size > 0)
201      {
202        current_ = iter;
203        current_buffer_ = buffer;
204        current_buffer_position_ = buffer_size - 1;
205        return;
206      }
207    }
208  }
209
210  // Advance the iterator by the specified distance.
211  void advance(std::ptrdiff_t n)
212  {
213    if (n > 0)
214    {
215      BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
216      for (;;)
217      {
218        std::ptrdiff_t current_buffer_balance
219          = boost::asio::buffer_size(current_buffer_)
220          - current_buffer_position_;
221
222        // Check if the advance can be satisfied by the current buffer.
223        if (current_buffer_balance > n)
224        {
225          position_ += n;
226          current_buffer_position_ += n;
227          return;
228        }
229
230        // Update position.
231        n -= current_buffer_balance;
232        position_ += current_buffer_balance;
233
234        // Move to next buffer. If it is empty then it will be skipped on the
235        // next iteration of this loop.
236        if (++current_ == end_)
237        {
238          BOOST_ASSERT(n == 0 && "iterator out of bounds");
239          current_buffer_ = buffer_type();
240          current_buffer_position_ = 0;
241          return;
242        }
243        current_buffer_ = *current_;
244        current_buffer_position_ = 0;
245      }
246    }
247    else if (n < 0)
248    {
249      std::size_t abs_n = -n;
250      BOOST_ASSERT(position_ >= abs_n && "iterator out of bounds");
251      for (;;)
252      {
253        // Check if the advance can be satisfied by the current buffer.
254        if (current_buffer_position_ >= abs_n)
255        {
256          position_ -= abs_n;
257          current_buffer_position_ -= abs_n;
258          return;
259        }
260
261        // Update position.
262        abs_n -= current_buffer_position_;
263        position_ -= current_buffer_position_;
264
265        // Check if we've reached the beginning of the buffers.
266        if (current_ == begin_)
267        {
268          BOOST_ASSERT(abs_n == 0 && "iterator out of bounds");
269          current_buffer_position_ = 0;
270          return;
271        }
272
273        // Find the previous non-empty buffer.
274        typename BufferSequence::const_iterator iter = current_;
275        while (iter != begin_)
276        {
277          --iter;
278          buffer_type buffer = *iter;
279          std::size_t buffer_size = boost::asio::buffer_size(buffer);
280          if (buffer_size > 0)
281          {
282            current_ = iter;
283            current_buffer_ = buffer;
284            current_buffer_position_ = buffer_size;
285            break;
286          }
287        }
288      }
289    }
290  }
291
292  // Determine the distance between two iterators.
293  std::ptrdiff_t distance_to(const buffers_iterator& other) const
294  {
295    return other.position_ - position_;
296  }
297
298  buffer_type current_buffer_;
299  std::size_t current_buffer_position_;
300  typename BufferSequence::const_iterator begin_;
301  typename BufferSequence::const_iterator current_;
302  typename BufferSequence::const_iterator end_;
303  std::size_t position_;
304};
305
306/// Construct an iterator representing the beginning of the buffers' data.
307template <typename BufferSequence>
308inline buffers_iterator<BufferSequence> buffers_begin(
309    const BufferSequence& buffers)
310{
311  return buffers_iterator<BufferSequence>::begin(buffers);
312}
313
314/// Construct an iterator representing the end of the buffers' data.
315template <typename BufferSequence>
316inline buffers_iterator<BufferSequence> buffers_end(
317    const BufferSequence& buffers)
318{
319  return buffers_iterator<BufferSequence>::end(buffers);
320}
321
322} // namespace asio
323} // namespace boost
324
325#include <boost/asio/detail/pop_options.hpp>
326
327#endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP
Note: See TracBrowser for help on using the browser.