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 : /** The type produced by `buffer_slice` 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>`): 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 : @code
64 : co_await write(sock, buffer_slice(bufs, 0, 16384)); // first 16 KB
65 : auto rest = buffer_slice(bufs, n); // drop first n
66 : @endcode
67 :
68 : @see slice_type, consuming_buffers
69 : */
70 : template<class BufferSequence>
71 : requires MutableBufferSequence<BufferSequence>
72 : || ConstBufferSequence<BufferSequence>
73 : slice_type<BufferSequence>
74 HIT 2576 : buffer_slice(
75 : BufferSequence const& seq,
76 : std::size_t offset = 0,
77 : std::size_t length =
78 : (std::numeric_limits<std::size_t>::max)()) noexcept
79 : {
80 : if constexpr (std::convertible_to<BufferSequence, const_buffer>)
81 : {
82 : // A single buffer is its own slice: advance and (maybe) truncate.
83 292 : buffer_type<BufferSequence> b = seq;
84 292 : b += offset; // operator+= clamps to size()
85 292 : if (length < b.size())
86 115 : b = buffer_type<BufferSequence>(b.data(), length);
87 292 : return b;
88 : }
89 : else
90 : {
91 2284 : return detail::slice_of<BufferSequence>(seq, offset, length);
92 : }
93 : }
94 :
95 : /** Deleted rvalue overload.
96 :
97 : Slicing a temporary would yield an immediately dangling view (the
98 : result borrows the sequence). Hoist the sequence into a named variable
99 : first.
100 : */
101 : template<class BufferSequence>
102 : requires MutableBufferSequence<BufferSequence>
103 : || ConstBufferSequence<BufferSequence>
104 : slice_type<BufferSequence>
105 : buffer_slice(
106 : BufferSequence const&& seq,
107 : std::size_t offset = 0,
108 : std::size_t length =
109 : (std::numeric_limits<std::size_t>::max)()) = delete;
110 :
111 : } // namespace capy
112 : } // namespace boost
113 :
114 : #endif
|