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

source code of boost/boost/asio/detail/consuming_buffers.hpp