Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot 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 19 : explicit consuming_buffers(BufferSequence const& bufs) noexcept
74 19 : : bufs_(bufs)
75 19 : , it_(capy::begin(bufs))
76 19 : , end_(capy::end(bufs))
77 : {
78 19 : }
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 29 : void consume(std::size_t n) noexcept
88 : {
89 58 : while (n > 0 && it_ != end_)
90 : {
91 29 : auto const& buf = *it_;
92 29 : std::size_t const buf_size = buf.size();
93 29 : std::size_t const remaining = buf_size - consumed_;
94 :
95 29 : if (n < remaining)
96 : {
97 : // Consume part of current buffer
98 18 : consumed_ += n;
99 18 : n = 0;
100 : }
101 : else
102 : {
103 : // Consume rest of current buffer and move to next
104 11 : n -= remaining;
105 11 : consumed_ = 0;
106 11 : ++it_;
107 : }
108 : }
109 29 : }
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 40 : const_iterator(
133 : iterator_type it,
134 : end_iterator_type end,
135 : std::size_t consumed) noexcept
136 40 : : it_(it)
137 40 : , end_(end)
138 40 : , consumed_(consumed)
139 : {
140 40 : }
141 :
142 6 : bool operator==(const_iterator const& other) const noexcept
143 : {
144 6 : return it_ == other.it_ && consumed_ == other.consumed_;
145 : }
146 :
147 : // != operator required for equality_comparable
148 6 : bool operator!=(const_iterator const& other) const noexcept
149 : {
150 6 : return !(*this == other);
151 : }
152 :
153 37 : value_type operator*() const noexcept
154 : {
155 37 : auto const& buf = *it_;
156 : if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
157 : {
158 48 : return buffer_type(
159 16 : static_cast<char*>(buf.data()) + consumed_,
160 32 : buf.size() - consumed_);
161 : }
162 : else
163 : {
164 63 : return buffer_type(
165 21 : static_cast<char const*>(buf.data()) + consumed_,
166 42 : buf.size() - consumed_);
167 : }
168 : }
169 :
170 3 : const_iterator& operator++() noexcept
171 : {
172 3 : consumed_ = 0;
173 3 : ++it_;
174 3 : return *this;
175 : }
176 :
177 : const_iterator operator++(int) noexcept
178 : {
179 : const_iterator tmp = *this;
180 : ++*this;
181 : return tmp;
182 : }
183 :
184 : const_iterator& operator--() noexcept
185 : {
186 : if (consumed_ == 0)
187 : {
188 : --it_;
189 : // Set consumed_ to the size of the previous buffer
190 : // This is a simplified implementation for bidirectional requirement
191 : if (it_ != end_)
192 : {
193 : auto const& buf = *it_;
194 : consumed_ = buf.size();
195 : }
196 : }
197 : else
198 : {
199 : consumed_ = 0;
200 : }
201 : return *this;
202 : }
203 :
204 : const_iterator operator--(int) noexcept
205 : {
206 : const_iterator tmp = *this;
207 : --*this;
208 : return tmp;
209 : }
210 : };
211 :
212 : /** Return iterator to beginning of remaining buffers.
213 :
214 : @return Iterator pointing to the first remaining buffer,
215 : adjusted for consumed bytes in the current buffer.
216 : */
217 37 : const_iterator begin() const noexcept
218 : {
219 37 : return const_iterator(it_, end_, consumed_);
220 : }
221 :
222 : /** Return iterator to end of buffer sequence.
223 :
224 : @return End iterator.
225 : */
226 3 : const_iterator end() const noexcept
227 : {
228 3 : return const_iterator(end_, end_, 0);
229 : }
230 : };
231 :
232 : } // namespace capy
233 : } // namespace boost
234 :
235 : #endif
|