100.00% Lines (2/2)
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_impl.hpp> | 15 | #include <boost/capy/detail/slice_impl.hpp> | |||||
| 16 | 16 | |||||||
| 17 | #include <cstddef> | 17 | #include <cstddef> | |||||
| 18 | #include <limits> | 18 | #include <limits> | |||||
| 19 | 19 | |||||||
| 20 | namespace boost { | 20 | namespace boost { | |||||
| 21 | namespace capy { | 21 | namespace capy { | |||||
| 22 | 22 | |||||||
| 23 | /** Return a byte-range slice of a buffer sequence. | 23 | /** Return a byte-range slice of a buffer sequence. | |||||
| 24 | 24 | |||||||
| 25 | Constructs a view over a contiguous byte range of `seq`. The | 25 | Constructs a view over a contiguous byte range of `seq`. The | |||||
| 26 | slice exposes its current bytes via `data()` (a buffer sequence) | 26 | slice exposes its current bytes via `data()` (a buffer sequence) | |||||
| 27 | and supports incremental consumption via `remove_prefix(n)`. | 27 | and supports incremental consumption via `remove_prefix(n)`. | |||||
| 28 | 28 | |||||||
| 29 | @par Return Value | 29 | @par Return Value | |||||
| 30 | An object of unspecified type satisfying the @ref Slice concept. | 30 | An object of unspecified type satisfying the @ref Slice concept. | |||||
| 31 | Bind with `auto` and operate through the concept's members. When | 31 | Bind with `auto` and operate through the concept's members. When | |||||
| 32 | `seq` models @ref MutableBufferSequence, the returned object | 32 | `seq` models @ref MutableBufferSequence, the returned object | |||||
| 33 | additionally models @ref MutableSlice. | 33 | additionally models @ref MutableSlice. | |||||
| 34 | 34 | |||||||
| 35 | @par Lifetime | 35 | @par Lifetime | |||||
| 36 | The returned slice is associated with `seq` as its underlying | 36 | The returned slice is associated with `seq` as its underlying | |||||
| 37 | buffer sequence. `seq` — and the memory referenced by its buffer | 37 | buffer sequence. `seq` — and the memory referenced by its buffer | |||||
| 38 | descriptors — must remain valid for as long as the slice, or | 38 | descriptors — must remain valid for as long as the slice, or | |||||
| 39 | any buffer sequence obtained from its `data()`, is in use. | 39 | any buffer sequence obtained from its `data()`, is in use. | |||||
| 40 | Passing a temporary buffer sequence to `buffer_slice` produces | 40 | Passing a temporary buffer sequence to `buffer_slice` produces | |||||
| 41 | a dangling slice. | 41 | a dangling slice. | |||||
| 42 | 42 | |||||||
| 43 | The buffer sequence returned by `data()` is independent of the | 43 | The buffer sequence returned by `data()` is independent of the | |||||
| 44 | slice object: subsequent operations on the slice (mutation, | 44 | slice object: subsequent operations on the slice (mutation, | |||||
| 45 | copy, move, destruction) do not invalidate an already-obtained | 45 | copy, move, destruction) do not invalidate an already-obtained | |||||
| 46 | `data()` view. It remains valid for as long as `seq` is valid. | 46 | `data()` view. It remains valid for as long as `seq` is valid. | |||||
| 47 | 47 | |||||||
| 48 | Iterators and buffer descriptors obtained through `data()` | 48 | Iterators and buffer descriptors obtained through `data()` | |||||
| 49 | follow the same invalidation rules as those of `seq`. | 49 | follow the same invalidation rules as those of `seq`. | |||||
| 50 | 50 | |||||||
| 51 | @par Parameters | 51 | @par Parameters | |||||
| 52 | @li `seq` The underlying buffer sequence. Must outlive the | 52 | @li `seq` The underlying buffer sequence. Must outlive the | |||||
| 53 | returned slice and any `data()` view obtained from it. | 53 | returned slice and any `data()` view obtained from it. | |||||
| 54 | @li `offset` Number of bytes to skip from the start of `seq`. | 54 | @li `offset` Number of bytes to skip from the start of `seq`. | |||||
| 55 | Clamped to `buffer_size(seq)`. | 55 | Clamped to `buffer_size(seq)`. | |||||
| 56 | @li `length` Maximum number of bytes the slice will expose, | 56 | @li `length` Maximum number of bytes the slice will expose, | |||||
| 57 | starting at `offset`. Clamped to `buffer_size(seq) - offset`. | 57 | starting at `offset`. Clamped to `buffer_size(seq) - offset`. | |||||
| 58 | Defaults to the maximum value of `std::size_t`, i.e. "to end". | 58 | Defaults to the maximum value of `std::size_t`, i.e. "to end". | |||||
| 59 | 59 | |||||||
| 60 | @par Example | 60 | @par Example | |||||
| 61 | @code | 61 | @code | |||||
| 62 | template< ReadStream Stream, MutableBufferSequence MB > | 62 | template< ReadStream Stream, MutableBufferSequence MB > | |||||
| 63 | task< io_result< std::size_t > > | 63 | task< io_result< std::size_t > > | |||||
| 64 | read_all( Stream& stream, MB buffers ) | 64 | read_all( Stream& stream, MB buffers ) | |||||
| 65 | { | 65 | { | |||||
| 66 | auto s = buffer_slice( buffers ); | 66 | auto s = buffer_slice( buffers ); | |||||
| 67 | std::size_t const total_size = buffer_size( buffers ); | 67 | std::size_t const total_size = buffer_size( buffers ); | |||||
| 68 | std::size_t total = 0; | 68 | std::size_t total = 0; | |||||
| 69 | while( total < total_size ) | 69 | while( total < total_size ) | |||||
| 70 | { | 70 | { | |||||
| 71 | auto [ec, n] = co_await stream.read_some( s.data() ); | 71 | auto [ec, n] = co_await stream.read_some( s.data() ); | |||||
| 72 | s.remove_prefix( n ); | 72 | s.remove_prefix( n ); | |||||
| 73 | total += n; | 73 | total += n; | |||||
| 74 | if( ec ) | 74 | if( ec ) | |||||
| 75 | co_return {ec, total}; | 75 | co_return {ec, total}; | |||||
| 76 | } | 76 | } | |||||
| 77 | co_return {{}, total}; | 77 | co_return {{}, total}; | |||||
| 78 | } | 78 | } | |||||
| 79 | @endcode | 79 | @endcode | |||||
| 80 | 80 | |||||||
| 81 | @see Slice, MutableSlice | 81 | @see Slice, MutableSlice | |||||
| 82 | */ | 82 | */ | |||||
| 83 | template<class BufferSequence> | 83 | template<class BufferSequence> | |||||
| 84 | requires MutableBufferSequence<BufferSequence> | 84 | requires MutableBufferSequence<BufferSequence> | |||||
| 85 | || ConstBufferSequence<BufferSequence> | 85 | || ConstBufferSequence<BufferSequence> | |||||
| 86 | auto | 86 | auto | |||||
| HITCBC | 87 | 4369 | buffer_slice( | 87 | 4369 | buffer_slice( | ||
| 88 | BufferSequence const& seq, | 88 | BufferSequence const& seq, | |||||
| 89 | std::size_t offset = 0, | 89 | std::size_t offset = 0, | |||||
| 90 | std::size_t length = | 90 | std::size_t length = | |||||
| 91 | (std::numeric_limits<std::size_t>::max)()) noexcept | 91 | (std::numeric_limits<std::size_t>::max)()) noexcept | |||||
| 92 | { | 92 | { | |||||
| HITCBC | 93 | 4369 | return detail::slice_impl<BufferSequence>(seq, offset, length); | 93 | 4369 | return detail::slice_impl<BufferSequence>(seq, offset, length); | ||
| 94 | } | 94 | } | |||||
| 95 | 95 | |||||||
| 96 | /** Deleted overload that rejects rvalue arguments at compile time. | 96 | /** Deleted overload that rejects rvalue arguments at compile time. | |||||
| 97 | 97 | |||||||
| 98 | Because the returned slice's validity depends on the underlying | 98 | Because the returned slice's validity depends on the underlying | |||||
| 99 | buffer sequence remaining alive, calling `buffer_slice` with a | 99 | buffer sequence remaining alive, calling `buffer_slice` with a | |||||
| 100 | temporary buffer sequence would produce an immediately dangling | 100 | temporary buffer sequence would produce an immediately dangling | |||||
| 101 | slice. This overload makes such calls ill-formed, surfacing the | 101 | slice. This overload makes such calls ill-formed, surfacing the | |||||
| 102 | lifetime error at compile time rather than as runtime UB. | 102 | lifetime error at compile time rather than as runtime UB. | |||||
| 103 | 103 | |||||||
| 104 | To slice a buffer sequence produced as a temporary, hoist it | 104 | To slice a buffer sequence produced as a temporary, hoist it | |||||
| 105 | into a named variable first: | 105 | into a named variable first: | |||||
| 106 | 106 | |||||||
| 107 | @code | 107 | @code | |||||
| 108 | auto bufs = some_dynamic_buffer.data(); // named, lives in scope | 108 | auto bufs = some_dynamic_buffer.data(); // named, lives in scope | |||||
| 109 | auto s = buffer_slice( bufs ); // OK | 109 | auto s = buffer_slice( bufs ); // OK | |||||
| 110 | @endcode | 110 | @endcode | |||||
| 111 | */ | 111 | */ | |||||
| 112 | template<class BufferSequence> | 112 | template<class BufferSequence> | |||||
| 113 | requires MutableBufferSequence<BufferSequence> | 113 | requires MutableBufferSequence<BufferSequence> | |||||
| 114 | || ConstBufferSequence<BufferSequence> | 114 | || ConstBufferSequence<BufferSequence> | |||||
| 115 | auto | 115 | auto | |||||
| 116 | buffer_slice( | 116 | buffer_slice( | |||||
| 117 | BufferSequence const&& seq, | 117 | BufferSequence const&& seq, | |||||
| 118 | std::size_t offset = 0, | 118 | std::size_t offset = 0, | |||||
| 119 | std::size_t length = | 119 | std::size_t length = | |||||
| 120 | (std::numeric_limits<std::size_t>::max)()) = delete; | 120 | (std::numeric_limits<std::size_t>::max)()) = delete; | |||||
| 121 | 121 | |||||||
| 122 | } // namespace capy | 122 | } // namespace capy | |||||
| 123 | } // namespace boost | 123 | } // namespace boost | |||||
| 124 | 124 | |||||||
| 125 | #endif | 125 | #endif | |||||