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