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-15 18:27:21 Functions: 100.0 % 81 81

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

Generated by: LCOV version 2.3