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