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_BUFFERS_CONSUMING_BUFFERS_HPP
  12 + #define BOOST_CAPY_BUFFERS_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 +
  24 + /** A cursor that drives consumption of a buffer sequence.
  25 +
  26 + `consuming_buffers` is the dedicated driver for `read_some`/`write_some`
  27 + loops. It presents the not-yet-consumed bytes of a buffer sequence via
  28 + `data()`, and `consume(n)` advances past `n` transferred bytes **in
  29 + place**.
  30 +
  31 + It is deliberately **not** itself a buffer sequence — it hands out the
  32 + remaining bytes through `data()` (returning a `slice_of` view). It
  33 + **borrows** the underlying sequence (iterators + a consumed-byte offset).
  34 + The sequence must outlive the cursor. That is the natural case when the
  35 + cursor is a local of a composed operation that took its buffers by value.
  36 +
  37 + @par Example
  38 + @par !example example
  39 +
  40 +
  41 + @see @ref buffer_slice
  42 + */
  43 + template<class Seq>
  44 + requires MutableBufferSequence<Seq> || ConstBufferSequence<Seq>
  45 + class consuming_buffers
  46 + {
  47 + public:
  48 + /// Names the buffer type the underlying sequence `Seq` yields.
  49 + using buffer_type = capy::buffer_type<Seq>;
  50 +
  51 + private:
  52 + using iterator_type =
  53 + decltype(capy::begin(std::declval<Seq const&>()));
  54 +
  55 + iterator_type first_{};
  56 + iterator_type last_{};
  57 + std::size_t front_skip_ = 0; // bytes consumed from *first_
  58 +
  59 + public:
  60 + /** Construct a cursor over `s`.
  61 +
  62 + @param s The sequence to consume. Must outlive the cursor.
  63 + */
HITGNC   64 + 306 explicit consuming_buffers(Seq const& s) noexcept
HITGNC   65 + 306 : first_(capy::begin(s))
HITGNC   66 + 306 , last_(capy::end(s))
  67 + {
HITGNC   68 + 306 }
  69 +
  70 + /** Reject construction from a temporary (the view would dangle).
  71 +
  72 + @param s The sequence that would be consumed.
  73 + */
  74 + consuming_buffers(Seq const&& s) = delete;
  75 +
  76 + /** Return the remaining (unconsumed) bytes as a buffer sequence.
  77 +
  78 + @return The bytes not yet consumed, as a buffer sequence.
  79 + */
  80 + detail::slice_of<Seq>
HITGNC   81 + 356 data() const noexcept
  82 + {
HITGNC   83 + 356 return detail::slice_of<Seq>(first_, last_, front_skip_, 0);
  84 + }
  85 +
  86 + /** Discard `n` bytes from the front, in place.
  87 +
  88 + Advances past `min(n, remaining)` bytes.
  89 +
  90 + @param n The number of bytes consumed.
  91 + */
  92 + void
HITGNC   93 + 264 consume(std::size_t n) noexcept
  94 + {
HITGNC   95 + 393 while (n > 0 && first_ != last_)
  96 + {
HITGNC   97 + 202 std::size_t const sz = buffer_type(*first_).size();
HITGNC   98 + 202 std::size_t const avail = sz - front_skip_;
HITGNC   99 + 202 if (n < avail)
  100 + {
HITGNC   101 + 73 front_skip_ += n;
HITGNC   102 + 73 return;
  103 + }
HITGNC   104 + 129 n -= avail;
HITGNC   105 + 129 ++first_;
HITGNC   106 + 129 front_skip_ = 0;
  107 + }
  108 + }
  109 + };
  110 +
  111 + /** Deduce the sequence type from the constructor argument.
  112 +
  113 + @tparam Seq The buffer sequence type.
  114 + */
  115 + template<class Seq>
  116 + consuming_buffers(Seq const&) -> consuming_buffers<Seq>;
  117 +
  118 + } // namespace capy
  119 + } // namespace boost
  120 +
  121 + #endif