1//
2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
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//
7// Official repository: https://github.com/boostorg/beast
8//
9
10#ifndef BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
11#define BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
12
13#include <boost/beast/core/buffer_traits.hpp>
14#include <boost/beast/core/buffers_adaptor.hpp>
15#include <boost/asio/buffer.hpp>
16#include <boost/config/workaround.hpp>
17#include <boost/throw_exception.hpp>
18#include <algorithm>
19#include <cstring>
20#include <iterator>
21#include <stdexcept>
22#include <type_traits>
23#include <utility>
24
25namespace boost {
26namespace beast {
27
28//------------------------------------------------------------------------------
29
30#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
31# pragma warning (push)
32# pragma warning (disable: 4521) // multiple copy constructors specified
33# pragma warning (disable: 4522) // multiple assignment operators specified
34#endif
35
36template<class MutableBufferSequence>
37template<bool isMutable>
38class buffers_adaptor<MutableBufferSequence>::subrange
39{
40public:
41 using value_type = typename std::conditional<
42 isMutable,
43 net::mutable_buffer,
44 net::const_buffer>::type;
45
46 struct iterator;
47 using const_iterator = iterator;
48
49 // construct from two iterators plus optionally subrange definition
50 subrange(
51 iter_type first, // iterator to first buffer in storage
52 iter_type last, // iterator to last buffer in storage
53 std::size_t pos = 0, // the offset in bytes from the beginning of the storage
54 std::size_t n = // the total length of the subrange
55 (std::numeric_limits<std::size_t>::max)());
56
57#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
58 subrange(
59 subrange const& other)
60 : first_(other.first_)
61 , last_(other.last_)
62 , first_offset_(other.first_offset_)
63 , last_size_(other.last_size_)
64 {
65 }
66
67 subrange& operator=(
68 subrange const& other)
69 {
70 first_ = other.first_;
71 last_ = other.last_;
72 first_offset_ = other.first_offset_;
73 last_size_ = other.last_size_;
74 return *this;
75 }
76#else
77 subrange(
78 subrange const&) = default;
79 subrange& operator=(
80 subrange const&) = default;
81#endif
82
83 // allow conversion from mutable to const
84 template<bool isMutable_ = isMutable, typename
85 std::enable_if<!isMutable_>::type * = nullptr>
86 subrange(subrange<true> const &other)
87 : first_(other.first_)
88 , last_(other.last_)
89 , first_offset_(other.first_offset_)
90 , last_size_(other.last_size_)
91 {
92 }
93
94 iterator
95 begin() const;
96
97 iterator
98 end() const;
99
100private:
101
102 friend subrange<!isMutable>;
103
104 void
105 adjust(
106 std::size_t pos,
107 std::size_t n);
108
109private:
110 // points to the first buffer in the sequence
111 iter_type first_;
112
113 // Points to one past the end of the underlying buffer sequence
114 iter_type last_;
115
116 // The initial offset into the first buffer
117 std::size_t first_offset_;
118
119 // how many bytes in the penultimate buffer are used (if any)
120 std::size_t last_size_;
121};
122
123#if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
124# pragma warning (pop)
125#endif
126
127//------------------------------------------------------------------------------
128
129template<class MutableBufferSequence>
130template<bool isMutable>
131struct buffers_adaptor<MutableBufferSequence>::
132 subrange<isMutable>::
133 iterator
134{
135 using iterator_category = std::bidirectional_iterator_tag;
136 using value_type = typename
137 buffers_adaptor<MutableBufferSequence>::
138 template subrange<isMutable>::
139 value_type;
140 using reference = value_type&;
141 using pointer = value_type*;
142 using difference_type = std::ptrdiff_t;
143
144 iterator(
145 subrange<isMutable> const *parent,
146 iter_type it);
147
148 iterator();
149
150 value_type
151 operator*() const;
152
153 pointer
154 operator->() const = delete;
155
156 iterator &
157 operator++();
158
159 iterator
160 operator++(int);
161
162 iterator &
163 operator--();
164
165 iterator
166 operator--(int);
167
168 bool
169 operator==(iterator const &b) const;
170
171 bool
172 operator!=(iterator const &b) const;
173
174private:
175
176 subrange<isMutable> const *parent_;
177 iter_type it_;
178};
179
180//------------------------------------------------------------------------------
181
182template<class MutableBufferSequence>
183auto
184buffers_adaptor<MutableBufferSequence>::
185end_impl() const ->
186 iter_type
187{
188 return out_ == end_ ? end_ : std::next(out_);
189}
190
191template<class MutableBufferSequence>
192buffers_adaptor<MutableBufferSequence>::
193buffers_adaptor(
194 buffers_adaptor const& other,
195 std::size_t nbegin,
196 std::size_t nout,
197 std::size_t nend)
198 : bs_(other.bs_)
199 , begin_(std::next(net::buffer_sequence_begin(bs_), nbegin))
200 , out_(std::next(net::buffer_sequence_begin(bs_), nout))
201 , end_(std::next(net::buffer_sequence_begin(bs_), nend))
202 , max_size_(other.max_size_)
203 , in_pos_(other.in_pos_)
204 , in_size_(other.in_size_)
205 , out_pos_(other.out_pos_)
206 , out_end_(other.out_end_)
207{
208}
209
210template<class MutableBufferSequence>
211buffers_adaptor<MutableBufferSequence>::
212buffers_adaptor(MutableBufferSequence const& bs)
213 : bs_(bs)
214 , begin_(net::buffer_sequence_begin(bs_))
215 , out_ (net::buffer_sequence_begin(bs_))
216 , end_ (net::buffer_sequence_begin(bs_))
217 , max_size_(
218 [&bs]
219 {
220 return buffer_bytes(bs);
221 }())
222{
223}
224
225template<class MutableBufferSequence>
226template<class... Args>
227buffers_adaptor<MutableBufferSequence>::
228buffers_adaptor(
229 boost::in_place_init_t, Args&&... args)
230 : bs_{std::forward<Args>(args)...}
231 , begin_(net::buffer_sequence_begin(bs_))
232 , out_ (net::buffer_sequence_begin(bs_))
233 , end_ (net::buffer_sequence_begin(bs_))
234 , max_size_(
235 [&]
236 {
237 return buffer_bytes(bs_);
238 }())
239{
240}
241
242template<class MutableBufferSequence>
243buffers_adaptor<MutableBufferSequence>::
244buffers_adaptor(buffers_adaptor const& other)
245 : buffers_adaptor(
246 other,
247 std::distance<iter_type>(
248 net::buffer_sequence_begin(other.bs_),
249 other.begin_),
250 std::distance<iter_type>(
251 net::buffer_sequence_begin(other.bs_),
252 other.out_),
253 std::distance<iter_type>(
254 net::buffer_sequence_begin(other.bs_),
255 other.end_))
256{
257}
258
259template<class MutableBufferSequence>
260auto
261buffers_adaptor<MutableBufferSequence>::
262operator=(buffers_adaptor const& other) ->
263 buffers_adaptor&
264{
265 if(this == &other)
266 return *this;
267 auto const nbegin = std::distance<iter_type>(
268 net::buffer_sequence_begin(other.bs_),
269 other.begin_);
270 auto const nout = std::distance<iter_type>(
271 net::buffer_sequence_begin(other.bs_),
272 other.out_);
273 auto const nend = std::distance<iter_type>(
274 net::buffer_sequence_begin(other.bs_),
275 other.end_);
276 bs_ = other.bs_;
277 begin_ = std::next(
278 net::buffer_sequence_begin(bs_), nbegin);
279 out_ = std::next(
280 net::buffer_sequence_begin(bs_), nout);
281 end_ = std::next(
282 net::buffer_sequence_begin(bs_), nend);
283 max_size_ = other.max_size_;
284 in_pos_ = other.in_pos_;
285 in_size_ = other.in_size_;
286 out_pos_ = other.out_pos_;
287 out_end_ = other.out_end_;
288 return *this;
289}
290
291//
292
293template<class MutableBufferSequence>
294auto
295buffers_adaptor<MutableBufferSequence>::
296data() const noexcept ->
297 const_buffers_type
298{
299 return const_buffers_type(
300 begin_, end_,
301 in_pos_, in_size_);
302}
303
304template<class MutableBufferSequence>
305auto
306buffers_adaptor<MutableBufferSequence>::
307data() noexcept ->
308 mutable_buffers_type
309{
310 return mutable_buffers_type(
311 begin_, end_,
312 in_pos_, in_size_);
313}
314
315template<class MutableBufferSequence>
316auto
317buffers_adaptor<MutableBufferSequence>::
318prepare(std::size_t n) ->
319 mutable_buffers_type
320{
321 auto prepared = n;
322 end_ = out_;
323 if(end_ != net::buffer_sequence_end(bs_))
324 {
325 auto size = buffer_bytes(*end_) - out_pos_;
326 if(n > size)
327 {
328 n -= size;
329 while(++end_ !=
330 net::buffer_sequence_end(bs_))
331 {
332 size = buffer_bytes(*end_);
333 if(n < size)
334 {
335 out_end_ = n;
336 n = 0;
337 ++end_;
338 break;
339 }
340 n -= size;
341 out_end_ = size;
342 }
343 }
344 else
345 {
346 ++end_;
347 out_end_ = out_pos_ + n;
348 n = 0;
349 }
350 }
351 if(n > 0)
352 BOOST_THROW_EXCEPTION(std::length_error{
353 "buffers_adaptor too long"});
354 return mutable_buffers_type(out_, end_, out_pos_, prepared);
355}
356
357template<class MutableBufferSequence>
358void
359buffers_adaptor<MutableBufferSequence>::
360commit(std::size_t n) noexcept
361{
362 if(out_ == end_)
363 return;
364 auto const last = std::prev(end_);
365 while(out_ != last)
366 {
367 auto const avail =
368 buffer_bytes(*out_) - out_pos_;
369 if(n < avail)
370 {
371 out_pos_ += n;
372 in_size_ += n;
373 return;
374 }
375 ++out_;
376 n -= avail;
377 out_pos_ = 0;
378 in_size_ += avail;
379 }
380
381 n = std::min<std::size_t>(
382 a: n, b: out_end_ - out_pos_);
383 out_pos_ += n;
384 in_size_ += n;
385 if(out_pos_ == buffer_bytes(*out_))
386 {
387 ++out_;
388 out_pos_ = 0;
389 out_end_ = 0;
390 }
391}
392
393template<class MutableBufferSequence>
394void
395buffers_adaptor<MutableBufferSequence>::
396consume(std::size_t n) noexcept
397{
398 while(begin_ != out_)
399 {
400 auto const avail =
401 buffer_bytes(*begin_) - in_pos_;
402 if(n < avail)
403 {
404 in_size_ -= n;
405 in_pos_ += n;
406 return;
407 }
408 n -= avail;
409 in_size_ -= avail;
410 in_pos_ = 0;
411 ++begin_;
412 }
413 auto const avail = out_pos_ - in_pos_;
414 if(n < avail)
415 {
416 in_size_ -= n;
417 in_pos_ += n;
418 }
419 else
420 {
421 in_size_ -= avail;
422 in_pos_ = out_pos_;
423 }
424}
425
426template<class MutableBufferSequence>
427auto
428buffers_adaptor<MutableBufferSequence>::
429 make_subrange(std::size_t pos, std::size_t n) ->
430 subrange<true>
431{
432 return subrange<true>(
433 begin_, net::buffer_sequence_end(bs_),
434 in_pos_ + pos, n);
435}
436
437template<class MutableBufferSequence>
438auto
439buffers_adaptor<MutableBufferSequence>::
440 make_subrange(std::size_t pos, std::size_t n) const ->
441 subrange<false>
442{
443 return subrange<false>(
444 begin_, net::buffer_sequence_end(bs_),
445 in_pos_ + pos, n);
446}
447
448// -------------------------------------------------------------------------
449// subrange
450
451template<class MutableBufferSequence>
452template<bool isMutable>
453buffers_adaptor<MutableBufferSequence>::
454subrange<isMutable>::
455subrange(
456 iter_type first, // iterator to first buffer in storage
457 iter_type last, // iterator to last buffer in storage
458 std::size_t pos, // the offset in bytes from the beginning of the storage
459 std::size_t n) // the total length of the subrange
460 : first_(first)
461 , last_(last)
462 , first_offset_(0)
463 , last_size_((std::numeric_limits<std::size_t>::max)())
464{
465 adjust(pos, n);
466}
467
468template<class MutableBufferSequence>
469template<bool isMutable>
470void
471buffers_adaptor<MutableBufferSequence>::
472 subrange<isMutable>::
473adjust(
474 std::size_t pos,
475 std::size_t n)
476{
477 if (n == 0)
478 last_ = first_;
479
480 if (first_ == last_)
481 {
482 first_offset_ = 0;
483 last_size_ = 0;
484 return;
485 }
486
487 auto is_last = [this](iter_type iter) {
488 return std::next(iter) == last_;
489 };
490
491
492 pos += first_offset_;
493 while (pos)
494 {
495 auto adjust = (std::min)(pos, first_->size());
496 if (adjust >= first_->size())
497 {
498 ++first_;
499 first_offset_ = 0;
500 pos -= adjust;
501 }
502 else
503 {
504 first_offset_ = adjust;
505 pos = 0;
506 break;
507 }
508 }
509
510 auto current = first_;
511 auto max_elem = current->size() - first_offset_;
512 if (is_last(current))
513 {
514 // both first and last element
515 last_size_ = (std::min)(max_elem, n);
516 last_ = std::next(current);
517 return;
518 }
519 else if (max_elem >= n)
520 {
521 last_ = std::next(current);
522 last_size_ = n;
523 }
524 else
525 {
526 n -= max_elem;
527 ++current;
528 }
529
530 for (;;)
531 {
532 max_elem = current->size();
533 if (is_last(current))
534 {
535 last_size_ = (std::min)(a: n, b: last_size_);
536 return;
537 }
538 else if (max_elem < n)
539 {
540 n -= max_elem;
541 ++current;
542 }
543 else
544 {
545 last_size_ = n;
546 last_ = std::next(current);
547 return;
548 }
549 }
550}
551
552
553template<class MutableBufferSequence>
554template<bool isMutable>
555auto
556buffers_adaptor<MutableBufferSequence>::
557 subrange<isMutable>::
558begin() const ->
559iterator
560{
561 return iterator(this, first_);
562}
563
564template<class MutableBufferSequence>
565template<bool isMutable>
566auto
567buffers_adaptor<MutableBufferSequence>::
568 subrange<isMutable>::
569end() const ->
570iterator
571{
572 return iterator(this, last_);
573}
574
575// -------------------------------------------------------------------------
576// buffers_adaptor::subrange::iterator
577
578template<class MutableBufferSequence>
579template<bool isMutable>
580buffers_adaptor<MutableBufferSequence>::
581subrange<isMutable>::
582iterator::
583iterator()
584 : parent_(nullptr)
585 , it_()
586{
587}
588
589template<class MutableBufferSequence>
590template<bool isMutable>
591buffers_adaptor<MutableBufferSequence>::
592subrange<isMutable>::
593iterator::
594iterator(subrange<isMutable> const *parent,
595 iter_type it)
596 : parent_(parent)
597 , it_(it)
598{
599}
600
601template<class MutableBufferSequence>
602template<bool isMutable>
603auto
604buffers_adaptor<MutableBufferSequence>::
605 subrange<isMutable>::
606 iterator::
607operator*() const ->
608 value_type
609{
610 value_type result = *it_;
611
612 if (it_ == parent_->first_)
613 result += parent_->first_offset_;
614
615 if (std::next(it_) == parent_->last_)
616 {
617 result = value_type(
618 result.data(),
619 (std::min)(
620 parent_->last_size_,
621 result.size()));
622 }
623
624 return result;
625}
626
627template<class MutableBufferSequence>
628template<bool isMutable>
629auto
630buffers_adaptor<MutableBufferSequence>::
631 subrange<isMutable>::
632 iterator::
633operator++() ->
634 iterator &
635{
636 ++it_;
637 return *this;
638}
639
640template<class MutableBufferSequence>
641template<bool isMutable>
642auto
643buffers_adaptor<MutableBufferSequence>::
644 subrange<isMutable>::
645 iterator::
646operator++(int) ->
647 iterator
648{
649 auto result = *this;
650 ++it_;
651 return result;
652}
653
654template<class MutableBufferSequence>
655template<bool isMutable>
656auto
657buffers_adaptor<MutableBufferSequence>::
658 subrange<isMutable>::
659 iterator::
660operator--() ->
661 iterator &
662{
663 --it_;
664 return *this;
665}
666
667template<class MutableBufferSequence>
668template<bool isMutable>
669auto
670buffers_adaptor<MutableBufferSequence>::
671 subrange<isMutable>::
672 iterator::
673operator--(int) ->
674 iterator
675{
676 auto result = *this;
677 --it_;
678 return result;
679}
680
681template<class MutableBufferSequence>
682template<bool isMutable>
683auto
684buffers_adaptor<MutableBufferSequence>::
685 subrange<isMutable>::
686 iterator::
687operator==(iterator const &b) const ->
688 bool
689{
690 return it_ == b.it_;
691}
692
693template<class MutableBufferSequence>
694template<bool isMutable>
695auto
696buffers_adaptor<MutableBufferSequence>::
697 subrange<isMutable>::
698 iterator::
699operator!=(iterator const &b) const ->
700 bool
701{
702 return !(*this == b);
703}
704
705} // beast
706} // boost
707
708#endif
709

source code of boost/libs/beast/include/boost/beast/core/impl/buffers_adaptor.hpp