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 : #ifndef BOOST_CAPY_BUFFERS_BUFFER_SLICE_HPP
11 : #define BOOST_CAPY_BUFFERS_BUFFER_SLICE_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <boost/capy/buffers.hpp>
15 : #include <boost/capy/detail/slice_of.hpp>
16 :
17 : #include <concepts>
18 : #include <cstddef>
19 : #include <limits>
20 : #include <type_traits>
21 :
22 : namespace boost {
23 : namespace capy {
24 :
25 : /** Names whichever buffer type `buffer_slice` returns for a sequence `BS`.
26 :
27 : A single buffer is closed under sub-ranging, so slicing it yields a
28 : buffer of the same kind. Any other sequence yields the generic
29 : `detail::slice_of<BS>` borrowed view. In both cases the result is itself
30 : a buffer sequence — `slice_type<BS> ∈ { buffer, slice_of<BS> }`.
31 : */
32 : template<class BS>
33 : using slice_type = std::conditional_t<
34 : std::convertible_to<BS, const_buffer>,
35 : buffer_type<BS>,
36 : detail::slice_of<BS>>;
37 :
38 : /** Return a byte sub-range of a buffer sequence, as a value.
39 :
40 : The result is itself a buffer sequence (`slice_type<BS>`), so pass it
41 : directly to any operation expecting a buffer sequence. There is no
42 : `.data()` and no separate concept to bind. For a single buffer the
43 : result is an adjusted buffer; for any other sequence it is a borrowed
44 : `slice_of<BS>` view.
45 :
46 : @par Lifetime
47 : Except for the single-buffer case, the result borrows `seq`: it stores
48 : iterators into the sequence, not a copy. `seq` must outlive the result.
49 : The rvalue overload is deleted so a temporary cannot be sliced into a
50 : dangling view.
51 :
52 : @par Complexity
53 : Single forward pass to the cut points; never sums the whole sequence.
54 :
55 : @param seq The sequence to slice. Must outlive the result.
56 : @param offset Bytes skipped from the front. Clamped to the total size.
57 : @param length Bytes exposed, starting at `offset`. Defaults to the end.
58 :
59 : @return A `slice_type<BS>` value modeling the same buffer-sequence
60 : concept as `seq` (mutable if `seq` is mutable).
61 :
62 : @par Example
63 : @par !example example
64 :
65 :
66 : @see slice_type, consuming_buffers
67 : */
68 : template<class BufferSequence>
69 : requires MutableBufferSequence<BufferSequence>
70 : || ConstBufferSequence<BufferSequence>
71 : slice_type<BufferSequence>
72 HIT 2670 : buffer_slice(
73 : BufferSequence const& seq,
74 : std::size_t offset = 0,
75 : std::size_t length =
76 : (std::numeric_limits<std::size_t>::max)()) noexcept
77 : {
78 : if constexpr (std::convertible_to<BufferSequence, const_buffer>)
79 : {
80 : // A single buffer is its own slice: advance and (maybe) truncate.
81 384 : buffer_type<BufferSequence> b = seq;
82 384 : b += offset; // operator+= clamps to size()
83 384 : if (length < b.size())
84 156 : b = buffer_type<BufferSequence>(b.data(), length);
85 384 : return b;
86 : }
87 : else
88 : {
89 2286 : return detail::slice_of<BufferSequence>(seq, offset, length);
90 : }
91 : }
92 :
93 : /** Rejects a temporary sequence at compile time, since the result would dangle.
94 :
95 : Slicing a temporary would yield an immediately dangling view (the
96 : result borrows the sequence). Hoist the sequence into a named variable
97 : first.
98 : */
99 : template<class BufferSequence>
100 : requires MutableBufferSequence<BufferSequence>
101 : || ConstBufferSequence<BufferSequence>
102 : slice_type<BufferSequence>
103 : buffer_slice(
104 : BufferSequence const&& seq,
105 : std::size_t offset = 0,
106 : std::size_t length =
107 : (std::numeric_limits<std::size_t>::max)()) = delete;
108 :
109 : } // namespace capy
110 : } // namespace boost
111 :
112 : #endif
|