0.00% Lines (0/0) 0.00% Functions (0/0)
TLA Baseline Branch
Line Hits Code Line Hits 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_SLICE_HPP  
11 - #define BOOST_CAPY_BUFFERS_SLICE_HPP  
12 -  
13 - #include <boost/capy/detail/config.hpp>  
14 - #include <boost/capy/buffers.hpp>  
15 - #include <array>  
16 - #include <cassert>  
17 - #include <iterator>  
18 - #include <type_traits>  
19 -  
20 - namespace boost {  
21 - namespace capy {  
22 -  
23 - template<class T> class slice_of;  
24 -  
25 - namespace detail {  
26 -  
27 - template<class T, class = void>  
28 - struct has_tag_invoke : std::false_type {};  
29 -  
30 - template<class T>  
31 - struct has_tag_invoke<T, decltype(tag_invoke(  
32 - std::declval<slice_tag const&>(),  
33 - std::declval<T&>(),  
34 - std::declval<slice_how>(),  
35 - std::declval<std::size_t>()))>  
36 - : std::true_type {};  
37 -  
38 - } // detail  
39 -  
40 - /** Alias for the type representing a slice of T  
41 - */  
42 - template<class T>  
43 - using slice_type = std::conditional_t<  
44 - detail::has_tag_invoke<T>::value,  
45 - T, slice_of<T>>;  
46 -  
47 - //------------------------------------------------  
48 -  
49 - /** A wrapper enabling a buffer sequence to be consumed  
50 - */  
51 - template<ConstBufferSequence BufferSequence>  
52 - class slice_of<BufferSequence>  
53 - {  
54 - static_assert(!std::is_const_v<BufferSequence>,  
55 - "BufferSequence can't be const");  
56 -  
57 - static_assert(!std::is_reference_v<BufferSequence>,  
58 - "BufferSequence can't be a reference");  
59 -  
60 - using iter_type = decltype(  
61 - std::declval<BufferSequence const&>().begin());  
62 -  
63 - using difference_type =  
64 - typename std::iterator_traits<iter_type>::difference_type;  
65 -  
66 - BufferSequence bs_;  
67 - difference_type begin_ = 0; // index of first buffer in sequence  
68 - difference_type end_ = 0; // 1 + index of last buffer in sequence  
69 - std::size_t len_ = 0; // length of bs_  
70 - std::size_t size_ = 0; // total bytes  
71 - std::size_t prefix_ = 0; // used prefix bytes  
72 - std::size_t suffix_ = 0; // used suffix bytes  
73 -  
74 - public:  
75 - /** The type of values returned by iterators  
76 - */  
77 - using value_type = std::conditional_t<  
78 - MutableBufferSequence<BufferSequence>,  
79 - mutable_buffer, const_buffer>;  
80 -  
81 - /** The type of returned iterators  
82 - */  
83 - class const_iterator  
84 - {  
85 - iter_type it_;  
86 - // VFALCO we could just point back to  
87 - // the original sequence to save size  
88 - std::size_t prefix_ = 0;  
89 - std::size_t suffix_ = 0;  
90 - std::size_t i_ = 0;  
91 - std::size_t n_ = 0;  
92 -  
93 - friend class slice_of<BufferSequence>;  
94 -  
DCB 95 - 6652 const_iterator(  
96 - iter_type it,  
97 - std::size_t prefix__,  
98 - std::size_t suffix__,  
99 - std::size_t i,  
100 - std::size_t n) noexcept  
DCB 101 - 6652 : it_(it)  
DCB 102 - 6652 , prefix_(prefix__)  
DCB 103 - 6652 , suffix_(suffix__)  
DCB 104 - 6652 , i_(i)  
DCB 105 - 6652 , n_(n)  
106 - {  
107 - // n_ is the index of the end iterator  
DCB 108 - 6652 }  
109 -  
110 - public:  
111 - using value_type = typename slice_of::value_type;  
112 - using reference = value_type;  
113 - using pointer = void;  
114 - using difference_type = std::ptrdiff_t;  
115 - using iterator_category =  
116 - std::bidirectional_iterator_tag;  
117 - using iterator_concept = std::bidirectional_iterator_tag;  
118 -  
119 - const_iterator() = default;  
120 -  
121 - bool  
DCB 122 - 9116 operator==(  
123 - const_iterator const& other) const noexcept  
124 - {  
125 - return  
DCB 126 - 9144 it_ == other.it_ &&  
DCB 127 - 3326 prefix_ == other.prefix_ &&  
DCB 128 - 3326 suffix_ == other.suffix_ &&  
DCB 129 - 15768 i_ == other.i_ &&  
DCB 130 - 12442 n_ == other.n_;  
131 - }  
132 -  
133 - bool  
DCB 134 - 9116 operator!=(  
135 - const_iterator const& other) const noexcept  
136 - {  
DCB 137 - 9116 return !(*this == other);  
138 - }  
139 -  
140 - reference  
DCB 141 - 5790 operator*() const noexcept  
142 - {  
DCB 143 - 5790 value_type v = *it_;  
144 - using P = std::conditional_t<  
145 - MutableBufferSequence<BufferSequence>,  
146 - char*, char const*>;  
DCB 147 - 5790 auto p = reinterpret_cast<P>(v.data());  
DCB 148 - 5790 auto n = v.size();  
DCB 149 - 5790 if(i_ == 0)  
150 - {  
DCB 151 - 2943 p += prefix_;  
DCB 152 - 2943 n -= prefix_;  
153 - }  
DCB 154 - 5790 if(i_ == n_ - 1)  
DCB 155 - 2943 n -= suffix_;  
DCB 156 - 5790 return value_type(p, n);  
157 - }  
158 -  
159 - const_iterator&  
DCB 160 - 4502 operator++() noexcept  
161 - {  
DCB 162 - 4502 BOOST_CAPY_ASSERT(i_ < n_);  
DCB 163 - 4502 ++it_;  
DCB 164 - 4502 ++i_;  
DCB 165 - 4502 return *this;  
166 - }  
167 -  
168 - const_iterator  
DCB 169 - 644 operator++(int) noexcept  
170 - {  
DCB 171 - 644 auto temp = *this;  
DCB 172 - 644 ++(*this);  
DCB 173 - 644 return temp;  
174 - }  
175 -  
176 - const_iterator&  
DCB 177 - 1288 operator--() noexcept  
178 - {  
DCB 179 - 1288 BOOST_CAPY_ASSERT(i_ > 0);  
DCB 180 - 1288 --it_;  
DCB 181 - 1288 --i_;  
DCB 182 - 1288 return *this;  
183 - }  
184 -  
185 - const_iterator  
DCB 186 - 644 operator--(int) noexcept  
187 - {  
DCB 188 - 644 auto temp = *this;  
DCB 189 - 644 --(*this);  
DCB 190 - 644 return temp;  
191 - }  
192 - };  
193 -  
194 - /** Constructor  
195 - */  
196 - slice_of() = default;  
197 -  
198 - /** Constructor  
199 - */  
DCB 200 - 194 slice_of(  
201 - BufferSequence const& bs)  
DCB 202 - 194 : bs_(bs)  
203 - {  
DCB 204 - 194 iter_type it = capy::begin(bs_);  
DCB 205 - 194 iter_type eit = capy::end(bs_);  
DCB 206 - 194 begin_ = 0;  
DCB 207 - 194 end_ = std::distance(it, eit);  
DCB 208 - 776 while(it != eit)  
209 - {  
DCB 210 - 582 value_type b(*it);  
DCB 211 - 582 size_ += b.size();  
DCB 212 - 582 ++len_;  
DCB 213 - 582 ++it;  
214 - }  
DCB 215 - 194 }  
216 -  
217 - /** Return an iterator to the beginning of the sequence  
218 - */  
219 - const_iterator  
DCB 220 - 3326 begin() const noexcept  
221 - {  
222 - return const_iterator(  
DCB 223 - 3326 begin_iter_impl(), prefix_, suffix_, 0, len_);  
224 - }  
225 -  
226 - /** Return an iterator to the end of the sequence  
227 - */  
228 - const_iterator  
DCB 229 - 3326 end() const noexcept  
230 - {  
231 - return const_iterator(  
DCB 232 - 3326 end_iter_impl(), prefix_, suffix_, len_, len_);  
233 - }  
234 -  
235 - friend  
236 - void  
DCB 237 - 671 tag_invoke(  
238 - slice_tag const&,  
239 - slice_of<BufferSequence>& bs,  
240 - slice_how how,  
241 - std::size_t n)  
242 - {  
DCB 243 - 671 bs.slice_impl(how, n);  
DCB 244 - 671 }  
245 -  
246 - private:  
247 - iter_type  
DCB 248 - 3938 begin_iter_impl() const noexcept  
249 - {  
DCB 250 - 3938 iter_type it = capy::begin(bs_);  
DCB 251 - 3938 std::advance(it, begin_);  
DCB 252 - 3938 return it;  
253 - }  
254 -  
255 - iter_type  
DCB 256 - 3591 end_iter_impl() const noexcept  
257 - {  
DCB 258 - 3591 iter_type it = capy::begin(bs_);  
DCB 259 - 3591 std::advance(it, end_);  
DCB 260 - 3591 return it;  
261 - }  
262 -  
263 - void  
DCB 264 - 347 remove_prefix_impl(  
265 - std::size_t n)  
266 - {  
DCB 267 - 347 if(n > size_)  
DCB 268 - 25 n = size_;  
269 -  
270 - // nice hack to simplify the loop (M. Nejati)  
DCB 271 - 347 n += prefix_;  
DCB 272 - 347 size_ += prefix_;  
DCB 273 - 347 prefix_ = 0;  
274 -  
DCB 275 - 347 iter_type it = begin_iter_impl();  
276 -  
DCB 277 - 709 while(n > 0 && begin_ != end_)  
278 - {  
DCB 279 - 612 value_type b = *it;  
DCB 280 - 612 if(n < b.size())  
281 - {  
DCB 282 - 250 prefix_ = n;  
DCB 283 - 250 size_ -= n;  
DCB 284 - 250 break;  
285 - }  
DCB 286 - 362 n -= b.size();  
DCB 287 - 362 size_ -= b.size();  
DCB 288 - 362 ++begin_;  
DCB 289 - 362 ++it;  
DCB 290 - 362 --len_;  
291 - }  
DCB 292 - 347 }  
293 -  
294 - void  
DCB 295 - 265 remove_suffix_impl(  
296 - std::size_t n)  
297 - {  
DCB 298 - 265 if(size_ == 0)  
299 - {  
DUB 300 - BOOST_CAPY_ASSERT(begin_ == end_);  
DCB 301 - 265 return;  
302 - }  
DCB 303 - 265 BOOST_CAPY_ASSERT(begin_ != end_);  
304 -  
DCB 305 - 265 if(n > size_)  
DUB 306 - n = size_;  
307 -  
DCB 308 - 265 n += suffix_;  
DCB 309 - 265 size_ += suffix_;  
DCB 310 - 265 suffix_ = 0;  
311 -  
DCB 312 - 265 iter_type bit = begin_iter_impl();  
DCB 313 - 265 iter_type it = end_iter_impl();  
DCB 314 - 265 it--;  
315 -  
DCB 316 - 517 while(it != bit)  
317 - {  
DCB 318 - 391 value_type b = *it;  
DCB 319 - 391 if(n < b.size())  
320 - {  
DCB 321 - 139 suffix_ = n;  
DCB 322 - 139 size_ -= n;  
DCB 323 - 139 return;  
324 - }  
DCB 325 - 252 n -= b.size();  
DCB 326 - 252 size_ -= b.size();  
DCB 327 - 252 --it;  
DCB 328 - 252 --end_;  
DCB 329 - 252 --len_;  
330 - }  
DCB 331 - 126 value_type b = *it;  
DCB 332 - 126 auto m = b.size() - prefix_;  
DCB 333 - 126 if(n < m)  
334 - {  
DCB 335 - 126 suffix_ = n;  
DCB 336 - 126 size_ -= n;  
DCB 337 - 126 return;  
338 - }  
DUB 339 - end_ = begin_;  
DUB 340 - len_ = 0;  
DUB 341 - size_ = 0;  
342 - }  
343 -  
344 - void  
DCB 345 - 324 keep_prefix_impl(  
346 - std::size_t n)  
347 - {  
DCB 348 - 324 if(n >= size_)  
DCB 349 - 9 return;  
DCB 350 - 315 if(n == 0)  
351 - {  
DCB 352 - 50 end_ = begin_;  
DCB 353 - 50 len_ = 0;  
DCB 354 - 50 size_ = 0;  
DCB 355 - 50 return;  
356 - }  
DCB 357 - 265 remove_suffix_impl(size_ - n);  
358 - }  
359 -  
360 - void  
361 - keep_suffix_impl(  
362 - std::size_t n)  
363 - {  
364 - if(n >= size_)  
365 - return;  
366 - if(n == 0)  
367 - {  
368 - begin_ = end_;  
369 - len_ = 0;  
370 - size_ = 0;  
371 - return;  
372 - }  
373 - remove_prefix_impl(size_ - n);  
374 - }  
375 -  
376 - void  
DCB 377 - 671 slice_impl(  
378 - slice_how how,  
379 - std::size_t n)  
380 - {  
DCB 381 - 671 switch(how)  
382 - {  
DCB 383 - 347 case slice_how::remove_prefix:  
384 - {  
DCB 385 - 347 remove_prefix_impl(n);  
DCB 386 - 347 break;  
387 - }  
DCB 388 - 324 case slice_how::keep_prefix:  
389 - {  
DCB 390 - 324 keep_prefix_impl(n);  
DCB 391 - 324 break;  
392 - }  
393 - }  
DCB 394 - 671 }  
395 - };  
396 -  
397 - //------------------------------------------------  
398 -  
399 - // in-place modify return value  
400 - // -----------------------------  
401 - // keep_prefix* prefix  
402 - // keep_suffix suffix  
403 - // remove_prefix* sans_prefix  
404 - // remove_suffix sans_suffix  
405 -  
406 - /** Remove all but the first `n` bytes from a buffer sequence  
407 - */  
408 - constexpr struct keep_prefix_mrdocs_workaround_t  
409 - {  
410 - template<ConstBufferSequence BufferSequence>  
411 - requires detail::has_tag_invoke<BufferSequence>::value  
DCB 412 - 3142 void operator()(  
413 - BufferSequence& bs,  
414 - std::size_t n) const  
415 - {  
DCB 416 - 3142 tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);  
DCB 417 - 3142 }  
418 - } const keep_prefix{};  
419 -  
420 - /** Remove all but the last `n` bytes from a buffer sequence  
421 - */  
422 - constexpr struct keep_suffix_mrdocs_workaround_t  
423 - {  
424 - template<ConstBufferSequence BufferSequence>  
425 - requires detail::has_tag_invoke<BufferSequence>::value  
DCB 426 - 1132 void operator()(  
427 - BufferSequence& bs,  
428 - std::size_t n) const  
429 - {  
DCB 430 - 1132 auto n0 = buffer_size(bs);  
DCB 431 - 1132 if(n < n0)  
DCB 432 - 998 tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);  
DCB 433 - 1132 }  
434 - } const keep_suffix{};  
435 -  
436 - /** Remove `n` bytes from the beginning of a buffer sequence  
437 - */  
438 - constexpr struct remove_prefix_mrdocs_workaround_t  
439 - {  
440 - template<ConstBufferSequence BufferSequence>  
441 - requires detail::has_tag_invoke<BufferSequence>::value  
DCB 442 - 3369 void operator()(  
443 - BufferSequence& bs,  
444 - std::size_t n) const  
445 - {  
DCB 446 - 3369 tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n);  
DCB 447 - 3369 }  
448 - } const remove_prefix{};  
449 -  
450 - /** Remove `n` bytes from the end of a buffer sequence  
451 - */  
452 - constexpr struct remove_suffix_mrdocs_workaround_t  
453 - {  
454 - template<ConstBufferSequence BufferSequence>  
455 - requires detail::has_tag_invoke<BufferSequence>::value  
DCB 456 - 1386 void operator()(  
457 - BufferSequence& bs,  
458 - std::size_t n) const  
459 - {  
DCB 460 - 1386 auto n0 = buffer_size(bs);  
DCB 461 - 1386 if(n > 0)  
462 - {  
DCB 463 - 1297 if( n > n0)  
DCB 464 - 89 n = n0;  
DCB 465 - 1297 tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);  
466 - }  
DCB 467 - 1386 }  
468 - } const remove_suffix{};  
469 -  
470 - //------------------------------------------------  
471 -  
472 - /** Return a sequence representing the first `n` bytes of a buffer sequence  
473 - */  
474 - constexpr struct prefix_mrdocs_workaround_t  
475 - {  
476 - template<ConstBufferSequence BufferSequence>  
DCB 477 - 944 slice_type<BufferSequence> operator()(  
478 - BufferSequence const& bs,  
479 - std::size_t n) const noexcept  
480 - {  
DCB 481 - 944 slice_type<BufferSequence> result(bs);  
DCB 482 - 944 keep_prefix(result, n);  
DCB 483 - 944 return result;  
484 - }  
485 - } prefix{};  
486 -  
487 - /** Return a sequence representing the last `n` bytes of a buffer sequence  
488 - */  
489 - constexpr struct suffix_mrdocs_workaround_t  
490 - {  
491 - template<ConstBufferSequence BufferSequence>  
492 - slice_type<BufferSequence> operator()(  
493 - BufferSequence const& bs,  
494 - std::size_t n) const noexcept  
495 - {  
496 - slice_type<BufferSequence> result(bs);  
497 - keep_suffix(result, n);  
498 - return result;  
499 - }  
500 - } suffix{};  
501 -  
502 - /** Return a sequence representing all but the first `n` bytes of a buffer sequence  
503 - */  
504 - constexpr struct sans_prefix_mrdocs_workaround_t  
505 - {  
506 - template<ConstBufferSequence BufferSequence>  
DCB 507 - 959 slice_type<BufferSequence> operator()(  
508 - BufferSequence const& bs,  
509 - std::size_t n) const noexcept  
510 - {  
DCB 511 - 959 slice_type<BufferSequence> result(bs);  
DCB 512 - 959 remove_prefix(result, n);  
DCB 513 - 959 return result;  
514 - }  
515 - } sans_prefix{};  
516 -  
517 - /** Return a sequence representing all but the last `n` bytes of a buffer sequence  
518 - */  
519 - constexpr struct sans_suffix_mrdocs_workaround_t  
520 - {  
521 - template<ConstBufferSequence BufferSequence>  
522 - slice_type<BufferSequence> operator()(  
523 - BufferSequence const& bs,  
524 - std::size_t n) const noexcept  
525 - {  
526 - slice_type<BufferSequence> result(bs);  
527 - remove_suffix(result, n);  
528 - return result;  
529 - }  
530 - } sans_suffix{};  
531 -  
532 - } // capy  
533 - } // boost  
534 -  
535 - #endif