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