include/boost/capy/buffers/consuming_buffers.hpp

100.0% Lines (46/46) 100.0% Functions (37/37)
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 //
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)
6 //
7 // Official repository: https://github.com/cppalliance/capy
8 //
9
10 #ifndef BOOST_CAPY_BUFFERS_CONSUMING_BUFFERS_HPP
11 #define BOOST_CAPY_BUFFERS_CONSUMING_BUFFERS_HPP
12
13 #include <boost/capy/detail/config.hpp>
14 #include <boost/capy/buffers.hpp>
15
16 #include <cstddef>
17 #include <iterator>
18 #include <ranges>
19 #include <type_traits>
20
21 namespace boost {
22 namespace capy {
23
24 namespace detail {
25
26 template<class T>
27 struct buffer_type_for;
28
29 template<MutableBufferSequence T>
30 struct buffer_type_for<T>
31 {
32 using type = mutable_buffer;
33 };
34
35 template<ConstBufferSequence T>
36 requires (!MutableBufferSequence<T>)
37 struct buffer_type_for<T>
38 {
39 using type = const_buffer;
40 };
41
42 } // namespace detail
43
44 /** Wrapper for consuming a buffer sequence incrementally.
45
46 This class wraps a buffer sequence and tracks the current
47 position. It provides a `consume(n)` function that advances
48 through the sequence as bytes are processed.
49
50 Works with both mutable and const buffer sequences.
51
52 @tparam BufferSequence The buffer sequence type.
53 */
54 template<class BufferSequence>
55 requires MutableBufferSequence<BufferSequence> ||
56 ConstBufferSequence<BufferSequence>
57 class consuming_buffers
58 {
59 using iterator_type = decltype(capy::begin(std::declval<BufferSequence const&>()));
60 using end_iterator_type = decltype(capy::end(std::declval<BufferSequence const&>()));
61 using buffer_type = typename detail::buffer_type_for<BufferSequence>::type;
62
63 BufferSequence const& bufs_;
64 iterator_type it_;
65 end_iterator_type end_;
66 std::size_t consumed_ = 0; // Bytes consumed in current buffer
67
68 public:
69 /** Construct from a buffer sequence.
70
71 @param bufs The buffer sequence to wrap.
72 */
73 203x explicit consuming_buffers(BufferSequence const& bufs) noexcept
74 203x : bufs_(bufs)
75 203x , it_(capy::begin(bufs))
76 203x , end_(capy::end(bufs))
77 {
78 203x }
79
80 /** Consume n bytes from the buffer sequence.
81
82 Advances the current position by n bytes, moving to the
83 next buffer when the current one is exhausted.
84
85 @param n The number of bytes to consume.
86 */
87 94x void consume(std::size_t n) noexcept
88 {
89 206x while (n > 0 && it_ != end_)
90 {
91 112x auto const& buf = *it_;
92 112x std::size_t const buf_size = buf.size();
93 112x std::size_t const remaining = buf_size - consumed_;
94
95 112x if (n < remaining)
96 {
97 // Consume part of current buffer
98 30x consumed_ += n;
99 30x n = 0;
100 }
101 else
102 {
103 // Consume rest of current buffer and move to next
104 82x n -= remaining;
105 82x consumed_ = 0;
106 82x ++it_;
107 }
108 }
109 94x }
110
111 /** Iterator for the consuming buffer sequence.
112
113 Returns buffers starting from the current position,
114 with the first buffer adjusted for consumed bytes.
115 */
116 class const_iterator
117 {
118 iterator_type it_;
119 end_iterator_type end_;
120 std::size_t consumed_;
121
122 public:
123 using iterator_category = std::bidirectional_iterator_tag;
124 using value_type = buffer_type;
125 using difference_type = std::ptrdiff_t;
126 using pointer = value_type*;
127 using reference = value_type;
128
129 // Default constructor required for forward_iterator
130 const_iterator() noexcept = default;
131
132 /// Construct from position and consumed byte count.
133 826x const_iterator(
134 iterator_type it,
135 end_iterator_type end,
136 std::size_t consumed) noexcept
137 826x : it_(it)
138 826x , end_(end)
139 826x , consumed_(consumed)
140 {
141 826x }
142
143 /// Test for equality.
144 518x bool operator==(const_iterator const& other) const noexcept
145 {
146 518x return it_ == other.it_ && consumed_ == other.consumed_;
147 }
148
149 /// Test for inequality.
150 518x bool operator!=(const_iterator const& other) const noexcept
151 {
152 518x return !(*this == other);
153 }
154
155 /// Return the current buffer, adjusted for consumed bytes.
156 457x value_type operator*() const noexcept
157 {
158 457x auto const& buf = *it_;
159 if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
160 {
161 579x return buffer_type(
162 193x static_cast<char*>(buf.data()) + consumed_,
163 386x buf.size() - consumed_);
164 }
165 else
166 {
167 792x return buffer_type(
168 264x static_cast<char const*>(buf.data()) + consumed_,
169 528x buf.size() - consumed_);
170 }
171 }
172
173 /// Advance to the next element.
174 427x const_iterator& operator++() noexcept
175 {
176 427x consumed_ = 0;
177 427x ++it_;
178 427x return *this;
179 }
180
181 /// Advance to the next element (postfix).
182 274x const_iterator operator++(int) noexcept
183 {
184 274x const_iterator tmp = *this;
185 274x ++*this;
186 274x return tmp;
187 }
188
189 /// Move to the previous element.
190 const_iterator& operator--() noexcept
191 {
192 if (consumed_ == 0)
193 {
194 --it_;
195 // Set consumed_ to the size of the previous buffer
196 // This is a simplified implementation for bidirectional requirement
197 if (it_ != end_)
198 {
199 auto const& buf = *it_;
200 consumed_ = buf.size();
201 }
202 }
203 else
204 {
205 consumed_ = 0;
206 }
207 return *this;
208 }
209
210 /// Move to the previous element (postfix).
211 const_iterator operator--(int) noexcept
212 {
213 const_iterator tmp = *this;
214 --*this;
215 return tmp;
216 }
217 };
218
219 /** Return iterator to beginning of remaining buffers.
220
221 @return Iterator pointing to the first remaining buffer,
222 adjusted for consumed bytes in the current buffer.
223 */
224 413x const_iterator begin() const noexcept
225 {
226 413x return const_iterator(it_, end_, consumed_);
227 }
228
229 /** Return iterator to end of buffer sequence.
230
231 @return End iterator.
232 */
233 413x const_iterator end() const noexcept
234 {
235 413x return const_iterator(end_, end_, 0);
236 }
237 };
238
239 } // namespace capy
240 } // namespace boost
241
242 #endif
243