LCOV - code coverage report
Current view: top level - boost/capy/buffers - slice.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 97.0 % 166 161
Test Date: 2026-01-30 23:43:15 Functions: 100.0 % 102 102

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
       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_BUFFERS_SLICE_HPP
      11              : #define BOOST_CAPY_BUFFERS_SLICE_HPP
      12              : 
      13              : #include <boost/capy/detail/config.hpp>
      14              : #include <boost/capy/buffers.hpp>
      15              : #include <array>
      16              : #include <cassert>
      17              : #include <iterator>
      18              : #include <type_traits>
      19              : 
      20              : namespace boost {
      21              : namespace capy {
      22              : 
      23              : template<class T> class slice_of;
      24              : 
      25              : namespace detail {
      26              : 
      27              : template<class T, class = void>
      28              : struct has_tag_invoke : std::false_type {};
      29              : 
      30              : template<class T>
      31              : struct has_tag_invoke<T, decltype(tag_invoke(
      32              :     std::declval<slice_tag const&>(),
      33              :     std::declval<T&>(),
      34              :     std::declval<slice_how>(),
      35              :     std::declval<std::size_t>()))>
      36              :     : std::true_type {};
      37              : 
      38              : } // detail
      39              : 
      40              : /** Alias for the type representing a slice of T
      41              : */
      42              : template<class T>
      43              : using slice_type = std::conditional_t<
      44              :     detail::has_tag_invoke<T>::value,
      45              :     T, slice_of<T>>;
      46              : 
      47              : //------------------------------------------------
      48              : 
      49              : /** A wrapper enabling a buffer sequence to be consumed
      50              : */
      51              : template<ConstBufferSequence BufferSequence>
      52              : class slice_of<BufferSequence>
      53              : {
      54              :     static_assert(!std::is_const_v<BufferSequence>,
      55              :         "BufferSequence can't be const");
      56              : 
      57              :     static_assert(!std::is_reference_v<BufferSequence>,
      58              :         "BufferSequence can't be a reference");
      59              : 
      60              :     using iter_type = decltype(
      61              :         std::declval<BufferSequence const&>().begin());
      62              : 
      63              :     using difference_type =
      64              :         typename std::iterator_traits<iter_type>::difference_type;
      65              : 
      66              :     BufferSequence bs_;
      67              :     difference_type begin_ = 0; // index of first buffer in sequence
      68              :     difference_type end_ = 0;   // 1 + index of last buffer in sequence
      69              :     std::size_t len_ = 0;       // length of bs_
      70              :     std::size_t size_ = 0;      // total bytes
      71              :     std::size_t prefix_ = 0;    // used prefix bytes
      72              :     std::size_t suffix_ = 0;    // used suffix bytes
      73              : 
      74              : public:
      75              :     /** The type of values returned by iterators
      76              :     */
      77              :     using value_type = std::conditional_t<
      78              :         MutableBufferSequence<BufferSequence>,
      79              :         mutable_buffer, const_buffer>;
      80              : 
      81              :     /** The type of returned iterators
      82              :     */
      83              :     class const_iterator
      84              :     {
      85              :         iter_type it_;
      86              :         // VFALCO we could just point back to
      87              :         // the original sequence to save size
      88              :         std::size_t prefix_ = 0;
      89              :         std::size_t suffix_ = 0;
      90              :         std::size_t i_ = 0;
      91              :         std::size_t n_ = 0;
      92              : 
      93              :         friend class slice_of<BufferSequence>;
      94              : 
      95         6652 :         const_iterator(
      96              :             iter_type it,
      97              :             std::size_t prefix__,
      98              :             std::size_t suffix__,
      99              :             std::size_t i,
     100              :             std::size_t n) noexcept
     101         6652 :             : it_(it)
     102         6652 :             , prefix_(prefix__)
     103         6652 :             , suffix_(suffix__)
     104         6652 :             , i_(i)
     105         6652 :             , n_(n)
     106              :         {
     107              :             // n_ is the index of the end iterator
     108         6652 :         }
     109              : 
     110              :     public:
     111              :         using value_type = typename slice_of::value_type;
     112              :         using reference = value_type;
     113              :         using pointer = void;
     114              :         using difference_type = std::ptrdiff_t;
     115              :         using iterator_category =
     116              :             std::bidirectional_iterator_tag;
     117              :         using iterator_concept = std::bidirectional_iterator_tag;
     118              : 
     119              :         const_iterator() = default;
     120              : 
     121              :         bool
     122         9116 :         operator==(
     123              :             const_iterator const& other) const noexcept
     124              :         {
     125              :             return
     126         9144 :                 it_     == other.it_ &&
     127         3326 :                 prefix_ == other.prefix_ &&
     128         3326 :                 suffix_ == other.suffix_ &&
     129        15768 :                 i_      == other.i_ &&
     130        12442 :                 n_      == other.n_;
     131              :         }
     132              : 
     133              :         bool
     134         9116 :         operator!=(
     135              :             const_iterator const& other) const noexcept
     136              :         {
     137         9116 :             return !(*this == other);
     138              :         }
     139              : 
     140              :         reference
     141         5790 :         operator*() const noexcept
     142              :         {
     143         5790 :             value_type v = *it_;
     144              :             using P = std::conditional_t<
     145              :                 MutableBufferSequence<BufferSequence>,
     146              :                 char*, char const*>;
     147         5790 :             auto p = reinterpret_cast<P>(v.data());
     148         5790 :             auto n = v.size();
     149         5790 :             if(i_ == 0)
     150              :             {
     151         2943 :                 p += prefix_;
     152         2943 :                 n -= prefix_;
     153              :             }
     154         5790 :             if(i_ == n_ - 1)
     155         2943 :                 n -= suffix_;
     156         5790 :             return value_type(p, n);
     157              :         }
     158              : 
     159              :         const_iterator&
     160         4502 :         operator++() noexcept
     161              :         {
     162         4502 :             BOOST_CAPY_ASSERT(i_ < n_);
     163         4502 :             ++it_;
     164         4502 :             ++i_;
     165         4502 :             return *this;
     166              :         }
     167              : 
     168              :         const_iterator
     169          644 :         operator++(int) noexcept
     170              :         {
     171          644 :             auto temp = *this;
     172          644 :             ++(*this);
     173          644 :             return temp;
     174              :         }
     175              : 
     176              :         const_iterator&
     177         1288 :         operator--() noexcept
     178              :         {
     179         1288 :             BOOST_CAPY_ASSERT(i_ > 0);
     180         1288 :             --it_;
     181         1288 :             --i_;
     182         1288 :             return *this;
     183              :         }
     184              : 
     185              :         const_iterator
     186          644 :         operator--(int) noexcept
     187              :         {
     188          644 :             auto temp = *this;
     189          644 :             --(*this);
     190          644 :             return temp;
     191              :         }
     192              :     };
     193              : 
     194              :     /** Constructor
     195              :     */
     196              :     slice_of() = default;
     197              : 
     198              :     /** Constructor
     199              :     */
     200          194 :     slice_of(
     201              :         BufferSequence const& bs)
     202          194 :         : bs_(bs)
     203              :     {
     204          194 :         iter_type it = capy::begin(bs_);
     205          194 :         iter_type eit = capy::end(bs_);
     206          194 :         begin_ = 0;
     207          194 :         end_ = std::distance(it, eit);
     208          776 :         while(it != eit)
     209              :         {
     210          582 :             value_type b(*it);
     211          582 :             size_ += b.size();
     212          582 :             ++len_;
     213          582 :             ++it;
     214              :         }
     215          194 :     }
     216              : 
     217              :     /** Return an iterator to the beginning of the sequence
     218              :     */
     219              :     const_iterator
     220         3326 :     begin() const noexcept
     221              :     {
     222              :         return const_iterator(
     223         3326 :             begin_iter_impl(), prefix_, suffix_, 0, len_);
     224              :     }
     225              : 
     226              :     /** Return an iterator to the end of the sequence
     227              :     */
     228              :     const_iterator
     229         3326 :     end() const noexcept
     230              :     {
     231              :         return const_iterator(
     232         3326 :             end_iter_impl(), prefix_, suffix_, len_, len_);
     233              :     }
     234              : 
     235              :     friend
     236              :     void
     237          671 :     tag_invoke(
     238              :         slice_tag const&,
     239              :         slice_of<BufferSequence>& bs,
     240              :         slice_how how,
     241              :         std::size_t n)
     242              :     {
     243          671 :         bs.slice_impl(how, n);
     244          671 :     }
     245              : 
     246              : private:
     247              :     iter_type
     248         3938 :     begin_iter_impl() const noexcept
     249              :     {
     250         3938 :         iter_type it = capy::begin(bs_);
     251         3938 :         std::advance(it, begin_);
     252         3938 :         return it;
     253              :     }
     254              : 
     255              :     iter_type
     256         3591 :     end_iter_impl() const noexcept
     257              :     {
     258         3591 :         iter_type it = capy::begin(bs_);
     259         3591 :         std::advance(it, end_);
     260         3591 :         return it;
     261              :     }
     262              : 
     263              :     void
     264          347 :     remove_prefix_impl(
     265              :         std::size_t n)
     266              :     {
     267          347 :         if(n > size_)
     268           25 :             n = size_;
     269              : 
     270              :         // nice hack to simplify the loop (M. Nejati)
     271          347 :         n += prefix_;
     272          347 :         size_ += prefix_;
     273          347 :         prefix_ = 0;
     274              : 
     275          347 :         iter_type it = begin_iter_impl();
     276              : 
     277          709 :         while(n > 0 && begin_ != end_)
     278              :         {
     279          612 :             value_type b = *it;
     280          612 :             if(n < b.size())
     281              :             {
     282          250 :                 prefix_ = n;
     283          250 :                 size_ -= n;
     284          250 :                 break;
     285              :             }
     286          362 :             n -= b.size();
     287          362 :             size_ -= b.size();
     288          362 :             ++begin_;
     289          362 :             ++it;
     290          362 :             --len_;
     291              :         }
     292          347 :     }
     293              : 
     294              :     void
     295          265 :     remove_suffix_impl(
     296              :         std::size_t n)
     297              :     {
     298          265 :         if(size_ == 0)
     299              :         {
     300            0 :             BOOST_CAPY_ASSERT(begin_ == end_);
     301          265 :             return;
     302              :         }
     303          265 :         BOOST_CAPY_ASSERT(begin_ != end_);
     304              : 
     305          265 :         if(n > size_)
     306            0 :             n = size_;
     307              : 
     308          265 :         n += suffix_;
     309          265 :         size_ += suffix_;
     310          265 :         suffix_ = 0;
     311              : 
     312          265 :         iter_type bit = begin_iter_impl();
     313          265 :         iter_type it = end_iter_impl();
     314          265 :         it--;
     315              : 
     316          517 :         while(it != bit)
     317              :         {
     318          391 :             value_type b = *it;
     319          391 :             if(n < b.size())
     320              :             {
     321          139 :                 suffix_ = n;
     322          139 :                 size_ -= n;
     323          139 :                 return;
     324              :             }
     325          252 :             n -= b.size();
     326          252 :             size_ -= b.size();
     327          252 :             --it;
     328          252 :             --end_;
     329          252 :             --len_;
     330              :         }
     331          126 :         value_type b = *it;
     332          126 :         auto m = b.size() - prefix_;
     333          126 :         if(n < m)
     334              :         {
     335          126 :             suffix_ = n;
     336          126 :             size_ -= n;
     337          126 :             return;
     338              :         }
     339            0 :         end_ = begin_;
     340            0 :         len_ = 0;
     341            0 :         size_ = 0;
     342              :     }
     343              : 
     344              :     void
     345          324 :     keep_prefix_impl(
     346              :         std::size_t n)
     347              :     {
     348          324 :         if(n >= size_)
     349            9 :             return;
     350          315 :         if(n == 0)
     351              :         {
     352           50 :             end_ = begin_;
     353           50 :             len_ = 0;
     354           50 :             size_ = 0;
     355           50 :             return;
     356              :         }
     357          265 :         remove_suffix_impl(size_ - n);
     358              :     }
     359              : 
     360              :     void
     361              :     keep_suffix_impl(
     362              :         std::size_t n)
     363              :     {
     364              :         if(n >= size_)
     365              :             return;
     366              :         if(n == 0)
     367              :         {
     368              :             begin_ = end_;
     369              :             len_ = 0;
     370              :             size_ = 0;
     371              :             return;
     372              :         }
     373              :         remove_prefix_impl(size_ - n);
     374              :     }
     375              : 
     376              :     void
     377          671 :     slice_impl(
     378              :         slice_how how,
     379              :         std::size_t n)
     380              :     {
     381          671 :         switch(how)
     382              :         {
     383          347 :         case slice_how::remove_prefix:
     384              :         {
     385          347 :             remove_prefix_impl(n);
     386          347 :             break;
     387              :         }
     388          324 :         case slice_how::keep_prefix:
     389              :         {
     390          324 :             keep_prefix_impl(n);
     391          324 :             break;
     392              :         }
     393              :         }
     394          671 :     }
     395              : };
     396              : 
     397              : //------------------------------------------------
     398              : 
     399              : // in-place modify  return value
     400              : // -----------------------------
     401              : // keep_prefix*     prefix
     402              : // keep_suffix      suffix
     403              : // remove_prefix*   sans_prefix
     404              : // remove_suffix    sans_suffix
     405              : 
     406              : /** Remove all but the first `n` bytes from a buffer sequence
     407              : */
     408              : constexpr struct keep_prefix_mrdocs_workaround_t
     409              : {
     410              :     template<ConstBufferSequence BufferSequence>
     411              :         requires detail::has_tag_invoke<BufferSequence>::value
     412         2598 :     void operator()(
     413              :         BufferSequence& bs,
     414              :         std::size_t n) const
     415              :     {
     416         2598 :         tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);
     417         2598 :     }
     418              : } const keep_prefix{};
     419              : 
     420              : /** Remove all but the last `n` bytes from a buffer sequence
     421              : */
     422              : constexpr struct keep_suffix_mrdocs_workaround_t
     423              : {
     424              :     template<ConstBufferSequence BufferSequence>
     425              :         requires detail::has_tag_invoke<BufferSequence>::value
     426          588 :     void operator()(
     427              :         BufferSequence& bs,
     428              :         std::size_t n) const
     429              :     {
     430          588 :         auto n0 = buffer_size(bs);
     431          588 :         if(n < n0)
     432          518 :             tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
     433          588 :     }
     434              : } const keep_suffix{};
     435              : 
     436              : /** Remove `n` bytes from the beginning of a buffer sequence
     437              : */
     438              : constexpr struct remove_prefix_mrdocs_workaround_t
     439              : {
     440              :     template<ConstBufferSequence BufferSequence>
     441              :         requires detail::has_tag_invoke<BufferSequence>::value
     442         2825 :     void operator()(
     443              :         BufferSequence& bs,
     444              :         std::size_t n) const
     445              :     {
     446         2825 :         tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n);
     447         2825 :     }
     448              : } const remove_prefix{};
     449              : 
     450              : /** Remove `n` bytes from the end of a buffer sequence
     451              : */
     452              : constexpr struct remove_suffix_mrdocs_workaround_t
     453              : {
     454              :     template<ConstBufferSequence BufferSequence>
     455              :         requires detail::has_tag_invoke<BufferSequence>::value
     456          842 :     void operator()(
     457              :         BufferSequence& bs,
     458              :         std::size_t n) const
     459              :     {
     460          842 :         auto n0 = buffer_size(bs);
     461          842 :         if(n > 0)
     462              :         {
     463          785 :             if( n > n0)
     464           57 :                 n = n0;
     465          785 :             tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
     466              :         }
     467          842 :     }
     468              : } const remove_suffix{};
     469              : 
     470              : //------------------------------------------------
     471              : 
     472              : /** Return a sequence representing the first `n` bytes of a buffer sequence
     473              : */
     474              : constexpr struct prefix_mrdocs_workaround_t
     475              : {
     476              :     template<ConstBufferSequence BufferSequence>
     477          944 :     slice_type<BufferSequence> operator()(
     478              :         BufferSequence const& bs,
     479              :         std::size_t n) const noexcept
     480              :     {
     481          944 :         slice_type<BufferSequence> result(bs);
     482          944 :         keep_prefix(result, n);
     483          944 :         return result;
     484              :     }
     485              : } prefix{};
     486              : 
     487              : /** Return a sequence representing the last `n` bytes of a buffer sequence
     488              : */
     489              : constexpr struct suffix_mrdocs_workaround_t
     490              : {
     491              :     template<ConstBufferSequence BufferSequence>
     492              :     slice_type<BufferSequence> operator()(
     493              :         BufferSequence const& bs,
     494              :         std::size_t n) const noexcept
     495              :     {
     496              :         slice_type<BufferSequence> result(bs);
     497              :         keep_suffix(result, n);
     498              :         return result;
     499              :     }
     500              : } suffix{};
     501              : 
     502              : /** Return a sequence representing all but the first `n` bytes of a buffer sequence
     503              : */
     504              : constexpr struct sans_prefix_mrdocs_workaround_t
     505              : {
     506              :     template<ConstBufferSequence BufferSequence>
     507          959 :     slice_type<BufferSequence> operator()(
     508              :         BufferSequence const& bs,
     509              :         std::size_t n) const noexcept
     510              :     {
     511          959 :         slice_type<BufferSequence> result(bs);
     512          959 :         remove_prefix(result, n);
     513          959 :         return result;
     514              :     }
     515              : } sans_prefix{};
     516              : 
     517              : /** Return a sequence representing all but the last `n` bytes of a buffer sequence
     518              : */
     519              : constexpr struct sans_suffix_mrdocs_workaround_t
     520              : {
     521              :     template<ConstBufferSequence BufferSequence>
     522              :     slice_type<BufferSequence> operator()(
     523              :         BufferSequence const& bs,
     524              :         std::size_t n) const noexcept
     525              :     {
     526              :         slice_type<BufferSequence> result(bs);
     527              :         remove_suffix(result, n);
     528              :         return result;
     529              :     }
     530              : } sans_suffix{};
     531              : 
     532              : } // capy
     533              : } // boost
     534              : 
     535              : #endif
        

Generated by: LCOV version 2.3