100.00% Lines (72/72) 100.00% Functions (13/13)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Steve Gerbino 2   // Copyright (c) 2026 Steve Gerbino
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_DETAIL_SLICE_OF_HPP 10   #ifndef BOOST_CAPY_DETAIL_SLICE_OF_HPP
11   #define BOOST_CAPY_DETAIL_SLICE_OF_HPP 11   #define BOOST_CAPY_DETAIL_SLICE_OF_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   15  
16   #include <cstddef> 16   #include <cstddef>
17   #include <iterator> 17   #include <iterator>
18   #include <limits> 18   #include <limits>
19   #include <type_traits> 19   #include <type_traits>
20   20  
21   namespace boost { 21   namespace boost {
22   namespace capy { 22   namespace capy {
23   namespace detail { 23   namespace detail {
24   24  
25   /** A borrowed view over a byte sub-range of a buffer sequence. 25   /** A borrowed view over a byte sub-range of a buffer sequence.
26   26  
27 - `slice_of<BS>` is the generic result of `buffer_slice` for a sequence 27 + `slice_of<BS>` is the view `consuming_buffers::data()` returns. It
28 - that is not closed under sub-ranging (everything except a single 28 + models the same buffer-sequence concept as `BS`:
29 - buffer). It models the same buffer-sequence concept as `BS`:  
30   `MutableBufferSequence` if `BS` is mutable, otherwise 29   `MutableBufferSequence` if `BS` is mutable, otherwise
31   `ConstBufferSequence`. It can therefore be passed anywhere a buffer 30   `ConstBufferSequence`. It can therefore be passed anywhere a buffer
32   sequence is expected. 31   sequence is expected.
33   32  
34   It stores iterators into the underlying sequence plus front/back byte 33   It stores iterators into the underlying sequence plus front/back byte
35   offsets; it neither owns nor copies the descriptors. The underlying 34   offsets; it neither owns nor copies the descriptors. The underlying
36   sequence must outlive the view. 35   sequence must outlive the view.
37   36  
38   @par Complexity 37   @par Complexity
39   Construction is a single forward pass to the cut points. It is 38   Construction is a single forward pass to the cut points. It is
40   O(buffers up to `offset`) for a to-end slice, and O(buffers up to 39   O(buffers up to `offset`) for a to-end slice, and O(buffers up to
41   `offset + length`) for a bounded slice. It never sums the whole 40   `offset + length`) for a bounded slice. It never sums the whole
42   sequence. 41   sequence.
43   */ 42   */
44   template<class BS> 43   template<class BS>
45   requires ConstBufferSequence<BS> 44   requires ConstBufferSequence<BS>
46   class slice_of 45   class slice_of
47   { 46   {
48   public: 47   public:
49   /// The buffer type yielded by iteration. 48   /// The buffer type yielded by iteration.
50   using buffer_type = capy::buffer_type<BS>; 49   using buffer_type = capy::buffer_type<BS>;
51   50  
52   /// The underlying sequence's iterator type. 51   /// The underlying sequence's iterator type.
53   using iterator_type = 52   using iterator_type =
54 - decltype(capy::begin(std::declval<BS const&>())); 53 + decltype(capy::buffer_sequence_begin(std::declval<BS const&>()));
55   54  
56   private: 55   private:
57   iterator_type first_{}; 56   iterator_type first_{};
58   iterator_type last_{}; 57   iterator_type last_{};
59   std::size_t front_skip_ = 0; // bytes trimmed from *first_ 58   std::size_t front_skip_ = 0; // bytes trimmed from *first_
60   std::size_t back_skip_ = 0; // bytes trimmed from the final buffer 59   std::size_t back_skip_ = 0; // bytes trimmed from the final buffer
61   60  
62   static buffer_type 61   static buffer_type
HITCBC 63   34174 adjust(buffer_type const& b, 62   34135 adjust(buffer_type const& b,
64   std::size_t front_n, std::size_t back_n) noexcept 63   std::size_t front_n, std::size_t back_n) noexcept
65   { 64   {
66   if constexpr (std::is_same_v<buffer_type, mutable_buffer>) 65   if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
HITCBC 67   17025 return mutable_buffer( 66   17004 return mutable_buffer(
HITCBC 68   17025 static_cast<char*>(b.data()) + front_n, 67   17004 static_cast<char*>(b.data()) + front_n,
HITCBC 69   34050 b.size() - front_n - back_n); 68   34008 b.size() - front_n - back_n);
70   else 69   else
HITCBC 71   17149 return const_buffer( 70   17131 return const_buffer(
HITCBC 72   17149 static_cast<char const*>(b.data()) + front_n, 71   17131 static_cast<char const*>(b.data()) + front_n,
HITCBC 73   34298 b.size() - front_n - back_n); 72   34262 b.size() - front_n - back_n);
74   } 73   }
75   74  
76   public: 75   public:
77   /// Bidirectional iterator that adjusts the first and last buffers. 76   /// Bidirectional iterator that adjusts the first and last buffers.
78   class const_iterator 77   class const_iterator
79   { 78   {
80   iterator_type cur_{}; 79   iterator_type cur_{};
81   iterator_type anchor_first_{}; 80   iterator_type anchor_first_{};
82   iterator_type anchor_last_{}; 81   iterator_type anchor_last_{};
83   std::size_t front_skip_ = 0; 82   std::size_t front_skip_ = 0;
84   std::size_t back_skip_ = 0; 83   std::size_t back_skip_ = 0;
85   84  
86   public: 85   public:
87   using iterator_category = std::bidirectional_iterator_tag; 86   using iterator_category = std::bidirectional_iterator_tag;
88   using value_type = buffer_type; 87   using value_type = buffer_type;
89   using difference_type = std::ptrdiff_t; 88   using difference_type = std::ptrdiff_t;
90   using pointer = value_type*; 89   using pointer = value_type*;
91   using reference = value_type; 90   using reference = value_type;
92   91  
93   const_iterator() noexcept = default; 92   const_iterator() noexcept = default;
94   93  
HITCBC 95   51180 const_iterator( 94   51125 const_iterator(
96   iterator_type cur, iterator_type anchor_first, 95   iterator_type cur, iterator_type anchor_first,
97   iterator_type anchor_last, std::size_t front_skip, 96   iterator_type anchor_last, std::size_t front_skip,
98   std::size_t back_skip) noexcept 97   std::size_t back_skip) noexcept
HITCBC 99   51180 : cur_(cur) 98   51125 : cur_(cur)
HITCBC 100   51180 , anchor_first_(anchor_first) 99   51125 , anchor_first_(anchor_first)
HITCBC 101   51180 , anchor_last_(anchor_last) 100   51125 , anchor_last_(anchor_last)
HITCBC 102   51180 , front_skip_(front_skip) 101   51125 , front_skip_(front_skip)
HITCBC 103   51180 , back_skip_(back_skip) 102   51125 , back_skip_(back_skip)
104   { 103   {
HITCBC 105   51180 } 104   51125 }
106   105  
HITCBC 107   59254 bool operator==(const_iterator const& o) const noexcept 106   59189 bool operator==(const_iterator const& o) const noexcept
108   { 107   {
HITCBC 109   59254 return cur_ == o.cur_; 108   59189 return cur_ == o.cur_;
110   } 109   }
111   110  
HITCBC 112   59234 bool operator!=(const_iterator const& o) const noexcept 111   59189 bool operator!=(const_iterator const& o) const noexcept
113   { 112   {
HITCBC 114   59234 return !(*this == o); 113   59189 return !(*this == o);
115   } 114   }
116   115  
HITCBC 117   34174 value_type operator*() const noexcept 116   34135 value_type operator*() const noexcept
118   { 117   {
HITCBC 119   34174 buffer_type buf = *cur_; 118   34135 buffer_type buf = *cur_;
HITCBC 120   34174 auto const front_n = (cur_ == anchor_first_) ? front_skip_ : 0; 119   34135 auto const front_n = (cur_ == anchor_first_) ? front_skip_ : 0;
HITCBC 121   34174 auto next = cur_; 120   34135 auto next = cur_;
HITCBC 122   34174 ++next; 121   34135 ++next;
HITCBC 123   34174 auto const back_n = (next == anchor_last_) ? back_skip_ : 0; 122   34135 auto const back_n = (next == anchor_last_) ? back_skip_ : 0;
HITCBC 124   34174 return adjust(buf, front_n, back_n); 123   34135 return adjust(buf, front_n, back_n);
125   } 124   }
126   125  
HITCBC 127   21972 const_iterator& operator++() noexcept { ++cur_; return *this; } 126   21929 const_iterator& operator++() noexcept { ++cur_; return *this; }
HITCBC 128   6452 const_iterator operator++(int) noexcept 127   6446 const_iterator operator++(int) noexcept
HITCBC 129   6452 { auto t = *this; ++*this; return t; } 128   6446 { auto t = *this; ++*this; return t; }
HITCBC 130   12144 const_iterator& operator--() noexcept { --cur_; return *this; } 129   12144 const_iterator& operator--() noexcept { --cur_; return *this; }
HITCBC 131   6072 const_iterator operator--(int) noexcept 130   6072 const_iterator operator--(int) noexcept
HITCBC 132   6072 { auto t = *this; --*this; return t; } 131   6072 { auto t = *this; --*this; return t; }
133   }; 132   };
134   133  
135   /// Construct an empty slice. 134   /// Construct an empty slice.
136   slice_of() noexcept = default; 135   slice_of() noexcept = default;
137   136  
138   /** Construct a view of `[offset, offset + length)` bytes of `bs`. 137   /** Construct a view of `[offset, offset + length)` bytes of `bs`.
139   138  
140   @param bs The underlying sequence (must outlive the view). 139   @param bs The underlying sequence (must outlive the view).
141   @param offset Bytes skipped from the front. Clamped to the total. 140   @param offset Bytes skipped from the front. Clamped to the total.
142   @param length Bytes exposed; the default exposes to the end. 141   @param length Bytes exposed; the default exposes to the end.
143   */ 142   */
HITCBC 144   2294 slice_of( 143   2285 slice_of(
145   BS const& bs, 144   BS const& bs,
146   std::size_t offset, 145   std::size_t offset,
147   std::size_t length = 146   std::size_t length =
148   (std::numeric_limits<std::size_t>::max)()) noexcept 147   (std::numeric_limits<std::size_t>::max)()) noexcept
HITCBC 149   2294 { 148   2285 {
HITCBC 150 - 2294 first_ = capy::begin(bs); 149 + 2285 first_ = capy::buffer_sequence_begin(bs);
HITCBC 151 - 2294 last_ = capy::end(bs); 150 + 2285 last_ = capy::buffer_sequence_end(bs);
152   151  
153   // Position first_/front_skip_ at byte `offset` (single forward pass). 152   // Position first_/front_skip_ at byte `offset` (single forward pass).
HITCBC 154   2294 std::size_t skip = offset; 153   2285 std::size_t skip = offset;
HITCBC 155   2962 while (first_ != last_) 154   2950 while (first_ != last_)
156   { 155   {
HITCBC 157   2857 std::size_t const sz = buffer_type(*first_).size(); 156   2846 std::size_t const sz = buffer_type(*first_).size();
HITCBC 158   2857 if (skip < sz) 157   2846 if (skip < sz)
159   { 158   {
HITCBC 160   2189 front_skip_ = skip; 159   2181 front_skip_ = skip;
HITCBC 161   2189 break; 160   2181 break;
162   } 161   }
HITCBC 163   668 skip -= sz; 162   665 skip -= sz;
HITCBC 164   668 ++first_; 163   665 ++first_;
165   } 164   }
166   165  
HITCBC 167   2294 if (first_ == last_) 166   2285 if (first_ == last_)
HITCBC 168   182 return; // offset at or past the end: empty slice 167   180 return; // offset at or past the end: empty slice
HITCBC 169   2189 if (length == (std::numeric_limits<std::size_t>::max)()) 168   2181 if (length == (std::numeric_limits<std::size_t>::max)())
HITCBC 170 - 1044 return; // to-end: last_ already end(bs), back_skip_ == 0 169 + 1039 return; // to-end: last_ already at the end, back_skip_ == 0
171   170  
172   // Walk `length` live bytes forward to fix last_/back_skip_. 171   // Walk `length` live bytes forward to fix last_/back_skip_.
HITCBC 173   1145 std::size_t left = length; 172   1142 std::size_t left = length;
HITCBC 174   1145 auto cursor = first_; 173   1142 auto cursor = first_;
HITCBC 175   1145 std::size_t cursor_front = front_skip_; 174   1142 std::size_t cursor_front = front_skip_;
HITCBC 176   1643 while (cursor != last_ && left > 0) 175   1637 while (cursor != last_ && left > 0)
177   { 176   {
HITCBC 178   1538 std::size_t const sz = buffer_type(*cursor).size(); 177   1533 std::size_t const sz = buffer_type(*cursor).size();
HITCBC 179   1538 std::size_t const avail = sz - cursor_front; 178   1533 std::size_t const avail = sz - cursor_front;
HITCBC 180   1538 if (left <= avail) 179   1533 if (left <= avail)
181   { 180   {
HITCBC 182   1040 back_skip_ = avail - left; 181   1038 back_skip_ = avail - left;
HITCBC 183   1040 ++cursor; 182   1038 ++cursor;
HITCBC 184   1040 last_ = cursor; 183   1038 last_ = cursor;
HITCBC 185   1040 return; 184   1038 return;
186   } 185   }
HITCBC 187   498 left -= avail; 186   495 left -= avail;
HITCBC 188   498 ++cursor; 187   495 ++cursor;
HITCBC 189   498 cursor_front = 0; 188   495 cursor_front = 0;
190   } 189   }
HITCBC 191   105 last_ = cursor; 190   104 last_ = cursor;
192   } 191   }
193   192  
194   /** Construct directly from a positioned iterator range. 193   /** Construct directly from a positioned iterator range.
195   194  
196   Used by `consuming_buffers::data()` to expose its current position 195   Used by `consuming_buffers::data()` to expose its current position
197   without re-walking from the start. 196   without re-walking from the start.
198   */ 197   */
HITCBC 199   357 slice_of( 198   354 slice_of(
200   iterator_type first, iterator_type last, 199   iterator_type first, iterator_type last,
201   std::size_t front_skip = 0, std::size_t back_skip = 0) noexcept 200   std::size_t front_skip = 0, std::size_t back_skip = 0) noexcept
HITCBC 202   357 : first_(first) 201   354 : first_(first)
HITCBC 203   357 , last_(last) 202   354 , last_(last)
HITCBC 204   357 , front_skip_(front_skip) 203   354 , front_skip_(front_skip)
HITCBC 205   357 , back_skip_(back_skip) 204   354 , back_skip_(back_skip)
206   { 205   {
HITCBC 207   357 } 206   354 }
208   207  
209   /// Return an iterator to the first buffer. 208   /// Return an iterator to the first buffer.
HITCBC 210   25580 const_iterator begin() const noexcept 209   25555 const_iterator begin() const noexcept
211   { 210   {
212   return const_iterator( 211   return const_iterator(
HITCBC 213   25580 first_, first_, last_, front_skip_, back_skip_); 212   25555 first_, first_, last_, front_skip_, back_skip_);
214   } 213   }
215   214  
216   /// Return an iterator past the last buffer. 215   /// Return an iterator past the last buffer.
HITCBC 217   25600 const_iterator end() const noexcept 216   25570 const_iterator end() const noexcept
218   { 217   {
219   return const_iterator( 218   return const_iterator(
HITCBC 220   25600 last_, first_, last_, front_skip_, back_skip_); 219   25570 last_, first_, last_, front_skip_, back_skip_);
221   } 220   }
222   }; 221   };
223   222  
224   } // namespace detail 223   } // namespace detail
225   } // namespace capy 224   } // namespace capy
226   } // namespace boost 225   } // namespace boost
227   226  
228   #endif 227   #endif