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 42071 : static buffer_type adjust_buffer(
67 : buffer_type const& buf,
68 : std::size_t front_n,
69 : std::size_t back_n) noexcept
70 : {
71 : if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
72 : {
73 18031 : return mutable_buffer(
74 18031 : static_cast<char*>(buf.data()) + front_n,
75 36062 : buf.size() - front_n - back_n);
76 : }
77 : else
78 : {
79 24040 : return const_buffer(
80 24040 : static_cast<char const*>(buf.data()) + front_n,
81 48080 : buf.size() - front_n - back_n);
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 69754 : 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 69754 : : cur_(cur)
119 69754 : , anchor_first_(anchor_first)
120 69754 : , anchor_last_(anchor_last)
121 69754 : , front_skip_(front_skip)
122 69754 : , back_skip_(back_skip)
123 : {
124 69754 : }
125 :
126 76234 : bool operator==(const_iterator const& other) const noexcept
127 : {
128 76234 : return cur_ == other.cur_;
129 : }
130 :
131 76234 : bool operator!=(const_iterator const& other) const noexcept
132 : {
133 76234 : return !(*this == other);
134 : }
135 :
136 42071 : value_type operator*() const noexcept
137 : {
138 42071 : buffer_type buf = *cur_;
139 42071 : auto front_n = (cur_ == anchor_first_) ? front_skip_ : 0;
140 42071 : auto next = cur_;
141 42071 : ++next;
142 42071 : auto back_n = (next == anchor_last_) ? back_skip_ : 0;
143 42071 : return adjust_buffer(buf, front_n, back_n);
144 : }
145 :
146 29897 : const_iterator& operator++() noexcept
147 : {
148 29897 : ++cur_;
149 29897 : return *this;
150 : }
151 :
152 6512 : const_iterator operator++(int) noexcept
153 : {
154 6512 : const_iterator tmp = *this;
155 6512 : ++*this;
156 6512 : return tmp;
157 : }
158 :
159 12144 : const_iterator& operator--() noexcept
160 : {
161 12144 : --cur_;
162 12144 : return *this;
163 : }
164 :
165 6072 : const_iterator operator--(int) noexcept
166 : {
167 6072 : const_iterator tmp = *this;
168 6072 : --*this;
169 6072 : return tmp;
170 : }
171 : };
172 :
173 : data_view() noexcept = default;
174 :
175 10692 : 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 10692 : : first_(first)
181 10692 : , last_(last)
182 10692 : , front_skip_(front_skip)
183 10692 : , back_skip_(back_skip)
184 : {
185 10692 : }
186 :
187 34863 : const_iterator begin() const noexcept
188 : {
189 : return const_iterator(
190 34863 : first_, first_, last_, front_skip_, back_skip_);
191 : }
192 :
193 34891 : const_iterator end() const noexcept
194 : {
195 : return const_iterator(
196 34891 : last_, first_, last_, front_skip_, back_skip_);
197 : }
198 : };
199 :
200 MIS 0 : slice_impl() noexcept = default;
201 :
202 HIT 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 4377 : slice_impl(
209 : BufferSequence const& bs,
210 : std::size_t offset,
211 : std::size_t length) noexcept
212 4377 : {
213 4377 : auto it_begin = capy::begin(bs);
214 4377 : auto it_end = capy::end(bs);
215 :
216 4377 : std::size_t total = 0;
217 10956 : for (auto it = it_begin; it != it_end; ++it)
218 6579 : total += (*it).size();
219 :
220 4377 : if (offset > total)
221 1 : offset = total;
222 4377 : std::size_t const remaining = total - offset;
223 4377 : if (length > remaining)
224 2293 : length = remaining;
225 :
226 4377 : first_ = it_begin;
227 4377 : last_ = it_end;
228 :
229 4377 : std::size_t skip = offset;
230 4756 : while (first_ != last_)
231 : {
232 4658 : std::size_t const buf_size = (*first_).size();
233 4658 : if (skip < buf_size)
234 : {
235 4279 : front_skip_ = skip;
236 4279 : break;
237 : }
238 379 : skip -= buf_size;
239 379 : ++first_;
240 : }
241 :
242 4377 : std::size_t left = length;
243 4377 : auto cursor = first_;
244 4377 : std::size_t cursor_front = front_skip_;
245 5734 : while (cursor != last_ && left > 0)
246 : {
247 5358 : std::size_t const buf_size = (*cursor).size();
248 5358 : std::size_t const avail = buf_size - cursor_front;
249 5358 : if (left <= avail)
250 : {
251 4001 : back_skip_ = avail - left;
252 4001 : ++cursor;
253 4001 : last_ = cursor;
254 4001 : return;
255 : }
256 1357 : left -= avail;
257 1357 : ++cursor;
258 1357 : cursor_front = 0;
259 : }
260 :
261 376 : last_ = cursor;
262 : }
263 :
264 10692 : data_view data() const noexcept
265 : {
266 10692 : return data_view(first_, last_, front_skip_, back_skip_);
267 : }
268 :
269 746 : void remove_prefix(std::size_t n) noexcept
270 : {
271 1062 : while (n > 0 && first_ != last_)
272 : {
273 922 : std::size_t const buf_total = (*first_).size();
274 922 : std::size_t live = buf_total - front_skip_;
275 922 : auto next = first_;
276 922 : ++next;
277 922 : bool const is_last = (next == last_);
278 922 : if (is_last)
279 406 : live -= back_skip_;
280 :
281 922 : if (n < live)
282 : {
283 467 : front_skip_ += n;
284 471 : return;
285 : }
286 :
287 455 : n -= live;
288 455 : if (is_last)
289 : {
290 139 : first_ = last_;
291 139 : front_skip_ = 0;
292 139 : back_skip_ = 0;
293 139 : return;
294 : }
295 316 : ++first_;
296 316 : front_skip_ = 0;
297 : }
298 : }
299 : };
300 :
301 : } // namespace detail
302 : } // namespace capy
303 : } // namespace boost
304 :
305 : #endif
|