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   315 explicit consuming_buffers(Seq const& s) noexcept 64   315 explicit consuming_buffers(Seq const& s) noexcept
HITCBC 65   315 : first_(capy::begin(s)) 65   315 : first_(capy::begin(s))
HITCBC 66   315 , last_(capy::end(s)) 66   315 , last_(capy::end(s))
67   { 67   {
HITCBC 68   315 } 68   315 }
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   362 data() const noexcept 81   362 data() const noexcept
82   { 82   {
HITCBC 83   362 return detail::slice_of<Seq>(first_, last_, front_skip_, 0); 83   362 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   272 consume(std::size_t n) noexcept 93   272 consume(std::size_t n) noexcept
94   { 94   {
HITCBC 95   415 while (n > 0 && first_ != last_) 95   415 while (n > 0 && first_ != last_)
96   { 96   {
HITCBC 97   214 std::size_t const sz = buffer_type(*first_).size(); 97   214 std::size_t const sz = buffer_type(*first_).size();
HITCBC 98   214 std::size_t const avail = sz - front_skip_; 98   214 std::size_t const avail = sz - front_skip_;
HITCBC 99   214 if (n < avail) 99   214 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   143 n -= avail; 104   143 n -= avail;
HITCBC 105   143 ++first_; 105   143 ++first_;
HITCBC 106   143 front_skip_ = 0; 106   143 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