]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // |
b32b8144 | 2 | // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) |
7c673cae FG |
3 | // |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
b32b8144 FG |
7 | // Official repository: https://github.com/boostorg/beast |
8 | // | |
7c673cae | 9 | |
b32b8144 FG |
10 | #ifndef BOOST_BEAST_IMPL_BUFFERS_ADAPTER_IPP |
11 | #define BOOST_BEAST_IMPL_BUFFERS_ADAPTER_IPP | |
7c673cae | 12 | |
b32b8144 | 13 | #include <boost/beast/core/detail/type_traits.hpp> |
7c673cae | 14 | #include <boost/asio/buffer.hpp> |
b32b8144 | 15 | #include <boost/throw_exception.hpp> |
7c673cae FG |
16 | #include <algorithm> |
17 | #include <cstring> | |
18 | #include <iterator> | |
19 | #include <stdexcept> | |
7c673cae | 20 | |
b32b8144 | 21 | namespace boost { |
7c673cae FG |
22 | namespace beast { |
23 | ||
24 | template<class MutableBufferSequence> | |
25 | class buffers_adapter<MutableBufferSequence>:: | |
26 | const_buffers_type | |
27 | { | |
28 | buffers_adapter const* ba_; | |
29 | ||
30 | public: | |
b32b8144 | 31 | using value_type = boost::asio::mutable_buffer; |
7c673cae FG |
32 | |
33 | class const_iterator; | |
34 | ||
35 | const_buffers_type() = delete; | |
36 | const_buffers_type( | |
37 | const_buffers_type const&) = default; | |
38 | const_buffers_type& operator=( | |
39 | const_buffers_type const&) = default; | |
40 | ||
41 | const_iterator | |
42 | begin() const; | |
43 | ||
44 | const_iterator | |
45 | end() const; | |
46 | ||
47 | private: | |
48 | friend class buffers_adapter; | |
49 | ||
50 | const_buffers_type(buffers_adapter const& ba) | |
51 | : ba_(&ba) | |
52 | { | |
53 | } | |
54 | }; | |
55 | ||
56 | template<class MutableBufferSequence> | |
57 | class buffers_adapter<MutableBufferSequence>:: | |
58 | const_buffers_type::const_iterator | |
59 | { | |
60 | iter_type it_; | |
61 | buffers_adapter const* ba_ = nullptr; | |
62 | ||
63 | public: | |
64 | using value_type = boost::asio::const_buffer; | |
65 | using pointer = value_type const*; | |
66 | using reference = value_type; | |
67 | using difference_type = std::ptrdiff_t; | |
68 | using iterator_category = | |
69 | std::bidirectional_iterator_tag; | |
70 | ||
71 | const_iterator() = default; | |
72 | const_iterator(const_iterator&& other) = default; | |
73 | const_iterator(const_iterator const& other) = default; | |
74 | const_iterator& operator=(const_iterator&& other) = default; | |
75 | const_iterator& operator=(const_iterator const& other) = default; | |
76 | ||
77 | bool | |
78 | operator==(const_iterator const& other) const | |
79 | { | |
80 | return ba_ == other.ba_ && | |
81 | it_ == other.it_; | |
82 | } | |
83 | ||
84 | bool | |
85 | operator!=(const_iterator const& other) const | |
86 | { | |
87 | return !(*this == other); | |
88 | } | |
89 | ||
90 | reference | |
91 | operator*() const | |
92 | { | |
b32b8144 FG |
93 | value_type const b = *it_; |
94 | return value_type{b.data(), | |
95 | (ba_->out_ == boost::asio::buffer_sequence_end(ba_->bs_) || | |
96 | it_ != ba_->out_) ? b.size() : ba_->out_pos_} + | |
7c673cae FG |
97 | (it_ == ba_->begin_ ? ba_->in_pos_ : 0); |
98 | } | |
99 | ||
100 | pointer | |
101 | operator->() const = delete; | |
102 | ||
103 | const_iterator& | |
104 | operator++() | |
105 | { | |
106 | ++it_; | |
107 | return *this; | |
108 | } | |
109 | ||
110 | const_iterator | |
111 | operator++(int) | |
112 | { | |
113 | auto temp = *this; | |
114 | ++(*this); | |
115 | return temp; | |
116 | } | |
117 | ||
118 | const_iterator& | |
119 | operator--() | |
120 | { | |
121 | --it_; | |
122 | return *this; | |
123 | } | |
124 | ||
125 | const_iterator | |
126 | operator--(int) | |
127 | { | |
128 | auto temp = *this; | |
129 | --(*this); | |
130 | return temp; | |
131 | } | |
132 | ||
133 | private: | |
134 | friend class const_buffers_type; | |
135 | ||
136 | const_iterator(buffers_adapter const& ba, | |
137 | iter_type iter) | |
138 | : it_(iter) | |
139 | , ba_(&ba) | |
140 | { | |
141 | } | |
142 | }; | |
143 | ||
144 | template<class MutableBufferSequence> | |
145 | inline | |
146 | auto | |
147 | buffers_adapter<MutableBufferSequence>::const_buffers_type::begin() const -> | |
148 | const_iterator | |
149 | { | |
150 | return const_iterator{*ba_, ba_->begin_}; | |
151 | } | |
152 | ||
153 | template<class MutableBufferSequence> | |
154 | inline | |
155 | auto | |
156 | buffers_adapter<MutableBufferSequence>::const_buffers_type::end() const -> | |
157 | const_iterator | |
158 | { | |
159 | return const_iterator{*ba_, ba_->out_ == | |
160 | ba_->end_ ? ba_->end_ : std::next(ba_->out_)}; | |
161 | } | |
162 | ||
163 | //------------------------------------------------------------------------------ | |
164 | ||
165 | template<class MutableBufferSequence> | |
166 | class buffers_adapter<MutableBufferSequence>:: | |
167 | mutable_buffers_type | |
168 | { | |
169 | buffers_adapter const* ba_; | |
170 | ||
171 | public: | |
172 | using value_type = boost::asio::mutable_buffer; | |
173 | ||
174 | class const_iterator; | |
175 | ||
176 | mutable_buffers_type() = delete; | |
177 | mutable_buffers_type( | |
178 | mutable_buffers_type const&) = default; | |
179 | mutable_buffers_type& operator=( | |
180 | mutable_buffers_type const&) = default; | |
181 | ||
182 | const_iterator | |
183 | begin() const; | |
184 | ||
185 | const_iterator | |
186 | end() const; | |
187 | ||
188 | private: | |
189 | friend class buffers_adapter; | |
190 | ||
191 | mutable_buffers_type( | |
192 | buffers_adapter const& ba) | |
193 | : ba_(&ba) | |
194 | { | |
195 | } | |
196 | }; | |
197 | ||
198 | template<class MutableBufferSequence> | |
199 | class buffers_adapter<MutableBufferSequence>:: | |
200 | mutable_buffers_type::const_iterator | |
201 | { | |
202 | iter_type it_; | |
203 | buffers_adapter const* ba_ = nullptr; | |
204 | ||
205 | public: | |
206 | using value_type = boost::asio::mutable_buffer; | |
207 | using pointer = value_type const*; | |
208 | using reference = value_type; | |
209 | using difference_type = std::ptrdiff_t; | |
210 | using iterator_category = | |
211 | std::bidirectional_iterator_tag; | |
212 | ||
213 | const_iterator() = default; | |
214 | const_iterator(const_iterator&& other) = default; | |
215 | const_iterator(const_iterator const& other) = default; | |
216 | const_iterator& operator=(const_iterator&& other) = default; | |
217 | const_iterator& operator=(const_iterator const& other) = default; | |
218 | ||
219 | bool | |
220 | operator==(const_iterator const& other) const | |
221 | { | |
222 | return ba_ == other.ba_ && | |
223 | it_ == other.it_; | |
224 | } | |
225 | ||
226 | bool | |
227 | operator!=(const_iterator const& other) const | |
228 | { | |
229 | return !(*this == other); | |
230 | } | |
231 | ||
232 | reference | |
233 | operator*() const | |
234 | { | |
b32b8144 FG |
235 | value_type const b = *it_; |
236 | return value_type{b.data(), | |
7c673cae | 237 | it_ == std::prev(ba_->end_) ? |
b32b8144 | 238 | ba_->out_end_ : b.size()} + |
7c673cae FG |
239 | (it_ == ba_->out_ ? ba_->out_pos_ : 0); |
240 | } | |
241 | ||
242 | pointer | |
243 | operator->() const = delete; | |
244 | ||
245 | const_iterator& | |
246 | operator++() | |
247 | { | |
248 | ++it_; | |
249 | return *this; | |
250 | } | |
251 | ||
252 | const_iterator | |
253 | operator++(int) | |
254 | { | |
255 | auto temp = *this; | |
256 | ++(*this); | |
257 | return temp; | |
258 | } | |
259 | ||
260 | const_iterator& | |
261 | operator--() | |
262 | { | |
263 | --it_; | |
264 | return *this; | |
265 | } | |
266 | ||
267 | const_iterator | |
268 | operator--(int) | |
269 | { | |
270 | auto temp = *this; | |
271 | --(*this); | |
272 | return temp; | |
273 | } | |
274 | ||
275 | private: | |
276 | friend class mutable_buffers_type; | |
277 | ||
278 | const_iterator(buffers_adapter const& ba, | |
279 | iter_type iter) | |
280 | : it_(iter) | |
281 | , ba_(&ba) | |
282 | { | |
283 | } | |
284 | }; | |
285 | ||
286 | template<class MutableBufferSequence> | |
287 | inline | |
288 | auto | |
b32b8144 FG |
289 | buffers_adapter<MutableBufferSequence>:: |
290 | mutable_buffers_type:: | |
291 | begin() const -> | |
7c673cae FG |
292 | const_iterator |
293 | { | |
294 | return const_iterator{*ba_, ba_->out_}; | |
295 | } | |
296 | ||
297 | template<class MutableBufferSequence> | |
298 | inline | |
299 | auto | |
b32b8144 FG |
300 | buffers_adapter<MutableBufferSequence>:: |
301 | mutable_buffers_type:: | |
302 | end() const -> | |
7c673cae FG |
303 | const_iterator |
304 | { | |
305 | return const_iterator{*ba_, ba_->end_}; | |
306 | } | |
307 | ||
308 | //------------------------------------------------------------------------------ | |
309 | ||
310 | template<class MutableBufferSequence> | |
311 | buffers_adapter<MutableBufferSequence>::buffers_adapter( | |
312 | buffers_adapter&& other) | |
313 | : buffers_adapter(std::move(other), | |
b32b8144 FG |
314 | std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.begin_), |
315 | std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.out_), | |
316 | std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.end_)) | |
7c673cae FG |
317 | { |
318 | } | |
319 | ||
320 | template<class MutableBufferSequence> | |
321 | buffers_adapter<MutableBufferSequence>::buffers_adapter( | |
322 | buffers_adapter const& other) | |
323 | : buffers_adapter(other, | |
b32b8144 FG |
324 | std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.begin_), |
325 | std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.out_), | |
326 | std::distance<iter_type>(boost::asio::buffer_sequence_begin(other.bs_), other.end_)) | |
7c673cae FG |
327 | { |
328 | } | |
329 | ||
330 | template<class MutableBufferSequence> | |
331 | auto | |
332 | buffers_adapter<MutableBufferSequence>::operator=( | |
333 | buffers_adapter&& other) -> buffers_adapter& | |
334 | { | |
335 | auto const nbegin = std::distance<iter_type>( | |
b32b8144 FG |
336 | boost::asio::buffer_sequence_begin(other.bs_), |
337 | other.begin_); | |
7c673cae | 338 | auto const nout = std::distance<iter_type>( |
b32b8144 FG |
339 | boost::asio::buffer_sequence_begin(other.bs_), |
340 | other.out_); | |
7c673cae | 341 | auto const nend = std::distance<iter_type>( |
b32b8144 FG |
342 | boost::asio::buffer_sequence_begin(other.bs_), |
343 | other.end_); | |
7c673cae | 344 | bs_ = std::move(other.bs_); |
b32b8144 FG |
345 | begin_ = std::next(boost::asio::buffer_sequence_begin(bs_), nbegin); |
346 | out_ = std::next(boost::asio::buffer_sequence_begin(bs_), nout); | |
347 | end_ = std::next(boost::asio::buffer_sequence_begin(bs_), nend); | |
7c673cae FG |
348 | max_size_ = other.max_size_; |
349 | in_pos_ = other.in_pos_; | |
350 | in_size_ = other.in_size_; | |
351 | out_pos_ = other.out_pos_; | |
352 | out_end_ = other.out_end_; | |
353 | return *this; | |
354 | } | |
355 | ||
356 | template<class MutableBufferSequence> | |
357 | auto | |
358 | buffers_adapter<MutableBufferSequence>::operator=( | |
359 | buffers_adapter const& other) -> buffers_adapter& | |
360 | { | |
361 | auto const nbegin = std::distance<iter_type>( | |
b32b8144 FG |
362 | boost::asio::buffer_sequence_begin(other.bs_), |
363 | other.begin_); | |
7c673cae | 364 | auto const nout = std::distance<iter_type>( |
b32b8144 FG |
365 | boost::asio::buffer_sequence_begin(other.bs_), |
366 | other.out_); | |
7c673cae | 367 | auto const nend = std::distance<iter_type>( |
b32b8144 FG |
368 | boost::asio::buffer_sequence_begin(other.bs_), |
369 | other.end_); | |
7c673cae | 370 | bs_ = other.bs_; |
b32b8144 FG |
371 | begin_ = std::next(boost::asio::buffer_sequence_begin(bs_), nbegin); |
372 | out_ = std::next(boost::asio::buffer_sequence_begin(bs_), nout); | |
373 | end_ = std::next(boost::asio::buffer_sequence_begin(bs_), nend); | |
7c673cae FG |
374 | max_size_ = other.max_size_; |
375 | in_pos_ = other.in_pos_; | |
376 | in_size_ = other.in_size_; | |
377 | out_pos_ = other.out_pos_; | |
378 | out_end_ = other.out_end_; | |
379 | return *this; | |
380 | } | |
381 | ||
382 | template<class MutableBufferSequence> | |
383 | buffers_adapter<MutableBufferSequence>::buffers_adapter( | |
384 | MutableBufferSequence const& bs) | |
385 | : bs_(bs) | |
b32b8144 FG |
386 | , begin_(boost::asio::buffer_sequence_begin(bs_)) |
387 | , out_ (boost::asio::buffer_sequence_begin(bs_)) | |
388 | , end_ (boost::asio::buffer_sequence_begin(bs_)) | |
7c673cae FG |
389 | , max_size_(boost::asio::buffer_size(bs_)) |
390 | { | |
391 | } | |
392 | ||
393 | template<class MutableBufferSequence> | |
394 | auto | |
395 | buffers_adapter<MutableBufferSequence>::prepare(std::size_t n) -> | |
396 | mutable_buffers_type | |
397 | { | |
398 | using boost::asio::buffer_size; | |
399 | end_ = out_; | |
b32b8144 | 400 | if(end_ != boost::asio::buffer_sequence_end(bs_)) |
7c673cae FG |
401 | { |
402 | auto size = buffer_size(*end_) - out_pos_; | |
403 | if(n > size) | |
404 | { | |
405 | n -= size; | |
b32b8144 FG |
406 | while(++end_ != |
407 | boost::asio::buffer_sequence_end(bs_)) | |
7c673cae FG |
408 | { |
409 | size = buffer_size(*end_); | |
410 | if(n < size) | |
411 | { | |
412 | out_end_ = n; | |
413 | n = 0; | |
414 | ++end_; | |
415 | break; | |
416 | } | |
417 | n -= size; | |
418 | out_end_ = size; | |
419 | } | |
420 | } | |
421 | else | |
422 | { | |
423 | ++end_; | |
424 | out_end_ = out_pos_ + n; | |
425 | n = 0; | |
426 | } | |
427 | } | |
428 | if(n > 0) | |
b32b8144 FG |
429 | BOOST_THROW_EXCEPTION(std::length_error{ |
430 | "buffer overflow"}); | |
7c673cae FG |
431 | return mutable_buffers_type{*this}; |
432 | } | |
433 | ||
434 | template<class MutableBufferSequence> | |
435 | void | |
436 | buffers_adapter<MutableBufferSequence>::commit(std::size_t n) | |
437 | { | |
438 | using boost::asio::buffer_size; | |
439 | if(out_ == end_) | |
440 | return; | |
441 | auto const last = std::prev(end_); | |
442 | while(out_ != last) | |
443 | { | |
444 | auto const avail = | |
445 | buffer_size(*out_) - out_pos_; | |
446 | if(n < avail) | |
447 | { | |
448 | out_pos_ += n; | |
449 | in_size_ += n; | |
450 | max_size_ -= n; | |
451 | return; | |
452 | } | |
453 | ++out_; | |
454 | n -= avail; | |
455 | out_pos_ = 0; | |
456 | in_size_ += avail; | |
457 | max_size_ -= avail; | |
458 | } | |
459 | ||
460 | n = (std::min)(n, out_end_ - out_pos_); | |
461 | out_pos_ += n; | |
462 | in_size_ += n; | |
463 | max_size_ -= n; | |
464 | if(out_pos_ == buffer_size(*out_)) | |
465 | { | |
466 | ++out_; | |
467 | out_pos_ = 0; | |
468 | out_end_ = 0; | |
469 | } | |
470 | } | |
471 | ||
472 | template<class MutableBufferSequence> | |
473 | inline | |
474 | auto | |
475 | buffers_adapter<MutableBufferSequence>::data() const -> | |
476 | const_buffers_type | |
477 | { | |
478 | return const_buffers_type{*this}; | |
479 | } | |
480 | ||
481 | template<class MutableBufferSequence> | |
482 | void | |
483 | buffers_adapter<MutableBufferSequence>::consume(std::size_t n) | |
484 | { | |
485 | using boost::asio::buffer_size; | |
486 | while(begin_ != out_) | |
487 | { | |
488 | auto const avail = | |
489 | buffer_size(*begin_) - in_pos_; | |
490 | if(n < avail) | |
491 | { | |
492 | in_size_ -= n; | |
493 | in_pos_ += n; | |
494 | return; | |
495 | } | |
496 | n -= avail; | |
497 | in_size_ -= avail; | |
498 | in_pos_ = 0; | |
499 | ++begin_; | |
500 | } | |
501 | auto const avail = out_pos_ - in_pos_; | |
502 | if(n < avail) | |
503 | { | |
504 | in_size_ -= n; | |
505 | in_pos_ += n; | |
506 | } | |
507 | else | |
508 | { | |
509 | in_size_ -= avail; | |
510 | in_pos_ = out_pos_; | |
511 | } | |
512 | } | |
513 | ||
514 | } // beast | |
b32b8144 | 515 | } // boost |
7c673cae FG |
516 | |
517 | #endif |