TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Michael Vandeberg
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 : /*
11 : Implementation type for the public buffer_slice() free function.
12 : Users see this only via auto + the Slice concept; the type is
13 : documented as unspecified. Maintained alongside Slice in
14 : include/boost/capy/concept/slice.hpp.
15 : */
16 :
17 : #ifndef BOOST_CAPY_DETAIL_SLICE_IMPL_HPP
18 : #define BOOST_CAPY_DETAIL_SLICE_IMPL_HPP
19 :
20 : #include <boost/capy/detail/config.hpp>
21 : #include <boost/capy/buffers.hpp>
22 :
23 : #include <cstddef>
24 : #include <iterator>
25 : #include <type_traits>
26 :
27 : namespace boost {
28 : namespace capy {
29 : namespace detail {
30 :
31 : template<class T>
32 : struct slice_buffer_type_for;
33 :
34 : template<MutableBufferSequence T>
35 : struct slice_buffer_type_for<T>
36 : {
37 : using type = mutable_buffer;
38 : };
39 :
40 : template<ConstBufferSequence T>
41 : requires (!MutableBufferSequence<T>)
42 : struct slice_buffer_type_for<T>
43 : {
44 : using type = const_buffer;
45 : };
46 :
47 : template<class BufferSequence>
48 : requires MutableBufferSequence<BufferSequence>
49 : || ConstBufferSequence<BufferSequence>
50 : class slice_impl
51 : {
52 : public:
53 : using iterator_type =
54 : decltype(capy::begin(std::declval<BufferSequence const&>()));
55 : using end_iterator_type =
56 : decltype(capy::end(std::declval<BufferSequence const&>()));
57 : using buffer_type =
58 : typename slice_buffer_type_for<BufferSequence>::type;
59 :
60 : private:
61 : iterator_type first_{};
62 : end_iterator_type last_{};
63 : std::size_t front_skip_ = 0;
64 : std::size_t back_skip_ = 0;
65 :
66 HIT 493 : static buffer_type adjust_buffer(
67 : buffer_type const& buf,
68 : std::size_t front,
69 : std::size_t back) noexcept
70 : {
71 : if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
72 : {
73 247 : return mutable_buffer(
74 247 : static_cast<char*>(buf.data()) + front,
75 494 : buf.size() - front - back);
76 : }
77 : else
78 : {
79 246 : return const_buffer(
80 246 : static_cast<char const*>(buf.data()) + front,
81 492 : buf.size() - front - back);
82 : }
83 : }
84 :
85 : public:
86 : /// View returned by `slice_impl::data()`.
87 : class data_view
88 : {
89 : iterator_type first_{};
90 : end_iterator_type last_{};
91 : std::size_t front_skip_ = 0;
92 : std::size_t back_skip_ = 0;
93 :
94 : public:
95 : class const_iterator
96 : {
97 : iterator_type cur_{};
98 : iterator_type anchor_first_{};
99 : end_iterator_type anchor_last_{};
100 : std::size_t front_skip_ = 0;
101 : std::size_t back_skip_ = 0;
102 :
103 : public:
104 : using iterator_category = std::bidirectional_iterator_tag;
105 : using value_type = buffer_type;
106 : using difference_type = std::ptrdiff_t;
107 : using pointer = value_type*;
108 : using reference = value_type;
109 :
110 : const_iterator() noexcept = default;
111 :
112 942 : const_iterator(
113 : iterator_type cur,
114 : iterator_type anchor_first,
115 : end_iterator_type anchor_last,
116 : std::size_t front_skip,
117 : std::size_t back_skip) noexcept
118 942 : : cur_(cur)
119 942 : , anchor_first_(anchor_first)
120 942 : , anchor_last_(anchor_last)
121 942 : , front_skip_(front_skip)
122 942 : , back_skip_(back_skip)
123 : {
124 942 : }
125 :
126 598 : bool operator==(const_iterator const& other) const noexcept
127 : {
128 598 : return cur_ == other.cur_;
129 : }
130 :
131 598 : bool operator!=(const_iterator const& other) const noexcept
132 : {
133 598 : return !(*this == other);
134 : }
135 :
136 493 : value_type operator*() const noexcept
137 : {
138 493 : buffer_type buf = *cur_;
139 493 : auto front = (cur_ == anchor_first_) ? front_skip_ : 0;
140 493 : auto next = cur_;
141 493 : ++next;
142 493 : auto back = (next == anchor_last_) ? back_skip_ : 0;
143 493 : return adjust_buffer(buf, front, back);
144 : }
145 :
146 463 : const_iterator& operator++() noexcept
147 : {
148 463 : ++cur_;
149 463 : return *this;
150 : }
151 :
152 262 : const_iterator operator++(int) noexcept
153 : {
154 262 : const_iterator tmp = *this;
155 262 : ++*this;
156 262 : return tmp;
157 : }
158 :
159 : const_iterator& operator--() noexcept
160 : {
161 : --cur_;
162 : return *this;
163 : }
164 :
165 : const_iterator operator--(int) noexcept
166 : {
167 : const_iterator tmp = *this;
168 : --*this;
169 : return tmp;
170 : }
171 : };
172 :
173 : data_view() noexcept = default;
174 :
175 271 : data_view(
176 : iterator_type first,
177 : end_iterator_type last,
178 : std::size_t front_skip,
179 : std::size_t back_skip) noexcept
180 271 : : first_(first)
181 271 : , last_(last)
182 271 : , front_skip_(front_skip)
183 271 : , back_skip_(back_skip)
184 : {
185 271 : }
186 :
187 457 : const_iterator begin() const noexcept
188 : {
189 : return const_iterator(
190 457 : first_, first_, last_, front_skip_, back_skip_);
191 : }
192 :
193 485 : const_iterator end() const noexcept
194 : {
195 : return const_iterator(
196 485 : last_, first_, last_, front_skip_, back_skip_);
197 : }
198 : };
199 :
200 : slice_impl() noexcept = default;
201 :
202 10 : explicit slice_impl(BufferSequence const& bs) noexcept
203 10 : : first_(capy::begin(bs))
204 10 : , last_(capy::end(bs))
205 : {
206 10 : }
207 :
208 213 : slice_impl(
209 : BufferSequence const& bs,
210 : std::size_t offset,
211 : std::size_t length) noexcept
212 213 : {
213 213 : auto it_begin = capy::begin(bs);
214 213 : auto it_end = capy::end(bs);
215 :
216 213 : std::size_t total = 0;
217 508 : for (auto it = it_begin; it != it_end; ++it)
218 295 : total += (*it).size();
219 :
220 213 : if (offset > total)
221 1 : offset = total;
222 213 : std::size_t const remaining = total - offset;
223 213 : if (length > remaining)
224 205 : length = remaining;
225 :
226 213 : first_ = it_begin;
227 213 : last_ = it_end;
228 :
229 213 : std::size_t skip = offset;
230 235 : while (first_ != last_)
231 : {
232 228 : std::size_t const buf_size = (*first_).size();
233 228 : if (skip < buf_size)
234 : {
235 206 : front_skip_ = skip;
236 206 : break;
237 : }
238 22 : skip -= buf_size;
239 22 : ++first_;
240 : }
241 :
242 213 : std::size_t left = length;
243 213 : auto cursor = first_;
244 213 : std::size_t cursor_front = front_skip_;
245 278 : while (cursor != last_ && left > 0)
246 : {
247 270 : std::size_t const buf_size = (*cursor).size();
248 270 : std::size_t const avail = buf_size - cursor_front;
249 270 : if (left <= avail)
250 : {
251 205 : back_skip_ = avail - left;
252 205 : ++cursor;
253 205 : last_ = cursor;
254 205 : return;
255 : }
256 65 : left -= avail;
257 65 : ++cursor;
258 65 : cursor_front = 0;
259 : }
260 :
261 8 : last_ = cursor;
262 : }
263 :
264 271 : data_view data() const noexcept
265 : {
266 271 : return data_view(first_, last_, front_skip_, back_skip_);
267 : }
268 :
269 172 : void remove_prefix(std::size_t n) noexcept
270 : {
271 192 : while (n > 0 && first_ != last_)
272 : {
273 122 : std::size_t const buf_total = (*first_).size();
274 122 : std::size_t live = buf_total - front_skip_;
275 122 : auto next = first_;
276 122 : ++next;
277 122 : bool const is_last = (next == last_);
278 122 : if (is_last)
279 92 : live -= back_skip_;
280 :
281 122 : if (n < live)
282 : {
283 35 : front_skip_ += n;
284 35 : return;
285 : }
286 :
287 87 : n -= live;
288 87 : if (is_last)
289 : {
290 67 : first_ = last_;
291 67 : front_skip_ = 0;
292 67 : back_skip_ = 0;
293 67 : return;
294 : }
295 20 : ++first_;
296 20 : front_skip_ = 0;
297 : }
298 : }
299 : };
300 :
301 : } // namespace detail
302 : } // namespace capy
303 : } // namespace boost
304 :
305 : #endif
|