LCOV - code coverage report
Current view: top level - capy/detail - slice_of.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 100.0 % 72 72
Test Date: 2026-08-14 20:51:18 Functions: 86.7 % 158 137 21

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

Generated by: LCOV version 2.3