File indexing completed on 2025-07-15 08:28:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
0011 #define BOOST_BEAST_IMPL_BUFFERS_ADAPTOR_HPP
0012
0013 #include <boost/beast/core/buffer_traits.hpp>
0014 #include <boost/beast/core/buffers_adaptor.hpp>
0015 #include <boost/asio/buffer.hpp>
0016 #include <boost/config/workaround.hpp>
0017 #include <boost/throw_exception.hpp>
0018 #include <algorithm>
0019 #include <cstring>
0020 #include <iterator>
0021 #include <stdexcept>
0022 #include <type_traits>
0023 #include <utility>
0024
0025 namespace boost {
0026 namespace beast {
0027
0028
0029
0030 #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
0031 # pragma warning (push)
0032 # pragma warning (disable: 4521)
0033 # pragma warning (disable: 4522)
0034 #endif
0035
0036 template<class MutableBufferSequence>
0037 template<bool isMutable>
0038 class buffers_adaptor<MutableBufferSequence>::subrange
0039 {
0040 public:
0041 using value_type = typename std::conditional<
0042 isMutable,
0043 net::mutable_buffer,
0044 net::const_buffer>::type;
0045
0046 struct iterator;
0047 using const_iterator = iterator;
0048
0049
0050 subrange(
0051 iter_type first,
0052 iter_type last,
0053 std::size_t pos = 0,
0054 std::size_t n =
0055 (std::numeric_limits<std::size_t>::max)());
0056
0057 #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
0058 subrange(
0059 subrange const& other)
0060 : first_(other.first_)
0061 , last_(other.last_)
0062 , first_offset_(other.first_offset_)
0063 , last_size_(other.last_size_)
0064 {
0065 }
0066
0067 subrange& operator=(
0068 subrange const& other)
0069 {
0070 first_ = other.first_;
0071 last_ = other.last_;
0072 first_offset_ = other.first_offset_;
0073 last_size_ = other.last_size_;
0074 return *this;
0075 }
0076 #else
0077 subrange(
0078 subrange const&) = default;
0079 subrange& operator=(
0080 subrange const&) = default;
0081 #endif
0082
0083
0084 template<bool isMutable_ = isMutable, typename
0085 std::enable_if<!isMutable_>::type * = nullptr>
0086 subrange(subrange<true> const &other)
0087 : first_(other.first_)
0088 , last_(other.last_)
0089 , first_offset_(other.first_offset_)
0090 , last_size_(other.last_size_)
0091 {
0092 }
0093
0094 iterator
0095 begin() const;
0096
0097 iterator
0098 end() const;
0099
0100 private:
0101
0102 friend subrange<!isMutable>;
0103
0104 void
0105 adjust(
0106 std::size_t pos,
0107 std::size_t n);
0108
0109 private:
0110
0111 iter_type first_;
0112
0113
0114 iter_type last_;
0115
0116
0117 std::size_t first_offset_;
0118
0119
0120 std::size_t last_size_;
0121 };
0122
0123 #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
0124 # pragma warning (pop)
0125 #endif
0126
0127
0128
0129 template<class MutableBufferSequence>
0130 template<bool isMutable>
0131 struct buffers_adaptor<MutableBufferSequence>::
0132 subrange<isMutable>::
0133 iterator
0134 {
0135 using iterator_category = std::bidirectional_iterator_tag;
0136 using value_type = typename
0137 buffers_adaptor<MutableBufferSequence>::
0138 template subrange<isMutable>::
0139 value_type;
0140 using reference = value_type&;
0141 using pointer = value_type*;
0142 using difference_type = std::ptrdiff_t;
0143
0144 iterator(
0145 subrange<isMutable> const *parent,
0146 iter_type it);
0147
0148 iterator();
0149
0150 value_type
0151 operator*() const;
0152
0153 pointer
0154 operator->() const = delete;
0155
0156 iterator &
0157 operator++();
0158
0159 iterator
0160 operator++(int);
0161
0162 iterator &
0163 operator--();
0164
0165 iterator
0166 operator--(int);
0167
0168 bool
0169 operator==(iterator const &b) const;
0170
0171 bool
0172 operator!=(iterator const &b) const;
0173
0174 private:
0175
0176 subrange<isMutable> const *parent_;
0177 iter_type it_;
0178 };
0179
0180
0181
0182 template<class MutableBufferSequence>
0183 auto
0184 buffers_adaptor<MutableBufferSequence>::
0185 end_impl() const ->
0186 iter_type
0187 {
0188 return out_ == end_ ? end_ : std::next(out_);
0189 }
0190
0191 template<class MutableBufferSequence>
0192 buffers_adaptor<MutableBufferSequence>::
0193 buffers_adaptor(
0194 buffers_adaptor const& other,
0195 std::size_t nbegin,
0196 std::size_t nout,
0197 std::size_t nend)
0198 : bs_(other.bs_)
0199 , begin_(std::next(net::buffer_sequence_begin(bs_), nbegin))
0200 , out_(std::next(net::buffer_sequence_begin(bs_), nout))
0201 , end_(std::next(net::buffer_sequence_begin(bs_), nend))
0202 , max_size_(other.max_size_)
0203 , in_pos_(other.in_pos_)
0204 , in_size_(other.in_size_)
0205 , out_pos_(other.out_pos_)
0206 , out_end_(other.out_end_)
0207 {
0208 }
0209
0210 template<class MutableBufferSequence>
0211 buffers_adaptor<MutableBufferSequence>::
0212 buffers_adaptor(MutableBufferSequence const& bs)
0213 : bs_(bs)
0214 , begin_(net::buffer_sequence_begin(bs_))
0215 , out_ (net::buffer_sequence_begin(bs_))
0216 , end_ (net::buffer_sequence_begin(bs_))
0217 , max_size_(
0218 [&bs]
0219 {
0220 return buffer_bytes(bs);
0221 }())
0222 {
0223 }
0224
0225 template<class MutableBufferSequence>
0226 template<class... Args>
0227 buffers_adaptor<MutableBufferSequence>::
0228 buffers_adaptor(
0229 boost::in_place_init_t, Args&&... args)
0230 : bs_{std::forward<Args>(args)...}
0231 , begin_(net::buffer_sequence_begin(bs_))
0232 , out_ (net::buffer_sequence_begin(bs_))
0233 , end_ (net::buffer_sequence_begin(bs_))
0234 , max_size_(
0235 [&]
0236 {
0237 return buffer_bytes(bs_);
0238 }())
0239 {
0240 }
0241
0242 template<class MutableBufferSequence>
0243 buffers_adaptor<MutableBufferSequence>::
0244 buffers_adaptor(buffers_adaptor const& other)
0245 : buffers_adaptor(
0246 other,
0247 std::distance<iter_type>(
0248 net::buffer_sequence_begin(other.bs_),
0249 other.begin_),
0250 std::distance<iter_type>(
0251 net::buffer_sequence_begin(other.bs_),
0252 other.out_),
0253 std::distance<iter_type>(
0254 net::buffer_sequence_begin(other.bs_),
0255 other.end_))
0256 {
0257 }
0258
0259 template<class MutableBufferSequence>
0260 auto
0261 buffers_adaptor<MutableBufferSequence>::
0262 operator=(buffers_adaptor const& other) ->
0263 buffers_adaptor&
0264 {
0265 if(this == &other)
0266 return *this;
0267 auto const nbegin = std::distance<iter_type>(
0268 net::buffer_sequence_begin(other.bs_),
0269 other.begin_);
0270 auto const nout = std::distance<iter_type>(
0271 net::buffer_sequence_begin(other.bs_),
0272 other.out_);
0273 auto const nend = std::distance<iter_type>(
0274 net::buffer_sequence_begin(other.bs_),
0275 other.end_);
0276 bs_ = other.bs_;
0277 begin_ = std::next(
0278 net::buffer_sequence_begin(bs_), nbegin);
0279 out_ = std::next(
0280 net::buffer_sequence_begin(bs_), nout);
0281 end_ = std::next(
0282 net::buffer_sequence_begin(bs_), nend);
0283 max_size_ = other.max_size_;
0284 in_pos_ = other.in_pos_;
0285 in_size_ = other.in_size_;
0286 out_pos_ = other.out_pos_;
0287 out_end_ = other.out_end_;
0288 return *this;
0289 }
0290
0291
0292
0293 template<class MutableBufferSequence>
0294 auto
0295 buffers_adaptor<MutableBufferSequence>::
0296 data() const noexcept ->
0297 const_buffers_type
0298 {
0299 return const_buffers_type(
0300 begin_, end_,
0301 in_pos_, in_size_);
0302 }
0303
0304 template<class MutableBufferSequence>
0305 auto
0306 buffers_adaptor<MutableBufferSequence>::
0307 data() noexcept ->
0308 mutable_buffers_type
0309 {
0310 return mutable_buffers_type(
0311 begin_, end_,
0312 in_pos_, in_size_);
0313 }
0314
0315 template<class MutableBufferSequence>
0316 auto
0317 buffers_adaptor<MutableBufferSequence>::
0318 prepare(std::size_t n) ->
0319 mutable_buffers_type
0320 {
0321 auto prepared = n;
0322 end_ = out_;
0323 if(end_ != net::buffer_sequence_end(bs_))
0324 {
0325 auto size = buffer_bytes(*end_) - out_pos_;
0326 if(n > size)
0327 {
0328 n -= size;
0329 while(++end_ !=
0330 net::buffer_sequence_end(bs_))
0331 {
0332 size = buffer_bytes(*end_);
0333 if(n < size)
0334 {
0335 out_end_ = n;
0336 n = 0;
0337 ++end_;
0338 break;
0339 }
0340 n -= size;
0341 out_end_ = size;
0342 }
0343 }
0344 else
0345 {
0346 ++end_;
0347 out_end_ = out_pos_ + n;
0348 n = 0;
0349 }
0350 }
0351 if(n > 0)
0352 BOOST_THROW_EXCEPTION(std::length_error{
0353 "buffers_adaptor too long"});
0354 return mutable_buffers_type(out_, end_, out_pos_, prepared);
0355 }
0356
0357 template<class MutableBufferSequence>
0358 void
0359 buffers_adaptor<MutableBufferSequence>::
0360 commit(std::size_t n) noexcept
0361 {
0362 if(out_ == end_)
0363 return;
0364 auto const last = std::prev(end_);
0365 while(out_ != last)
0366 {
0367 auto const avail =
0368 buffer_bytes(*out_) - out_pos_;
0369 if(n < avail)
0370 {
0371 out_pos_ += n;
0372 in_size_ += n;
0373 return;
0374 }
0375 ++out_;
0376 n -= avail;
0377 out_pos_ = 0;
0378 in_size_ += avail;
0379 }
0380
0381 n = std::min<std::size_t>(
0382 n, out_end_ - out_pos_);
0383 out_pos_ += n;
0384 in_size_ += n;
0385 if(out_pos_ == buffer_bytes(*out_))
0386 {
0387 ++out_;
0388 out_pos_ = 0;
0389 out_end_ = 0;
0390 }
0391 }
0392
0393 template<class MutableBufferSequence>
0394 void
0395 buffers_adaptor<MutableBufferSequence>::
0396 consume(std::size_t n) noexcept
0397 {
0398 while(begin_ != out_)
0399 {
0400 auto const avail =
0401 buffer_bytes(*begin_) - in_pos_;
0402 if(n < avail)
0403 {
0404 in_size_ -= n;
0405 in_pos_ += n;
0406 return;
0407 }
0408 n -= avail;
0409 in_size_ -= avail;
0410 in_pos_ = 0;
0411 ++begin_;
0412 }
0413 auto const avail = out_pos_ - in_pos_;
0414 if(n < avail)
0415 {
0416 in_size_ -= n;
0417 in_pos_ += n;
0418 }
0419 else
0420 {
0421 in_size_ -= avail;
0422 in_pos_ = out_pos_;
0423 }
0424 }
0425
0426 template<class MutableBufferSequence>
0427 auto
0428 buffers_adaptor<MutableBufferSequence>::
0429 make_subrange(std::size_t pos, std::size_t n) ->
0430 subrange<true>
0431 {
0432 return subrange<true>(
0433 begin_, net::buffer_sequence_end(bs_),
0434 in_pos_ + pos, n);
0435 }
0436
0437 template<class MutableBufferSequence>
0438 auto
0439 buffers_adaptor<MutableBufferSequence>::
0440 make_subrange(std::size_t pos, std::size_t n) const ->
0441 subrange<false>
0442 {
0443 return subrange<false>(
0444 begin_, net::buffer_sequence_end(bs_),
0445 in_pos_ + pos, n);
0446 }
0447
0448
0449
0450
0451 template<class MutableBufferSequence>
0452 template<bool isMutable>
0453 buffers_adaptor<MutableBufferSequence>::
0454 subrange<isMutable>::
0455 subrange(
0456 iter_type first,
0457 iter_type last,
0458 std::size_t pos,
0459 std::size_t n)
0460 : first_(first)
0461 , last_(last)
0462 , first_offset_(0)
0463 , last_size_((std::numeric_limits<std::size_t>::max)())
0464 {
0465 adjust(pos, n);
0466 }
0467
0468 template<class MutableBufferSequence>
0469 template<bool isMutable>
0470 void
0471 buffers_adaptor<MutableBufferSequence>::
0472 subrange<isMutable>::
0473 adjust(
0474 std::size_t pos,
0475 std::size_t n)
0476 {
0477 if (n == 0)
0478 last_ = first_;
0479
0480 if (first_ == last_)
0481 {
0482 first_offset_ = 0;
0483 last_size_ = 0;
0484 return;
0485 }
0486
0487 auto is_last = [this](iter_type iter) {
0488 return std::next(iter) == last_;
0489 };
0490
0491
0492 pos += first_offset_;
0493 while (pos)
0494 {
0495 auto adjust = (std::min)(pos, first_->size());
0496 if (adjust >= first_->size())
0497 {
0498 ++first_;
0499 first_offset_ = 0;
0500 pos -= adjust;
0501 }
0502 else
0503 {
0504 first_offset_ = adjust;
0505 pos = 0;
0506 break;
0507 }
0508 }
0509
0510 auto current = first_;
0511 auto max_elem = current->size() - first_offset_;
0512 if (is_last(current))
0513 {
0514
0515 last_size_ = (std::min)(max_elem, n);
0516 last_ = std::next(current);
0517 return;
0518 }
0519 else if (max_elem >= n)
0520 {
0521 last_ = std::next(current);
0522 last_size_ = n;
0523 }
0524 else
0525 {
0526 n -= max_elem;
0527 ++current;
0528 }
0529
0530 for (;;)
0531 {
0532 max_elem = current->size();
0533 if (is_last(current))
0534 {
0535 last_size_ = (std::min)(n, last_size_);
0536 return;
0537 }
0538 else if (max_elem < n)
0539 {
0540 n -= max_elem;
0541 ++current;
0542 }
0543 else
0544 {
0545 last_size_ = n;
0546 last_ = std::next(current);
0547 return;
0548 }
0549 }
0550 }
0551
0552
0553 template<class MutableBufferSequence>
0554 template<bool isMutable>
0555 auto
0556 buffers_adaptor<MutableBufferSequence>::
0557 subrange<isMutable>::
0558 begin() const ->
0559 iterator
0560 {
0561 return iterator(this, first_);
0562 }
0563
0564 template<class MutableBufferSequence>
0565 template<bool isMutable>
0566 auto
0567 buffers_adaptor<MutableBufferSequence>::
0568 subrange<isMutable>::
0569 end() const ->
0570 iterator
0571 {
0572 return iterator(this, last_);
0573 }
0574
0575
0576
0577
0578 template<class MutableBufferSequence>
0579 template<bool isMutable>
0580 buffers_adaptor<MutableBufferSequence>::
0581 subrange<isMutable>::
0582 iterator::
0583 iterator()
0584 : parent_(nullptr)
0585 , it_()
0586 {
0587 }
0588
0589 template<class MutableBufferSequence>
0590 template<bool isMutable>
0591 buffers_adaptor<MutableBufferSequence>::
0592 subrange<isMutable>::
0593 iterator::
0594 iterator(subrange<isMutable> const *parent,
0595 iter_type it)
0596 : parent_(parent)
0597 , it_(it)
0598 {
0599 }
0600
0601 template<class MutableBufferSequence>
0602 template<bool isMutable>
0603 auto
0604 buffers_adaptor<MutableBufferSequence>::
0605 subrange<isMutable>::
0606 iterator::
0607 operator*() const ->
0608 value_type
0609 {
0610 value_type result = *it_;
0611
0612 if (it_ == parent_->first_)
0613 result += parent_->first_offset_;
0614
0615 if (std::next(it_) == parent_->last_)
0616 {
0617 result = value_type(
0618 result.data(),
0619 (std::min)(
0620 parent_->last_size_,
0621 result.size()));
0622 }
0623
0624 return result;
0625 }
0626
0627 template<class MutableBufferSequence>
0628 template<bool isMutable>
0629 auto
0630 buffers_adaptor<MutableBufferSequence>::
0631 subrange<isMutable>::
0632 iterator::
0633 operator++() ->
0634 iterator &
0635 {
0636 ++it_;
0637 return *this;
0638 }
0639
0640 template<class MutableBufferSequence>
0641 template<bool isMutable>
0642 auto
0643 buffers_adaptor<MutableBufferSequence>::
0644 subrange<isMutable>::
0645 iterator::
0646 operator++(int) ->
0647 iterator
0648 {
0649 auto result = *this;
0650 ++it_;
0651 return result;
0652 }
0653
0654 template<class MutableBufferSequence>
0655 template<bool isMutable>
0656 auto
0657 buffers_adaptor<MutableBufferSequence>::
0658 subrange<isMutable>::
0659 iterator::
0660 operator--() ->
0661 iterator &
0662 {
0663 --it_;
0664 return *this;
0665 }
0666
0667 template<class MutableBufferSequence>
0668 template<bool isMutable>
0669 auto
0670 buffers_adaptor<MutableBufferSequence>::
0671 subrange<isMutable>::
0672 iterator::
0673 operator--(int) ->
0674 iterator
0675 {
0676 auto result = *this;
0677 --it_;
0678 return result;
0679 }
0680
0681 template<class MutableBufferSequence>
0682 template<bool isMutable>
0683 auto
0684 buffers_adaptor<MutableBufferSequence>::
0685 subrange<isMutable>::
0686 iterator::
0687 operator==(iterator const &b) const ->
0688 bool
0689 {
0690 return it_ == b.it_;
0691 }
0692
0693 template<class MutableBufferSequence>
0694 template<bool isMutable>
0695 auto
0696 buffers_adaptor<MutableBufferSequence>::
0697 subrange<isMutable>::
0698 iterator::
0699 operator!=(iterator const &b) const ->
0700 bool
0701 {
0702 return !(*this == b);
0703 }
0704
0705 }
0706 }
0707
0708 #endif