• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // detail/consuming_buffers.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_DETAIL_CONSUMING_BUFFERS_HPP
12 #define ASIO_DETAIL_CONSUMING_BUFFERS_HPP
13 
14 
15 #include "asio/detail/config.hpp"
16 #include <cstddef>
17 #include <iterator>
18 #include "asio/buffer.hpp"
19 #include "asio/detail/limits.hpp"
20 
21 #include "asio/detail/push_options.hpp"
22 
23 namespace asio {
24 namespace detail {
25 
26 // A proxy iterator for a sub-range in a list of buffers.
27 template <typename Buffer, typename Buffer_Iterator>
28 class consuming_buffers_iterator
29 {
30 public:
31   /// The type used for the distance between two iterators.
32   typedef std::ptrdiff_t difference_type;
33 
34   /// The type of the value pointed to by the iterator.
35   typedef Buffer value_type;
36 
37   /// The type of the result of applying operator->() to the iterator.
38   typedef const Buffer* pointer;
39 
40   /// The type of the result of applying operator*() to the iterator.
41   typedef const Buffer& reference;
42 
43   /// The iterator category.
44   typedef std::forward_iterator_tag iterator_category;
45 
46   // Default constructor creates an end iterator.
consuming_buffers_iterator()47   consuming_buffers_iterator()
48     : at_end_(true)
49   {
50   }
51 
52   // Construct with a buffer for the first entry and an iterator
53   // range for the remaining entries.
consuming_buffers_iterator(bool at_end,const Buffer & first,Buffer_Iterator begin_remainder,Buffer_Iterator end_remainder,std::size_t max_size)54   consuming_buffers_iterator(bool at_end, const Buffer& first,
55       Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder,
56       std::size_t max_size)
57     : at_end_(max_size > 0 ? at_end : true),
58       first_(buffer(first, max_size)),
59       begin_remainder_(begin_remainder),
60       end_remainder_(end_remainder),
61       offset_(0),
62       max_size_(max_size)
63   {
64   }
65 
66   // Dereference an iterator.
operator *() const67   const Buffer& operator*() const
68   {
69     return dereference();
70   }
71 
72   // Dereference an iterator.
operator ->() const73   const Buffer* operator->() const
74   {
75     return &dereference();
76   }
77 
78   // Increment operator (prefix).
operator ++()79   consuming_buffers_iterator& operator++()
80   {
81     increment();
82     return *this;
83   }
84 
85   // Increment operator (postfix).
operator ++(int)86   consuming_buffers_iterator operator++(int)
87   {
88     consuming_buffers_iterator tmp(*this);
89     ++*this;
90     return tmp;
91   }
92 
93   // Test two iterators for equality.
operator ==(const consuming_buffers_iterator & a,const consuming_buffers_iterator & b)94   friend bool operator==(const consuming_buffers_iterator& a,
95       const consuming_buffers_iterator& b)
96   {
97     return a.equal(b);
98   }
99 
100   // Test two iterators for inequality.
operator !=(const consuming_buffers_iterator & a,const consuming_buffers_iterator & b)101   friend bool operator!=(const consuming_buffers_iterator& a,
102       const consuming_buffers_iterator& b)
103   {
104     return !a.equal(b);
105   }
106 
107 private:
increment()108   void increment()
109   {
110     if (!at_end_)
111     {
112       if (begin_remainder_ == end_remainder_
113           || offset_ + buffer_size(first_) >= max_size_)
114       {
115         at_end_ = true;
116       }
117       else
118       {
119         offset_ += buffer_size(first_);
120         first_ = buffer(*begin_remainder_++, max_size_ - offset_);
121       }
122     }
123   }
124 
equal(const consuming_buffers_iterator & other) const125   bool equal(const consuming_buffers_iterator& other) const
126   {
127     if (at_end_ && other.at_end_)
128       return true;
129     return !at_end_ && !other.at_end_
130       && buffer_cast<const void*>(first_)
131         == buffer_cast<const void*>(other.first_)
132       && buffer_size(first_) == buffer_size(other.first_)
133       && begin_remainder_ == other.begin_remainder_
134       && end_remainder_ == other.end_remainder_;
135   }
136 
dereference() const137   const Buffer& dereference() const
138   {
139     return first_;
140   }
141 
142   bool at_end_;
143   Buffer first_;
144   Buffer_Iterator begin_remainder_;
145   Buffer_Iterator end_remainder_;
146   std::size_t offset_;
147   std::size_t max_size_;
148 };
149 
150 // A proxy for a sub-range in a list of buffers.
151 template <typename Buffer, typename Buffers>
152 class consuming_buffers
153 {
154 public:
155   // The type for each element in the list of buffers.
156   typedef Buffer value_type;
157 
158   // A forward-only iterator type that may be used to read elements.
159   typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator>
160     const_iterator;
161 
162   // Construct to represent the entire list of buffers.
consuming_buffers(const Buffers & buffers)163   consuming_buffers(const Buffers& buffers)
164     : buffers_(buffers),
165       at_end_(buffers_.begin() == buffers_.end()),
166       begin_remainder_(buffers_.begin()),
167       max_size_((std::numeric_limits<std::size_t>::max)())
168   {
169     if (!at_end_)
170     {
171       first_ = *buffers_.begin();
172       ++begin_remainder_;
173     }
174   }
175 
176   // Copy constructor.
consuming_buffers(const consuming_buffers & other)177   consuming_buffers(const consuming_buffers& other)
178     : buffers_(other.buffers_),
179       at_end_(other.at_end_),
180       first_(other.first_),
181       begin_remainder_(buffers_.begin()),
182       max_size_(other.max_size_)
183   {
184     typename Buffers::const_iterator first = other.buffers_.begin();
185     typename Buffers::const_iterator second = other.begin_remainder_;
186     std::advance(begin_remainder_, std::distance(first, second));
187   }
188 
189   // Assignment operator.
operator =(const consuming_buffers & other)190   consuming_buffers& operator=(const consuming_buffers& other)
191   {
192     buffers_ = other.buffers_;
193     at_end_ = other.at_end_;
194     first_ = other.first_;
195     begin_remainder_ = buffers_.begin();
196     typename Buffers::const_iterator first = other.buffers_.begin();
197     typename Buffers::const_iterator second = other.begin_remainder_;
198     std::advance(begin_remainder_, std::distance(first, second));
199     max_size_ = other.max_size_;
200     return *this;
201   }
202 
203   // Get a forward-only iterator to the first element.
begin() const204   const_iterator begin() const
205   {
206     return const_iterator(at_end_, first_,
207         begin_remainder_, buffers_.end(), max_size_);
208   }
209 
210   // Get a forward-only iterator for one past the last element.
end() const211   const_iterator end() const
212   {
213     return const_iterator();
214   }
215 
216   // Set the maximum size for a single transfer.
prepare(std::size_t max_size)217   void prepare(std::size_t max_size)
218   {
219     max_size_ = max_size;
220   }
221 
222   // Consume the specified number of bytes from the buffers.
consume(std::size_t size)223   void consume(std::size_t size)
224   {
225     // Remove buffers from the start until the specified size is reached.
226     while (size > 0 && !at_end_)
227     {
228       if (buffer_size(first_) <= size)
229       {
230         size -= buffer_size(first_);
231         if (begin_remainder_ == buffers_.end())
232           at_end_ = true;
233         else
234           first_ = *begin_remainder_++;
235       }
236       else
237       {
238         first_ = first_ + size;
239         size = 0;
240       }
241     }
242 
243     // Remove any more empty buffers at the start.
244     while (!at_end_ && buffer_size(first_) == 0)
245     {
246       if (begin_remainder_ == buffers_.end())
247         at_end_ = true;
248       else
249         first_ = *begin_remainder_++;
250     }
251   }
252 
253 private:
254   Buffers buffers_;
255   bool at_end_;
256   Buffer first_;
257   typename Buffers::const_iterator begin_remainder_;
258   std::size_t max_size_;
259 };
260 
261 // Specialisation for null_buffers to ensure that the null_buffers type is
262 // always passed through to the underlying read or write operation.
263 template <typename Buffer>
264 class consuming_buffers<Buffer, asio::null_buffers>
265   : public asio::null_buffers
266 {
267 public:
consuming_buffers(const asio::null_buffers &)268   consuming_buffers(const asio::null_buffers&)
269   {
270     // No-op.
271   }
272 
prepare(std::size_t)273   void prepare(std::size_t)
274   {
275     // No-op.
276   }
277 
consume(std::size_t)278   void consume(std::size_t)
279   {
280     // No-op.
281   }
282 };
283 
284 } // namespace detail
285 } // namespace asio
286 
287 #include "asio/detail/pop_options.hpp"
288 
289 #endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP
290