LCOV - code coverage report
Current view: top level - boost/buffers - slice.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 98.0 % 149 146
Test Date: 2025-12-06 02:12:43 Functions: 100.0 % 83 83

            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              :     BufferSequence bs_;
      68              :     iter_type begin_;
      69              :     iter_type end_;
      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 = typename std::conditional<
      79              :         is_mutable_buffer_sequence<BufferSequence>::value,
      80              :         mutable_buffer, const_buffer>::type;
      81              : 
      82              :     /** The type of returned iterators
      83              :     */
      84              :     class const_iterator;
      85              : 
      86              :     /** Constructor
      87              :     */
      88              :     slice_of() = default;
      89              : 
      90              :     /** Constructor
      91              :     */
      92       278721 :     slice_of(
      93              :         BufferSequence const& bs)
      94       278721 :         : bs_(bs)
      95       278721 :         , begin_(buffers::begin(bs_))
      96       278721 :         , end_(buffers::end(bs_))
      97              :     {
      98       278721 :         auto it = begin_;
      99       836627 :         while(it != end_)
     100              :         {
     101       557906 :             value_type b(*it);
     102       557906 :             size_ += b.size();
     103       557906 :             ++len_;
     104       557906 :             ++it;
     105              :         }
     106       278721 :     }
     107              : 
     108              :     /** Return an iterator to the beginning of the sequence
     109              :     */
     110              :     const_iterator
     111              :     begin() const noexcept;
     112              : 
     113              :     /** Return an iterator to the end of the sequence
     114              :     */
     115              :     const_iterator
     116              :     end() const noexcept;
     117              : 
     118              :     friend
     119              :     void
     120       266423 :     tag_invoke(
     121              :         slice_tag const&,
     122              :         slice_of<BufferSequence>& bs,
     123              :         slice_how how,
     124              :         std::size_t n)
     125              :     {
     126       266423 :         bs.slice_impl(how, n);
     127       266423 :     }
     128              : 
     129              : private:
     130              :     void
     131       131154 :     remove_prefix_impl(
     132              :         std::size_t n)
     133              :     {
     134              :         // nice hack to simplify the loop (M. Nejati)
     135       131154 :         n += prefix_;
     136       131154 :         size_ += prefix_;
     137       131154 :         prefix_ = 0;
     138              : 
     139       200953 :         while(n > 0 && begin_ != end_)
     140              :         {
     141       178273 :             value_type b = *begin_;
     142       178273 :             if(n < b.size())
     143              :             {
     144       108474 :                 prefix_ = n;
     145       108474 :                 size_ -= n;
     146       108474 :                 break;
     147              :             }
     148        69799 :             n -= b.size();
     149        69799 :             size_ -= b.size();
     150        69799 :             ++begin_;
     151        69799 :             --len_;
     152              :         }
     153       131154 :     }
     154              : 
     155              :     void
     156       114759 :     remove_suffix_impl(
     157              :         std::size_t n)
     158              :     {
     159       114759 :         if(size_ == 0)
     160              :         {
     161            0 :             BOOST_ASSERT(begin_ == end_);
     162       114759 :             return;
     163              :         }
     164       114759 :         BOOST_ASSERT(begin_ != end_);
     165       114759 :         n += suffix_;
     166       114759 :         size_ += suffix_;
     167       114759 :         suffix_ = 0;
     168       114759 :         iter_type it = end_;
     169       114759 :         --it;
     170       188774 :         while(it != begin_)
     171              :         {
     172       114829 :             value_type b = *it;
     173       114829 :             if(n < b.size())
     174              :             {
     175        40814 :                 suffix_ = n;
     176        40814 :                 size_ -= n;
     177        40814 :                 return;
     178              :             }
     179        74015 :             n -= b.size();
     180        74015 :             size_ -= b.size();
     181        74015 :             --it;
     182        74015 :             --end_;
     183        74015 :             --len_;
     184              :         }
     185        73945 :         value_type b = *it;
     186        73945 :         auto m = b.size() - prefix_;
     187        73945 :         if(n < m)
     188              :         {
     189        73945 :             suffix_ = n;
     190        73945 :             size_ -= n;
     191        73945 :             return;
     192              :         }
     193            0 :         end_ = begin_;
     194            0 :         len_ = 0;
     195              :     }
     196              : 
     197              :     void
     198       135269 :     keep_prefix_impl(
     199              :         std::size_t n)
     200              :     {
     201       135269 :         if(n >= size_)
     202         8213 :             return;
     203       127056 :         if(n == 0)
     204              :         {
     205        12297 :             end_ = begin_;
     206        12297 :             len_ = 0;
     207        12297 :             size_ = 0;
     208        12297 :             return;
     209              :         }
     210       114759 :         remove_suffix_impl(size_ - n);
     211              :     }
     212              : 
     213              :     void
     214              :     keep_suffix_impl(
     215              :         std::size_t n)
     216              :     {
     217              :         if(n >= size_)
     218              :             return;
     219              :         if(n == 0)
     220              :         {
     221              :             begin_ = end_;
     222              :             len_ = 0;
     223              :             size_ = 0;
     224              :             return;
     225              :         }
     226              :         remove_prefix_impl(size_ - n);
     227              :     }
     228              : 
     229              :     void
     230       266423 :     slice_impl(
     231              :         slice_how how,
     232              :         std::size_t n)
     233              :     {
     234       266423 :         switch(how)
     235              :         {
     236       131154 :         case slice_how::remove_prefix:
     237              :         {
     238       131154 :             remove_prefix_impl(n);
     239       131154 :             break;
     240              :         }
     241       135269 :         case slice_how::keep_prefix:
     242              :         {
     243       135269 :             keep_prefix_impl(n);
     244       135269 :             break;
     245              :         }
     246              :         }
     247       266423 :     }
     248              : };
     249              : 
     250              : //------------------------------------------------
     251              : 
     252              : template<class BufferSequence>
     253              : class slice_of<BufferSequence>::
     254              :     const_iterator
     255              : {
     256              :     using iter_type = typename
     257              :         slice_of::iter_type;
     258              : 
     259              :     iter_type it_;
     260              :     // VFALCO we could just point back to
     261              :     // the original sequence to save size
     262              :     std::size_t prefix_ = 0;
     263              :     std::size_t suffix_ = 0;
     264              :     std::size_t i_ = 0;
     265              :     std::size_t n_ = 0;
     266              : 
     267              :     friend class slice_of<BufferSequence>;
     268              : 
     269      6410228 :     const_iterator(
     270              :         iter_type it,
     271              :         std::size_t prefix__,
     272              :         std::size_t suffix__,
     273              :         std::size_t i,
     274              :         std::size_t n) noexcept
     275      6410228 :         : it_(it)
     276      6410228 :         , prefix_(prefix__)
     277      6410228 :         , suffix_(suffix__)
     278      6410228 :         , i_(i)
     279      6410228 :         , n_(n)
     280              :     {
     281              :         // n_ is the index of the end iterator
     282      6410228 :     }
     283              : 
     284              : public:
     285              :     using value_type = typename slice_of::value_type;
     286              :     using reference = value_type;
     287              :     using pointer = void;
     288              :     using difference_type = std::ptrdiff_t;
     289              :     using iterator_category =
     290              :         std::bidirectional_iterator_tag;
     291              : #if defined(__cpp_concepts) || defined(__cpp_lib_concepts)
     292              :     using iterator_concept = std::bidirectional_iterator_tag; // (since C++20)
     293              : #endif
     294              : 
     295              :     const_iterator() = default;
     296              : 
     297              :     bool
     298      7765254 :     operator==(
     299              :         const_iterator const& other) const noexcept
     300              :     {
     301              :         return
     302     10970367 :             it_     == other.it_ &&
     303      3205113 :             prefix_ == other.prefix_ &&
     304      3205113 :             suffix_ == other.suffix_ &&
     305     14175480 :             i_      == other.i_ &&
     306     10970367 :             n_      == other.n_;
     307              :     }
     308              : 
     309              :     bool
     310      7765254 :     operator!=(
     311              :         const_iterator const& other) const noexcept
     312              :     {
     313      7765254 :         return !(*this == other);
     314              :     }
     315              : 
     316              :     reference
     317      4560141 :     operator*() const noexcept
     318              :     {
     319      4560141 :         value_type v = *it_;
     320              :         using P = typename std::conditional<
     321              :             is_mutable_buffer_sequence<BufferSequence>::value,
     322              :             char*, char const*>::type;
     323      4560141 :         auto p = reinterpret_cast<P>(v.data());
     324      4560141 :         auto n = v.size();
     325      4560141 :         if(i_ == 0)
     326              :         {
     327      2955699 :             p += prefix_;
     328      2955699 :             n -= prefix_;
     329              :         }
     330      4560141 :         if(i_ == n_ - 1)
     331      2955699 :             n -= suffix_;
     332      4560141 :         return value_type(p, n);
     333              :     }
     334              : 
     335              :     const_iterator&
     336      3003398 :     operator++() noexcept
     337              :     {
     338      3003398 :         BOOST_ASSERT(i_ < n_);
     339      3003398 :         ++it_;
     340      3003398 :         ++i_;
     341      3003398 :         return *this;
     342              :     }
     343              : 
     344              :     const_iterator
     345       778372 :     operator++(int) noexcept
     346              :     {
     347       778372 :         auto temp = *this;
     348       778372 :         ++(*this);
     349       778372 :         return temp;
     350              :     }
     351              : 
     352              :     const_iterator&
     353      1556744 :     operator--() noexcept
     354              :     {
     355      1556744 :         BOOST_ASSERT(i_ > 0);
     356      1556744 :         --it_;
     357      1556744 :         --i_;
     358      1556744 :         return *this;
     359              :     }
     360              : 
     361              :     const_iterator
     362       778372 :     operator--(int) noexcept
     363              :     {
     364       778372 :         auto temp = *this;
     365       778372 :         --(*this);
     366       778372 :         return temp;
     367              :     }
     368              : };
     369              : 
     370              : //------------------------------------------------
     371              : 
     372              : template<class BufferSequence>
     373              : auto
     374      3205115 : slice_of<BufferSequence>::
     375              : begin() const noexcept ->
     376              :     const_iterator
     377              : {
     378              :     return const_iterator(
     379      3205115 :         this->begin_, prefix_, suffix_, 0, len_);
     380              : }
     381              : 
     382              : template<class BufferSequence>
     383              : auto
     384      3205113 : slice_of<BufferSequence>::
     385              : end() const noexcept ->
     386              :     const_iterator
     387              : {
     388              :     return const_iterator(
     389      3205113 :         this->end_, prefix_, suffix_, len_, len_);
     390              : }
     391              : 
     392              : //------------------------------------------------
     393              : 
     394              : // in-place modify  return value
     395              : // -----------------------------
     396              : // keep_prefix*     prefix
     397              : // keep_suffix      suffix
     398              : // remove_prefix*   sans_prefix
     399              : // remove_suffix    sans_suffix
     400              : 
     401              : /** Remove all but the first `n` bytes from a buffer sequence
     402              : */
     403              : constexpr struct keep_prefix_mrdocs_workaround_t
     404              : {
     405              :     template<class BufferSequence>
     406       276140 :     auto operator()(
     407              :         BufferSequence& bs,
     408              :         std::size_t n) const -> typename std::enable_if<
     409              :             is_const_buffer_sequence<BufferSequence>::value &&
     410              :             detail::has_tag_invoke<BufferSequence>::value>::type
     411              : 
     412              :     {
     413       276140 :         tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);
     414       276140 :     }
     415              : } const keep_prefix{};
     416              : 
     417              : /** Remove all but the last `n` bytes from a buffer sequence
     418              : */
     419              : constexpr struct keep_suffix_mrdocs_workaround_t
     420              : {
     421              :     template<class BufferSequence>
     422       139852 :     auto operator()(
     423              :         BufferSequence& bs,
     424              :         std::size_t n) const -> typename std::enable_if<
     425              :             is_const_buffer_sequence<BufferSequence>::value &&
     426              :             detail::has_tag_invoke<BufferSequence>::value>::type
     427              :     {
     428       139852 :         auto n0 = size(bs);
     429       139852 :         if(n < n0)
     430       123398 :             tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
     431       139852 :     }
     432              : } const keep_suffix{};
     433              : 
     434              : /** Remove `n` bytes from the beginning of a buffer sequence
     435              : */
     436              : constexpr struct remove_prefix_mrdocs_workaround_t
     437              : {
     438              :     template<class BufferSequence>
     439       272017 :     auto operator()(
     440              :         BufferSequence& bs,
     441              :         std::size_t n) const -> typename std::enable_if<
     442              :             is_const_buffer_sequence<BufferSequence>::value &&
     443              :             detail::has_tag_invoke<BufferSequence>::value>::type
     444              :     {
     445       272017 :         tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n);
     446       272017 :     }
     447              : } const remove_prefix{};
     448              : 
     449              : /** Remove `n` bytes from the end of a buffer sequence
     450              : */
     451              : constexpr struct remove_suffix_mrdocs_workaround_t
     452              : {
     453              :     template<class BufferSequence>
     454       139852 :     auto operator()(
     455              :         BufferSequence& bs,
     456              :         std::size_t n) const -> typename std::enable_if<
     457              :             is_const_buffer_sequence<BufferSequence>::value &&
     458              :             detail::has_tag_invoke<BufferSequence>::value>::type
     459              :     {
     460       139852 :         auto n0 = size(bs);
     461       139852 :         if(n > 0)
     462              :         {
     463       131625 :             if( n > n0)
     464         8227 :                 n = n0;
     465       131625 :             tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
     466              :         }
     467       139852 :     }
     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<class BufferSequence>
     477           54 :     auto operator()(
     478              :         BufferSequence const& bs,
     479              :         std::size_t n) const noexcept -> typename std::enable_if<
     480              :             is_const_buffer_sequence<BufferSequence>::value,
     481              :             slice_type<BufferSequence>>::type
     482              :     {
     483           54 :         slice_type<BufferSequence> result(bs);
     484           54 :         keep_prefix(result, n);
     485           54 :         return result;
     486              :     }
     487              : } prefix{};
     488              : 
     489              : /** Return a sequence representing the last `n` bytes of a buffer sequence
     490              : */
     491              : constexpr struct suffix_mrdocs_workaround_t
     492              : {
     493              :     template<class BufferSequence>
     494              :     auto operator()(
     495              :         BufferSequence const& bs,
     496              :         std::size_t n) const noexcept -> typename std::enable_if<
     497              :             is_const_buffer_sequence<BufferSequence>::value,
     498              :             slice_type<BufferSequence>>::type
     499              :     {
     500              :         slice_type<BufferSequence> result(bs);
     501              :         keep_suffix(result, n);
     502              :         return result;
     503              :     }
     504              : } suffix{};
     505              : 
     506              : /** Return a sequence representing all but the first `n` bytes of a buffer sequence
     507              : */
     508              : constexpr struct sans_prefix_mrdocs_workaround_t
     509              : {
     510              :     template<class BufferSequence>
     511           69 :     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           69 :         slice_type<BufferSequence> result(bs);
     518           69 :         remove_prefix(result, n);
     519           69 :         return result;
     520              :     }
     521              : } sans_prefix{};
     522              : 
     523              : /** Return a sequence representing all but the last `n` bytes of a buffer sequence
     524              : */
     525              : constexpr struct sans_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              :         remove_suffix(result, n);
     536              :         return result;
     537              :     }
     538              : } sans_suffix{};
     539              : 
     540              : } // buffers
     541              : } // boost
     542              : 
     543              : #endif
        

Generated by: LCOV version 2.1