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   @par !example example 38   @par !example example
39   39  
40   40  
41   @see buffer_slice, slice_of 41   @see buffer_slice, slice_of
42   */ 42   */
43   template<class Seq> 43   template<class Seq>
44   requires MutableBufferSequence<Seq> || ConstBufferSequence<Seq> 44   requires MutableBufferSequence<Seq> || ConstBufferSequence<Seq>
45   class consuming_buffers 45   class consuming_buffers
46   { 46   {
47   public: 47   public:
48   /// Names the buffer type the underlying sequence `Seq` yields. 48   /// Names the buffer type the underlying sequence `Seq` yields.
49   using buffer_type = capy::buffer_type<Seq>; 49   using buffer_type = capy::buffer_type<Seq>;
50   50  
51   private: 51   private:
52   using iterator_type = 52   using iterator_type =
53   decltype(capy::begin(std::declval<Seq const&>())); 53   decltype(capy::begin(std::declval<Seq const&>()));
54   54  
55   iterator_type first_{}; 55   iterator_type first_{};
56   iterator_type last_{}; 56   iterator_type last_{};
57   std::size_t front_skip_ = 0; // bytes consumed from *first_ 57   std::size_t front_skip_ = 0; // bytes consumed from *first_
58   58  
59   public: 59   public:
60   /** Construct a cursor over `s`. 60   /** Construct a cursor over `s`.
61   61  
62   @param s The sequence to consume. Must outlive the cursor. 62   @param s The sequence to consume. Must outlive the cursor.
63   */ 63   */
HITCBC 64   307 explicit consuming_buffers(Seq const& s) noexcept 64   307 explicit consuming_buffers(Seq const& s) noexcept
HITCBC 65   307 : first_(capy::begin(s)) 65   307 : first_(capy::begin(s))
HITCBC 66   307 , last_(capy::end(s)) 66   307 , last_(capy::end(s))
67   { 67   {
HITCBC 68   307 } 68   307 }
69   69  
70   /** Reject construction from a temporary (the view would dangle). 70   /** Reject construction from a temporary (the view would dangle).
71   71  
72   @param s The sequence that would be consumed. 72   @param s The sequence that would be consumed.
73   */ 73   */
74   consuming_buffers(Seq const&& s) = delete; 74   consuming_buffers(Seq const&& s) = delete;
75   75  
76   /** Return the remaining (unconsumed) bytes as a buffer sequence. 76   /** Return the remaining (unconsumed) bytes as a buffer sequence.
77   77  
78   @return The bytes not yet consumed, as a buffer sequence. 78   @return The bytes not yet consumed, as a buffer sequence.
79   */ 79   */
80   detail::slice_of<Seq> 80   detail::slice_of<Seq>
HITCBC 81   355 data() const noexcept 81   355 data() const noexcept
82   { 82   {
HITCBC 83   355 return detail::slice_of<Seq>(first_, last_, front_skip_, 0); 83   355 return detail::slice_of<Seq>(first_, last_, front_skip_, 0);
84   } 84   }
85   85  
86   /** Discard `n` bytes from the front, in place. 86   /** Discard `n` bytes from the front, in place.
87   87  
88   Advances past `min(n, remaining)` bytes. 88   Advances past `min(n, remaining)` bytes.
89   89  
90   @param n The number of bytes consumed. 90   @param n The number of bytes consumed.
91   */ 91   */
92   void 92   void
HITCBC 93   263 consume(std::size_t n) noexcept 93   263 consume(std::size_t n) noexcept
94   { 94   {
HITCBC 95   397 while (n > 0 && first_ != last_) 95   397 while (n > 0 && first_ != last_)
96   { 96   {
HITCBC 97   205 std::size_t const sz = buffer_type(*first_).size(); 97   205 std::size_t const sz = buffer_type(*first_).size();
HITCBC 98   205 std::size_t const avail = sz - front_skip_; 98   205 std::size_t const avail = sz - front_skip_;
HITCBC 99   205 if (n < avail) 99   205 if (n < avail)
100   { 100   {
HITCBC 101   71 front_skip_ += n; 101   71 front_skip_ += n;
HITCBC 102   71 return; 102   71 return;
103   } 103   }
HITCBC 104   134 n -= avail; 104   134 n -= avail;
HITCBC 105   134 ++first_; 105   134 ++first_;
HITCBC 106   134 front_skip_ = 0; 106   134 front_skip_ = 0;
107   } 107   }
108   } 108   }
109   }; 109   };
110   110  
111   /** Deduce the sequence type from the constructor argument. 111   /** Deduce the sequence type from the constructor argument.
112   112  
113   @tparam Seq The buffer sequence type. 113   @tparam Seq The buffer sequence type.
114   */ 114   */
115   template<class Seq> 115   template<class Seq>
116   consuming_buffers(Seq const&) -> consuming_buffers<Seq>; 116   consuming_buffers(Seq const&) -> consuming_buffers<Seq>;
117   117  
118   } // namespace capy 118   } // namespace capy
119   } // namespace boost 119   } // namespace boost
120   120  
121   #endif 121   #endif