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 | ||||||