TLA Line data Source 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 buffer_slice, slice_of
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 : */
64 HIT 315 : explicit consuming_buffers(Seq const& s) noexcept
65 315 : : first_(capy::begin(s))
66 315 : , last_(capy::end(s))
67 : {
68 315 : }
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>
81 362 : data() const noexcept
82 : {
83 362 : 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
93 272 : consume(std::size_t n) noexcept
94 : {
95 415 : while (n > 0 && first_ != last_)
96 : {
97 214 : std::size_t const sz = buffer_type(*first_).size();
98 214 : std::size_t const avail = sz - front_skip_;
99 214 : if (n < avail)
100 : {
101 71 : front_skip_ += n;
102 71 : return;
103 : }
104 143 : n -= avail;
105 143 : ++first_;
106 143 : 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
|