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         [&]
__anon47b8f1df0202null235         {
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