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