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