LCOV - code coverage report
Current view: top level - boost/buffers - slice.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 97.0 % 168 163
Test Date: 2025-12-09 13:02:48 Functions: 98.6 % 138 136

            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/buffers
       8              : //
       9              : 
      10              : #ifndef BOOST_BUFFERS_SLICE_HPP
      11              : #define BOOST_BUFFERS_SLICE_HPP
      12              : 
      13              : #include <boost/buffers/detail/config.hpp>
      14              : #include <boost/buffers/buffer.hpp>
      15              : #include <boost/buffers/range.hpp>
      16              : #include <boost/assert.hpp>
      17              : #include <array>
      18              : #include <iterator>
      19              : #include <type_traits>
      20              : 
      21              : namespace boost {
      22              : namespace buffers {
      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 = typename std::conditional<
      45              :     detail::has_tag_invoke<T>::value,
      46              :     T, slice_of<T> >::type;
      47              : 
      48              : //------------------------------------------------
      49              : 
      50              : /** A wrapper enabling a buffer sequence to be consumed
      51              : */
      52              : template<class BufferSequence>
      53              : class slice_of
      54              : {
      55              :     static_assert(! std::is_const<BufferSequence>::value,
      56              :         "BufferSequence can't be const");
      57              : 
      58              :     static_assert(! std::is_reference<BufferSequence>::value,
      59              :         "BufferSequence can't be a reference");
      60              : 
      61              :     static_assert(is_const_buffer_sequence<BufferSequence>::value,
      62              :         "BufferSequence does not meet type requirements");
      63              : 
      64              :     using iter_type = decltype(
      65              :         std::declval<BufferSequence const&>().begin());
      66              : 
      67              :     using difference_type =
      68              :         typename std::iterator_traits<iter_type>::difference_type;
      69              : 
      70              :     BufferSequence bs_;
      71              :     difference_type begin_ = 0; // index of first buffer in sequence
      72              :     difference_type end_ = 0;   // 1 + index of last buffer in sequence
      73              :     std::size_t len_ = 0;       // length of bs_
      74              :     std::size_t size_ = 0;      // total bytes
      75              :     std::size_t prefix_ = 0;    // used prefix bytes
      76              :     std::size_t suffix_ = 0;    // used suffix bytes
      77              : 
      78              : public:
      79              :     /** The type of values returned by iterators
      80              :     */
      81              :     using value_type = typename std::conditional<
      82              :         is_mutable_buffer_sequence<BufferSequence>::value,
      83              :         mutable_buffer, const_buffer>::type;
      84              : 
      85              :     /** The type of returned iterators
      86              :     */
      87              :     class const_iterator;
      88              : 
      89              :     /** Constructor
      90              :     */
      91           44 :     slice_of() = default;
      92              : 
      93              :     /** Constructor
      94              :     */
      95       278925 :     slice_of(
      96              :         BufferSequence const& bs)
      97       278925 :         : bs_(bs)
      98              :     {
      99       278925 :         iter_type it = buffers::begin(bs_);
     100       278925 :         iter_type eit = buffers::end(bs_);
     101       278925 :         begin_ = 0;
     102       279129 :         end_ = std::distance(it, eit);
     103       837011 :         while(it != eit)
     104              :         {
     105       558086 :             value_type b(*it);
     106       558086 :             size_ += b.size();
     107       558086 :             ++len_;
     108       558086 :             ++it;
     109              :         }
     110       278925 :     }
     111              : 
     112              :     /** Return an iterator to the beginning of the sequence
     113              :     */
     114              :     const_iterator
     115              :     begin() const noexcept;
     116              : 
     117              :     /** Return an iterator to the end of the sequence
     118              :     */
     119              :     const_iterator
     120              :     end() const noexcept;
     121              : 
     122              :     friend
     123              :     void
     124       267095 :     tag_invoke(
     125              :         slice_tag const&,
     126              :         slice_of<BufferSequence>& bs,
     127              :         slice_how how,
     128              :         std::size_t n)
     129              :     {
     130       267095 :         bs.slice_impl(how, n);
     131       267095 :     }
     132              : 
     133              : private:
     134              :     iter_type
     135      3455250 :     begin_iter_impl() const noexcept
     136              :     {
     137      3455250 :         iter_type it = buffers::begin(bs_);
     138      3455250 :         std::advance(it, begin_);
     139      3455250 :         return it;
     140              :     }
     141              : 
     142              :     iter_type
     143      3323750 :     end_iter_impl() const noexcept
     144              :     {
     145      3323750 :         iter_type it = buffers::begin(bs_);
     146      3323750 :         std::advance(it, end_);
     147      3323750 :         return it;
     148              :     }
     149              : 
     150              :     void
     151       131498 :     remove_prefix_impl(
     152              :         std::size_t n)
     153              :     {
     154       131498 :         if(n > size_)
     155         4127 :             n = size_;
     156              : 
     157              :         // nice hack to simplify the loop (M. Nejati)
     158       131498 :         n += prefix_;
     159       131498 :         size_ += prefix_;
     160       131498 :         prefix_ = 0;
     161              : 
     162       131498 :         iter_type it = begin_iter_impl();
     163              : 
     164       200594 :         while(n > 0 && begin_ != end_)
     165              :         {
     166       177829 :             value_type b = *it;
     167       177829 :             if(n < b.size())
     168              :             {
     169       108733 :                 prefix_ = n;
     170       108733 :                 size_ -= n;
     171       108733 :                 break;
     172              :             }
     173        69096 :             n -= b.size();
     174        69096 :             size_ -= b.size();
     175        69096 :             ++begin_;
     176        69096 :             ++it;
     177        69096 :             --len_;
     178              :         }
     179       131498 :     }
     180              : 
     181              :     void
     182       115021 :     remove_suffix_impl(
     183              :         std::size_t n)
     184              :     {
     185       115021 :         if(size_ == 0)
     186              :         {
     187            0 :             BOOST_ASSERT(begin_ == end_);
     188       115021 :             return;
     189              :         }
     190       115021 :         BOOST_ASSERT(begin_ != end_);
     191              : 
     192       115021 :         if(n > size_)
     193            0 :             n = size_;
     194              : 
     195       115021 :         n += suffix_;
     196       115021 :         size_ += suffix_;
     197       115021 :         suffix_ = 0;
     198              : 
     199       115021 :         iter_type bit = begin_iter_impl();
     200       115021 :         iter_type it = end_iter_impl();
     201       115021 :         it--;
     202              : 
     203       189204 :         while(it != bit)
     204              :         {
     205       115088 :             value_type b = *it;
     206       115088 :             if(n < b.size())
     207              :             {
     208        40905 :                 suffix_ = n;
     209        40905 :                 size_ -= n;
     210        40905 :                 return;
     211              :             }
     212        74183 :             n -= b.size();
     213        74183 :             size_ -= b.size();
     214        74183 :             --it;
     215        74183 :             --end_;
     216        74183 :             --len_;
     217              :         }
     218        74116 :         value_type b = *it;
     219        74116 :         auto m = b.size() - prefix_;
     220        74116 :         if(n < m)
     221              :         {
     222        74116 :             suffix_ = n;
     223        74116 :             size_ -= n;
     224        74116 :             return;
     225              :         }
     226            0 :         end_ = begin_;
     227            0 :         len_ = 0;
     228            0 :         size_ = 0;
     229          144 :     }
     230              : 
     231              :     void
     232       135597 :     keep_prefix_impl(
     233              :         std::size_t n)
     234              :     {
     235       135597 :         if(n >= size_)
     236         8230 :             return;
     237       127367 :         if(n == 0)
     238              :         {
     239        12346 :             end_ = begin_;
     240        12346 :             len_ = 0;
     241        12346 :             size_ = 0;
     242        12346 :             return;
     243              :         }
     244       115021 :         remove_suffix_impl(size_ - n);
     245              :     }
     246              : 
     247              :     void
     248              :     keep_suffix_impl(
     249              :         std::size_t n)
     250              :     {
     251              :         if(n >= size_)
     252              :             return;
     253              :         if(n == 0)
     254              :         {
     255              :             begin_ = end_;
     256              :             len_ = 0;
     257              :             size_ = 0;
     258              :             return;
     259              :         }
     260              :         remove_prefix_impl(size_ - n);
     261              :     }
     262              : 
     263              :     void
     264       267095 :     slice_impl(
     265              :         slice_how how,
     266              :         std::size_t n)
     267              :     {
     268       267095 :         switch(how)
     269              :         {
     270       131498 :         case slice_how::remove_prefix:
     271              :         {
     272       131498 :             remove_prefix_impl(n);
     273       131498 :             break;
     274              :         }
     275       135597 :         case slice_how::keep_prefix:
     276              :         {
     277       135597 :             keep_prefix_impl(n);
     278       135597 :             break;
     279              :         }
     280              :         }
     281       267095 :     }
     282              : };
     283              : 
     284              : //------------------------------------------------
     285              : 
     286              : template<class BufferSequence>
     287              : class slice_of<BufferSequence>::
     288              :     const_iterator
     289              : {
     290              :     using iter_type = typename
     291              :         slice_of::iter_type;
     292              : 
     293              :     iter_type it_;
     294              :     // VFALCO we could just point back to
     295              :     // the original sequence to save size
     296              :     std::size_t prefix_ = 0;
     297              :     std::size_t suffix_ = 0;
     298              :     std::size_t i_ = 0;
     299              :     std::size_t n_ = 0;
     300              : 
     301              :     friend class slice_of<BufferSequence>;
     302              : 
     303      6417460 :     const_iterator(
     304              :         iter_type it,
     305              :         std::size_t prefix__,
     306              :         std::size_t suffix__,
     307              :         std::size_t i,
     308              :         std::size_t n) noexcept
     309      6417460 :         : it_(it)
     310      6417460 :         , prefix_(prefix__)
     311      6417460 :         , suffix_(suffix__)
     312      6417460 :         , i_(i)
     313      6417460 :         , n_(n)
     314              :     {
     315              :         // n_ is the index of the end iterator
     316      6417460 :     }
     317              : 
     318              : public:
     319              :     using value_type = typename slice_of::value_type;
     320              :     using reference = value_type;
     321              :     using pointer = void;
     322              :     using difference_type = std::ptrdiff_t;
     323              :     using iterator_category =
     324              :         std::bidirectional_iterator_tag;
     325              : #if defined(__cpp_concepts) || defined(__cpp_lib_concepts)
     326              :     using iterator_concept = std::bidirectional_iterator_tag; // (since C++20)
     327              : #endif
     328              : 
     329              :     const_iterator() = default;
     330              : 
     331              :     bool
     332      7783230 :     operator==(
     333              :         const_iterator const& other) const noexcept
     334              :     {
     335              :         return
     336     10987331 :             it_     == other.it_ &&
     337      3208729 :             prefix_ == other.prefix_ &&
     338      3208729 :             suffix_ == other.suffix_ &&
     339     14200688 :             i_      == other.i_ &&
     340     10991959 :             n_      == other.n_;
     341              :     }
     342              : 
     343              :     bool
     344      7783230 :     operator!=(
     345              :         const_iterator const& other) const noexcept
     346              :     {
     347      7783230 :         return !(*this == other);
     348              :     }
     349              : 
     350              :     reference
     351      4574501 :     operator*() const noexcept
     352              :     {
     353      4574501 :         value_type v = *it_;
     354              :         using P = typename std::conditional<
     355              :             is_mutable_buffer_sequence<BufferSequence>::value,
     356              :             char*, char const*>::type;
     357      4574501 :         auto p = reinterpret_cast<P>(v.data());
     358      4574501 :         auto n = v.size();
     359      4574501 :         if(i_ == 0)
     360              :         {
     361      2969221 :             p += prefix_;
     362      2969221 :             n -= prefix_;
     363              :         }
     364      4574501 :         if(i_ == n_ - 1)
     365      2969221 :             n -= suffix_;
     366      4574501 :         return value_type(p, n);
     367              :     }
     368              : 
     369              :     const_iterator&
     370      3013270 :     operator++() noexcept
     371              :     {
     372      3013270 :         BOOST_ASSERT(i_ < n_);
     373      3013270 :         ++it_;
     374      3013270 :         ++i_;
     375      3013270 :         return *this;
     376              :     }
     377              : 
     378              :     const_iterator
     379       780616 :     operator++(int) noexcept
     380              :     {
     381       780616 :         auto temp = *this;
     382       780616 :         ++(*this);
     383       780616 :         return temp;
     384              :     }
     385              : 
     386              :     const_iterator&
     387      1561232 :     operator--() noexcept
     388              :     {
     389      1561232 :         BOOST_ASSERT(i_ > 0);
     390      1561232 :         --it_;
     391      1561232 :         --i_;
     392      1561232 :         return *this;
     393              :     }
     394              : 
     395              :     const_iterator
     396       780616 :     operator--(int) noexcept
     397              :     {
     398       780616 :         auto temp = *this;
     399       780616 :         --(*this);
     400       780616 :         return temp;
     401              :     }
     402              : };
     403              : 
     404              : //------------------------------------------------
     405              : 
     406              : template<class BufferSequence>
     407              : auto
     408      3208731 : slice_of<BufferSequence>::
     409              : begin() const noexcept ->
     410              :     const_iterator
     411              : {
     412              :     return const_iterator(
     413      3208731 :         begin_iter_impl(), prefix_, suffix_, 0, len_);
     414              : }
     415              : 
     416              : template<class BufferSequence>
     417              : auto
     418      3208729 : slice_of<BufferSequence>::
     419              : end() const noexcept ->
     420              :     const_iterator
     421              : {
     422              :     return const_iterator(
     423      3208729 :         end_iter_impl(), prefix_, suffix_, len_, len_);
     424              : }
     425              : 
     426              : //------------------------------------------------
     427              : 
     428              : // in-place modify  return value
     429              : // -----------------------------
     430              : // keep_prefix*     prefix
     431              : // keep_suffix      suffix
     432              : // remove_prefix*   sans_prefix
     433              : // remove_suffix    sans_suffix
     434              : 
     435              : /** Remove all but the first `n` bytes from a buffer sequence
     436              : */
     437              : constexpr struct keep_prefix_mrdocs_workaround_t
     438              : {
     439              :     template<class BufferSequence>
     440       276191 :     auto operator()(
     441              :         BufferSequence& bs,
     442              :         std::size_t n) const -> typename std::enable_if<
     443              :             is_const_buffer_sequence<BufferSequence>::value &&
     444              :             detail::has_tag_invoke<BufferSequence>::value>::type
     445              : 
     446              :     {
     447       276191 :         tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);
     448       276191 :     }
     449              : } const keep_prefix{};
     450              : 
     451              : /** Remove all but the last `n` bytes from a buffer sequence
     452              : */
     453              : constexpr struct keep_suffix_mrdocs_workaround_t
     454              : {
     455              :     template<class BufferSequence>
     456       139903 :     auto operator()(
     457              :         BufferSequence& bs,
     458              :         std::size_t n) const -> typename std::enable_if<
     459              :             is_const_buffer_sequence<BufferSequence>::value &&
     460              :             detail::has_tag_invoke<BufferSequence>::value>::type
     461              :     {
     462       139903 :         auto n0 = size(bs);
     463       139903 :         if(n < n0)
     464       123437 :             tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
     465       139903 :     }
     466              : } const keep_suffix{};
     467              : 
     468              : /** Remove `n` bytes from the beginning of a buffer sequence
     469              : */
     470              : constexpr struct remove_prefix_mrdocs_workaround_t
     471              : {
     472              :     template<class BufferSequence>
     473       272370 :     auto operator()(
     474              :         BufferSequence& bs,
     475              :         std::size_t n) const -> typename std::enable_if<
     476              :             is_const_buffer_sequence<BufferSequence>::value &&
     477              :             detail::has_tag_invoke<BufferSequence>::value>::type
     478              :     {
     479       272370 :         tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n);
     480       272370 :     }
     481              : } const remove_prefix{};
     482              : 
     483              : /** Remove `n` bytes from the end of a buffer sequence
     484              : */
     485              : constexpr struct remove_suffix_mrdocs_workaround_t
     486              : {
     487              :     template<class BufferSequence>
     488       140157 :     auto operator()(
     489              :         BufferSequence& bs,
     490              :         std::size_t n) const -> typename std::enable_if<
     491              :             is_const_buffer_sequence<BufferSequence>::value &&
     492              :             detail::has_tag_invoke<BufferSequence>::value>::type
     493              :     {
     494       140157 :         auto n0 = size(bs);
     495       140157 :         if(n > 0)
     496              :         {
     497       131902 :             if( n > n0)
     498         8255 :                 n = n0;
     499       131902 :             tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
     500              :         }
     501       140157 :     }
     502              : } const remove_suffix{};
     503              : 
     504              : //------------------------------------------------
     505              : 
     506              : /** Return a sequence representing the first `n` bytes of a buffer sequence
     507              : */
     508              : constexpr struct prefix_mrdocs_workaround_t
     509              : {
     510              :     template<class BufferSequence>
     511           54 :     auto operator()(
     512              :         BufferSequence const& bs,
     513              :         std::size_t n) const noexcept -> typename std::enable_if<
     514              :             is_const_buffer_sequence<BufferSequence>::value,
     515              :             slice_type<BufferSequence>>::type
     516              :     {
     517           54 :         slice_type<BufferSequence> result(bs);
     518           54 :         keep_prefix(result, n);
     519           54 :         return result;
     520              :     }
     521              : } prefix{};
     522              : 
     523              : /** Return a sequence representing the last `n` bytes of a buffer sequence
     524              : */
     525              : constexpr struct suffix_mrdocs_workaround_t
     526              : {
     527              :     template<class BufferSequence>
     528              :     auto operator()(
     529              :         BufferSequence const& bs,
     530              :         std::size_t n) const noexcept -> typename std::enable_if<
     531              :             is_const_buffer_sequence<BufferSequence>::value,
     532              :             slice_type<BufferSequence>>::type
     533              :     {
     534              :         slice_type<BufferSequence> result(bs);
     535              :         keep_suffix(result, n);
     536              :         return result;
     537              :     }
     538              : } suffix{};
     539              : 
     540              : /** Return a sequence representing all but the first `n` bytes of a buffer sequence
     541              : */
     542              : constexpr struct sans_prefix_mrdocs_workaround_t
     543              : {
     544              :     template<class BufferSequence>
     545          117 :     auto operator()(
     546              :         BufferSequence const& bs,
     547              :         std::size_t n) const noexcept -> typename std::enable_if<
     548              :             is_const_buffer_sequence<BufferSequence>::value,
     549              :             slice_type<BufferSequence>>::type
     550              :     {
     551          117 :         slice_type<BufferSequence> result(bs);
     552          117 :         remove_prefix(result, n);
     553          117 :         return result;
     554              :     }
     555              : } sans_prefix{};
     556              : 
     557              : /** Return a sequence representing all but the last `n` bytes of a buffer sequence
     558              : */
     559              : constexpr struct sans_suffix_mrdocs_workaround_t
     560              : {
     561              :     template<class BufferSequence>
     562              :     auto operator()(
     563              :         BufferSequence const& bs,
     564              :         std::size_t n) const noexcept -> typename std::enable_if<
     565              :             is_const_buffer_sequence<BufferSequence>::value,
     566              :             slice_type<BufferSequence>>::type
     567              :     {
     568              :         slice_type<BufferSequence> result(bs);
     569              :         remove_suffix(result, n);
     570              :         return result;
     571              :     }
     572              : } sans_suffix{};
     573              : 
     574              : } // buffers
     575              : } // boost
     576              : 
     577              : #endif
        

Generated by: LCOV version 2.1