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