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