TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Steve Gerbino
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/cppalliance/capy
8 : //
9 :
10 : #ifndef BOOST_CAPY_BUFFERS_CONSUMING_BUFFERS_HPP
11 : #define BOOST_CAPY_BUFFERS_CONSUMING_BUFFERS_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <boost/capy/buffers.hpp>
15 : #include <boost/capy/detail/slice_of.hpp>
16 :
17 : #include <cstddef>
18 : #include <utility>
19 :
20 : namespace boost {
21 : namespace capy {
22 :
23 : /** A cursor that drives consumption of a buffer sequence.
24 :
25 : `consuming_buffers` is the dedicated driver for `read_some`/`write_some`
26 : loops: it presents the not-yet-consumed bytes of a buffer sequence via
27 : `data()`, and `consume(n)` advances past `n` transferred bytes **in
28 : place**.
29 :
30 : It is deliberately **not** itself a buffer sequence — it hands out the
31 : remaining bytes through `data()` (returning a `slice_of` view). It
32 : **borrows** the underlying sequence (iterators + a consumed-byte offset);
33 : the sequence must outlive the cursor, which is the natural case when the
34 : cursor is a local of a composed operation that took its buffers by value.
35 :
36 : @par Example
37 : @code
38 : consuming_buffers consuming(buffers);
39 : std::size_t total = 0, want = buffer_size(buffers);
40 : while (total < want)
41 : {
42 : auto [ec, n] = co_await stream.read_some(consuming.data());
43 : consuming.consume(n);
44 : total += n;
45 : if (ec && total < want) co_return {ec, total};
46 : }
47 : @endcode
48 :
49 : @see buffer_slice, slice_of
50 : */
51 : template<class Seq>
52 : requires MutableBufferSequence<Seq> || ConstBufferSequence<Seq>
53 : class consuming_buffers
54 : {
55 : public:
56 : /// The buffer type of the underlying sequence.
57 : using buffer_type = capy::buffer_type<Seq>;
58 :
59 : private:
60 : using iterator_type =
61 : decltype(capy::begin(std::declval<Seq const&>()));
62 :
63 : iterator_type first_{};
64 : iterator_type last_{};
65 : std::size_t front_skip_ = 0; // bytes consumed from *first_
66 :
67 : public:
68 : /** Construct a cursor over `s`.
69 :
70 : @param s The sequence to consume. Must outlive the cursor.
71 : */
72 HIT 291 : explicit consuming_buffers(Seq const& s) noexcept
73 291 : : first_(capy::begin(s))
74 291 : , last_(capy::end(s))
75 : {
76 291 : }
77 :
78 : /// Reject construction from a temporary (the view would dangle).
79 : consuming_buffers(Seq const&&) = delete;
80 :
81 : /// Return the remaining (unconsumed) bytes as a buffer sequence.
82 : detail::slice_of<Seq>
83 335 : data() const noexcept
84 : {
85 335 : return detail::slice_of<Seq>(first_, last_, front_skip_, 0);
86 : }
87 :
88 : /** Discard `n` bytes from the front, in place.
89 :
90 : Advances past `min(n, remaining)` bytes.
91 :
92 : @param n The number of bytes consumed.
93 : */
94 : void
95 245 : consume(std::size_t n) noexcept
96 : {
97 358 : while (n > 0 && first_ != last_)
98 : {
99 179 : std::size_t const sz = buffer_type(*first_).size();
100 179 : std::size_t const avail = sz - front_skip_;
101 179 : if (n < avail)
102 : {
103 66 : front_skip_ += n;
104 66 : return;
105 : }
106 113 : n -= avail;
107 113 : ++first_;
108 113 : front_skip_ = 0;
109 : }
110 : }
111 : };
112 :
113 : // CTAD: deduce the sequence type from the constructor argument.
114 : template<class Seq>
115 : consuming_buffers(Seq const&) -> consuming_buffers<Seq>;
116 :
117 : } // namespace capy
118 : } // namespace boost
119 :
120 : #endif
|