100.00% Lines (16/16) 100.00% Functions (3/3)
TLA Baseline Branch
Line Hits Code Line Hits Code
  1 + //
  2 + // Copyright (c) 2026 Steve Gerbino
  3 + // Copyright (c) 2026 Michael Vandeberg
  4 + //
  5 + // Distributed under the Boost Software License, Version 1.0. (See accompanying
  6 + // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7 + //
  8 + // Official repository: https://github.com/cppalliance/capy
  9 + //
  10 +
  11 + #ifndef BOOST_CAPY_DETAIL_CONSUMING_BUFFERS_HPP
  12 + #define BOOST_CAPY_DETAIL_CONSUMING_BUFFERS_HPP
  13 +
  14 + #include <boost/capy/detail/config.hpp>
  15 + #include <boost/capy/buffers.hpp>
  16 + #include <boost/capy/detail/slice_of.hpp>
  17 +
  18 + #include <cstddef>
  19 + #include <utility>
  20 +
  21 + namespace boost {
  22 + namespace capy {
  23 + namespace detail {
  24 +
  25 + /** A cursor that drives consumption of a buffer sequence.
  26 +
  27 + `consuming_buffers` is the dedicated driver for `read_some`/`write_some`
  28 + loops. It presents the not-yet-consumed bytes of a buffer sequence via
  29 + `data()`, and `consume(n)` advances past `n` transferred bytes **in
  30 + place**.
  31 +
  32 + It is deliberately **not** itself a buffer sequence — it hands out the
  33 + remaining bytes through `data()` (returning a `slice_of` view). It
  34 + **borrows** the underlying sequence (iterators + a consumed-byte offset).
  35 + The sequence must outlive the cursor. That is the natural case when the
  36 + cursor is a local of a composed operation that took its buffers by value.
  37 + */
  38 + template<class Seq>
  39 + requires ConstBufferSequence<Seq>
  40 + class consuming_buffers
  41 + {
  42 + public:
  43 + /// Names the buffer type the underlying sequence `Seq` yields.
  44 + using buffer_type = capy::buffer_type<Seq>;
  45 +
  46 + private:
  47 + using iterator_type =
  48 + decltype(capy::buffer_sequence_begin(std::declval<Seq const&>()));
  49 +
  50 + iterator_type first_{};
  51 + iterator_type last_{};
  52 + std::size_t front_skip_ = 0; // bytes consumed from *first_
  53 +
  54 + public:
  55 + /** Construct a cursor over `s`.
  56 +
  57 + @param s The sequence to consume. Must outlive the cursor.
  58 + */
HITGNC   59 + 306 explicit consuming_buffers(Seq const& s) noexcept
HITGNC   60 + 306 : first_(capy::buffer_sequence_begin(s))
HITGNC   61 + 306 , last_(capy::buffer_sequence_end(s))
  62 + {
HITGNC   63 + 306 }
  64 +
  65 + /** Reject construction from a temporary (the view would dangle).
  66 +
  67 + @param s The sequence that would be consumed.
  68 + */
  69 + consuming_buffers(Seq const&& s) = delete;
  70 +
  71 + /** Return the remaining (unconsumed) bytes as a buffer sequence.
  72 +
  73 + @return The bytes not yet consumed, as a buffer sequence.
  74 + */
  75 + slice_of<Seq>
HITGNC   76 + 354 data() const noexcept
  77 + {
HITGNC   78 + 354 return slice_of<Seq>(first_, last_, front_skip_, 0);
  79 + }
  80 +
  81 + /** Discard `n` bytes from the front, in place.
  82 +
  83 + Advances past `min(n, remaining)` bytes.
  84 +
  85 + @param n The number of bytes consumed.
  86 + */
  87 + void
HITGNC   88 + 262 consume(std::size_t n) noexcept
  89 + {
HITGNC   90 + 387 while (n > 0 && first_ != last_)
  91 + {
HITGNC   92 + 199 std::size_t const sz = buffer_type(*first_).size();
HITGNC   93 + 199 std::size_t const avail = sz - front_skip_;
HITGNC   94 + 199 if (n < avail)
  95 + {
HITGNC   96 + 74 front_skip_ += n;
HITGNC   97 + 74 return;
  98 + }
HITGNC   99 + 125 n -= avail;
HITGNC   100 + 125 ++first_;
HITGNC   101 + 125 front_skip_ = 0;
  102 + }
  103 + }
  104 + };
  105 +
  106 + /** Deduce the sequence type from the constructor argument.
  107 +
  108 + @tparam Seq The buffer sequence type.
  109 + */
  110 + template<class Seq>
  111 + consuming_buffers(Seq const&) -> consuming_buffers<Seq>;
  112 +
  113 + } // namespace detail
  114 + } // namespace capy
  115 + } // namespace boost
  116 +
  117 + #endif