100.00% Lines (7/7)
100.00% Functions (1/1)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | // | 1 | // | |||||
| 2 | // Copyright (c) 2026 Michael Vandeberg | 2 | // Copyright (c) 2026 Michael Vandeberg | |||||
| 3 | // | 3 | // | |||||
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | 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) | 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||||
| 6 | // | 6 | // | |||||
| 7 | // Official repository: https://github.com/cppalliance/capy | 7 | // Official repository: https://github.com/cppalliance/capy | |||||
| 8 | // | 8 | // | |||||
| 9 | 9 | |||||||
| 10 | #ifndef BOOST_CAPY_BUFFERS_BUFFER_SLICE_HPP | 10 | #ifndef BOOST_CAPY_BUFFERS_BUFFER_SLICE_HPP | |||||
| 11 | #define BOOST_CAPY_BUFFERS_BUFFER_SLICE_HPP | 11 | #define BOOST_CAPY_BUFFERS_BUFFER_SLICE_HPP | |||||
| 12 | 12 | |||||||
| 13 | #include <boost/capy/detail/config.hpp> | 13 | #include <boost/capy/detail/config.hpp> | |||||
| 14 | #include <boost/capy/buffers.hpp> | 14 | #include <boost/capy/buffers.hpp> | |||||
| 15 | #include <boost/capy/detail/slice_of.hpp> | 15 | #include <boost/capy/detail/slice_of.hpp> | |||||
| 16 | 16 | |||||||
| 17 | #include <concepts> | 17 | #include <concepts> | |||||
| 18 | #include <cstddef> | 18 | #include <cstddef> | |||||
| 19 | #include <limits> | 19 | #include <limits> | |||||
| 20 | #include <type_traits> | 20 | #include <type_traits> | |||||
| 21 | 21 | |||||||
| 22 | namespace boost { | 22 | namespace boost { | |||||
| 23 | namespace capy { | 23 | namespace capy { | |||||
| 24 | 24 | |||||||
| 25 | /** The type produced by `buffer_slice` for a sequence `BS`. | 25 | /** The type produced by `buffer_slice` for a sequence `BS`. | |||||
| 26 | 26 | |||||||
| 27 | A single buffer is closed under sub-ranging, so slicing it yields a | 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 | 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 | 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> }`. | 30 | a buffer sequence — `slice_type<BS> ∈ { buffer, slice_of<BS> }`. | |||||
| 31 | */ | 31 | */ | |||||
| 32 | template<class BS> | 32 | template<class BS> | |||||
| 33 | using slice_type = std::conditional_t< | 33 | using slice_type = std::conditional_t< | |||||
| 34 | std::convertible_to<BS, const_buffer>, | 34 | std::convertible_to<BS, const_buffer>, | |||||
| 35 | buffer_type<BS>, | 35 | buffer_type<BS>, | |||||
| 36 | detail::slice_of<BS>>; | 36 | detail::slice_of<BS>>; | |||||
| 37 | 37 | |||||||
| 38 | /** Return a byte sub-range of a buffer sequence, as a value. | 38 | /** Return a byte sub-range of a buffer sequence, as a value. | |||||
| 39 | 39 | |||||||
| 40 | The result is itself a buffer sequence (`slice_type<BS>`): pass it | 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 | 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 | 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 | 43 | result is an adjusted buffer; for any other sequence it is a borrowed | |||||
| 44 | `slice_of<BS>` view. | 44 | `slice_of<BS>` view. | |||||
| 45 | 45 | |||||||
| 46 | @par Lifetime | 46 | @par Lifetime | |||||
| 47 | Except for the single-buffer case, the result borrows `seq`: it stores | 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. | 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 | 49 | The rvalue overload is deleted so a temporary cannot be sliced into a | |||||
| 50 | dangling view. | 50 | dangling view. | |||||
| 51 | 51 | |||||||
| 52 | @par Complexity | 52 | @par Complexity | |||||
| 53 | Single forward pass to the cut points; never sums the whole sequence. | 53 | Single forward pass to the cut points; never sums the whole sequence. | |||||
| 54 | 54 | |||||||
| 55 | @param seq The sequence to slice. Must outlive the result. | 55 | @param seq The sequence to slice. Must outlive the result. | |||||
| 56 | @param offset Bytes skipped from the front. Clamped to the total size. | 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. | 57 | @param length Bytes exposed, starting at `offset`. Defaults to the end. | |||||
| 58 | 58 | |||||||
| 59 | @return A `slice_type<BS>` value modeling the same buffer-sequence | 59 | @return A `slice_type<BS>` value modeling the same buffer-sequence | |||||
| 60 | concept as `seq` (mutable if `seq` is mutable). | 60 | concept as `seq` (mutable if `seq` is mutable). | |||||
| 61 | 61 | |||||||
| 62 | @par Example | 62 | @par Example | |||||
| 63 | @code | 63 | @code | |||||
| 64 | co_await write(sock, buffer_slice(bufs, 0, 16384)); // first 16 KB | 64 | co_await write(sock, buffer_slice(bufs, 0, 16384)); // first 16 KB | |||||
| 65 | auto rest = buffer_slice(bufs, n); // drop first n | 65 | auto rest = buffer_slice(bufs, n); // drop first n | |||||
| 66 | @endcode | 66 | @endcode | |||||
| 67 | 67 | |||||||
| 68 | @see slice_type, consuming_buffers | 68 | @see slice_type, consuming_buffers | |||||
| 69 | */ | 69 | */ | |||||
| 70 | template<class BufferSequence> | 70 | template<class BufferSequence> | |||||
| 71 | requires MutableBufferSequence<BufferSequence> | 71 | requires MutableBufferSequence<BufferSequence> | |||||
| 72 | || ConstBufferSequence<BufferSequence> | 72 | || ConstBufferSequence<BufferSequence> | |||||
| 73 | slice_type<BufferSequence> | 73 | slice_type<BufferSequence> | |||||
| HITCBC | 74 | 2576 | buffer_slice( | 74 | 2576 | buffer_slice( | ||
| 75 | BufferSequence const& seq, | 75 | BufferSequence const& seq, | |||||
| 76 | std::size_t offset = 0, | 76 | std::size_t offset = 0, | |||||
| 77 | std::size_t length = | 77 | std::size_t length = | |||||
| 78 | (std::numeric_limits<std::size_t>::max)()) noexcept | 78 | (std::numeric_limits<std::size_t>::max)()) noexcept | |||||
| 79 | { | 79 | { | |||||
| 80 | if constexpr (std::convertible_to<BufferSequence, const_buffer>) | 80 | if constexpr (std::convertible_to<BufferSequence, const_buffer>) | |||||
| 81 | { | 81 | { | |||||
| 82 | // A single buffer is its own slice: advance and (maybe) truncate. | 82 | // A single buffer is its own slice: advance and (maybe) truncate. | |||||
| HITCBC | 83 | 292 | buffer_type<BufferSequence> b = seq; | 83 | 292 | buffer_type<BufferSequence> b = seq; | ||
| HITCBC | 84 | 292 | b += offset; // operator+= clamps to size() | 84 | 292 | b += offset; // operator+= clamps to size() | ||
| HITCBC | 85 | 292 | if (length < b.size()) | 85 | 292 | if (length < b.size()) | ||
| HITCBC | 86 | 115 | b = buffer_type<BufferSequence>(b.data(), length); | 86 | 115 | b = buffer_type<BufferSequence>(b.data(), length); | ||
| HITCBC | 87 | 292 | return b; | 87 | 292 | return b; | ||
| 88 | } | 88 | } | |||||
| 89 | else | 89 | else | |||||
| 90 | { | 90 | { | |||||
| HITCBC | 91 | 2284 | return detail::slice_of<BufferSequence>(seq, offset, length); | 91 | 2284 | return detail::slice_of<BufferSequence>(seq, offset, length); | ||
| 92 | } | 92 | } | |||||
| 93 | } | 93 | } | |||||
| 94 | 94 | |||||||
| 95 | /** Deleted rvalue overload. | 95 | /** Deleted rvalue overload. | |||||
| 96 | 96 | |||||||
| 97 | Slicing a temporary would yield an immediately dangling view (the | 97 | Slicing a temporary would yield an immediately dangling view (the | |||||
| 98 | result borrows the sequence). Hoist the sequence into a named variable | 98 | result borrows the sequence). Hoist the sequence into a named variable | |||||
| 99 | first. | 99 | first. | |||||
| 100 | */ | 100 | */ | |||||
| 101 | template<class BufferSequence> | 101 | template<class BufferSequence> | |||||
| 102 | requires MutableBufferSequence<BufferSequence> | 102 | requires MutableBufferSequence<BufferSequence> | |||||
| 103 | || ConstBufferSequence<BufferSequence> | 103 | || ConstBufferSequence<BufferSequence> | |||||
| 104 | slice_type<BufferSequence> | 104 | slice_type<BufferSequence> | |||||
| 105 | buffer_slice( | 105 | buffer_slice( | |||||
| 106 | BufferSequence const&& seq, | 106 | BufferSequence const&& seq, | |||||
| 107 | std::size_t offset = 0, | 107 | std::size_t offset = 0, | |||||
| 108 | std::size_t length = | 108 | std::size_t length = | |||||
| 109 | (std::numeric_limits<std::size_t>::max)()) = delete; | 109 | (std::numeric_limits<std::size_t>::max)()) = delete; | |||||
| 110 | 110 | |||||||
| 111 | } // namespace capy | 111 | } // namespace capy | |||||
| 112 | } // namespace boost | 112 | } // namespace boost | |||||
| 113 | 113 | |||||||
| 114 | #endif | 114 | #endif | |||||