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-07-22 18:10:09 Functions: 97.5 % 121 118 3

           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`), so it can be passed anywhere a buffer sequence
      32                 :     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: O(buffers up
      40                 :     to `offset`) for a to-end slice, O(buffers up to `offset + length`)
      41                 :     for a bounded slice. It never sums the whole sequence.
      42                 : */
      43                 : template<class BS>
      44                 :     requires MutableBufferSequence<BS> || ConstBufferSequence<BS>
      45                 : class slice_of
      46                 : {
      47                 : public:
      48                 :     /// The buffer type yielded by iteration.
      49                 :     using buffer_type = capy::buffer_type<BS>;
      50                 : 
      51                 :     /// The underlying sequence's iterator type.
      52                 :     using iterator_type =
      53                 :         decltype(capy::begin(std::declval<BS const&>()));
      54                 : 
      55                 : private:
      56                 :     iterator_type first_{};
      57                 :     iterator_type last_{};
      58                 :     std::size_t   front_skip_ = 0;  // bytes trimmed from *first_
      59                 :     std::size_t   back_skip_  = 0;  // bytes trimmed from the final buffer
      60                 : 
      61                 :     static buffer_type
      62 HIT       34112 :     adjust(buffer_type const& b,
      63                 :         std::size_t front_n, std::size_t back_n) noexcept
      64                 :     {
      65                 :         if constexpr (std::is_same_v<buffer_type, mutable_buffer>)
      66           17006 :             return mutable_buffer(
      67           17006 :                 static_cast<char*>(b.data()) + front_n,
      68           34012 :                 b.size() - front_n - back_n);
      69                 :         else
      70           17106 :             return const_buffer(
      71           17106 :                 static_cast<char const*>(b.data()) + front_n,
      72           34212 :                 b.size() - front_n - back_n);
      73                 :     }
      74                 : 
      75                 : public:
      76                 :     /// Bidirectional iterator that adjusts the first and last buffers.
      77                 :     class const_iterator
      78                 :     {
      79                 :         iterator_type cur_{};
      80                 :         iterator_type anchor_first_{};
      81                 :         iterator_type anchor_last_{};
      82                 :         std::size_t   front_skip_ = 0;
      83                 :         std::size_t   back_skip_  = 0;
      84                 : 
      85                 :     public:
      86                 :         using iterator_category = std::bidirectional_iterator_tag;
      87                 :         using value_type        = buffer_type;
      88                 :         using difference_type    = std::ptrdiff_t;
      89                 :         using pointer            = value_type*;
      90                 :         using reference          = value_type;
      91                 : 
      92                 :         const_iterator() noexcept = default;
      93                 : 
      94           51088 :         const_iterator(
      95                 :             iterator_type cur, iterator_type anchor_first,
      96                 :             iterator_type anchor_last, std::size_t front_skip,
      97                 :             std::size_t back_skip) noexcept
      98           51088 :             : cur_(cur)
      99           51088 :             , anchor_first_(anchor_first)
     100           51088 :             , anchor_last_(anchor_last)
     101           51088 :             , front_skip_(front_skip)
     102           51088 :             , back_skip_(back_skip)
     103                 :         {
     104           51088 :         }
     105                 : 
     106           59163 :         bool operator==(const_iterator const& o) const noexcept
     107                 :         {
     108           59163 :             return cur_ == o.cur_;
     109                 :         }
     110                 : 
     111           59163 :         bool operator!=(const_iterator const& o) const noexcept
     112                 :         {
     113           59163 :             return !(*this == o);
     114                 :         }
     115                 : 
     116           34112 :         value_type operator*() const noexcept
     117                 :         {
     118           34112 :             buffer_type buf = *cur_;
     119           34112 :             auto const front_n = (cur_ == anchor_first_) ? front_skip_ : 0;
     120           34112 :             auto next = cur_;
     121           34112 :             ++next;
     122           34112 :             auto const back_n = (next == anchor_last_) ? back_skip_ : 0;
     123           34112 :             return adjust(buf, front_n, back_n);
     124                 :         }
     125                 : 
     126           21911 :         const_iterator& operator++() noexcept { ++cur_; return *this; }
     127            6436 :         const_iterator  operator++(int) noexcept
     128            6436 :             { auto t = *this; ++*this; return t; }
     129           12144 :         const_iterator& operator--() noexcept { --cur_; return *this; }
     130            6072 :         const_iterator  operator--(int) noexcept
     131            6072 :             { auto t = *this; --*this; return t; }
     132                 :     };
     133                 : 
     134                 :     /// Construct an empty slice.
     135                 :     slice_of() noexcept = default;
     136                 : 
     137                 :     /** Construct a view of `[offset, offset + length)` bytes of `bs`.
     138                 : 
     139                 :         @param bs The underlying sequence (must outlive the view).
     140                 :         @param offset Bytes skipped from the front. Clamped to the total.
     141                 :         @param length Bytes exposed; the default exposes to the end.
     142                 :     */
     143            2291 :     slice_of(
     144                 :         BS const& bs,
     145                 :         std::size_t offset,
     146                 :         std::size_t length =
     147                 :             (std::numeric_limits<std::size_t>::max)()) noexcept
     148            2291 :     {
     149            2291 :         first_ = capy::begin(bs);
     150            2291 :         last_  = capy::end(bs);
     151                 : 
     152                 :         // Position first_/front_skip_ at byte `offset` (single forward pass).
     153            2291 :         std::size_t skip = offset;
     154            2958 :         while (first_ != last_)
     155                 :         {
     156            2853 :             std::size_t const sz = buffer_type(*first_).size();
     157            2853 :             if (skip < sz)
     158                 :             {
     159            2186 :                 front_skip_ = skip;
     160            2186 :                 break;
     161                 :             }
     162             667 :             skip -= sz;
     163             667 :             ++first_;
     164                 :         }
     165                 : 
     166            2291 :         if (first_ == last_)
     167             181 :             return;  // offset at or past the end: empty slice
     168            2186 :         if (length == (std::numeric_limits<std::size_t>::max)())
     169            1042 :             return;  // to-end: last_ already end(bs), back_skip_ == 0
     170                 : 
     171                 :         // Walk `length` live bytes forward to fix last_/back_skip_.
     172            1144 :         std::size_t left = length;
     173            1144 :         auto cursor = first_;
     174            1144 :         std::size_t cursor_front = front_skip_;
     175            1641 :         while (cursor != last_ && left > 0)
     176                 :         {
     177            1536 :             std::size_t const sz    = buffer_type(*cursor).size();
     178            1536 :             std::size_t const avail = sz - cursor_front;
     179            1536 :             if (left <= avail)
     180                 :             {
     181            1039 :                 back_skip_ = avail - left;
     182            1039 :                 ++cursor;
     183            1039 :                 last_ = cursor;
     184            1039 :                 return;
     185                 :             }
     186             497 :             left -= avail;
     187             497 :             ++cursor;
     188             497 :             cursor_front = 0;
     189                 :         }
     190             105 :         last_ = cursor;
     191                 :     }
     192                 : 
     193                 :     /** Construct directly from a positioned iterator range.
     194                 : 
     195                 :         Used by `consuming_buffers::data()` to expose its current position
     196                 :         without re-walking from the start.
     197                 :     */
     198             335 :     slice_of(
     199                 :         iterator_type first, iterator_type last,
     200                 :         std::size_t front_skip = 0, std::size_t back_skip = 0) noexcept
     201             335 :         : first_(first)
     202             335 :         , last_(last)
     203             335 :         , front_skip_(front_skip)
     204             335 :         , back_skip_(back_skip)
     205                 :     {
     206             335 :     }
     207                 : 
     208                 :     /// Return an iterator to the first buffer.
     209           25534 :     const_iterator begin() const noexcept
     210                 :     {
     211                 :         return const_iterator(
     212           25534 :             first_, first_, last_, front_skip_, back_skip_);
     213                 :     }
     214                 : 
     215                 :     /// Return an iterator past the last buffer.
     216           25554 :     const_iterator end() const noexcept
     217                 :     {
     218                 :         return const_iterator(
     219           25554 :             last_, first_, last_, front_skip_, back_skip_);
     220                 :     }
     221                 : };
     222                 : 
     223                 : } // namespace detail
     224                 : } // namespace capy
     225                 : } // namespace boost
     226                 : 
     227                 : #endif
        

Generated by: LCOV version 2.3