LCOV - code coverage report
Current view: top level - boost/buffers - slice.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 98.0 % 150 147
Test Date: 2025-12-08 14:54:08 Functions: 100.0 % 123 123

            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       278925 :     slice_of(
      93              :         BufferSequence const& bs)
      94       278925 :         : bs_(bs)
      95       278925 :         , begin_(buffers::begin(bs_))
      96       278925 :         , end_(buffers::end(bs_))
      97              :     {
      98       278925 :         auto it = begin_;
      99       837011 :         while(it != end_)
     100              :         {
     101       558086 :             value_type b(*it);
     102       558086 :             size_ += b.size();
     103       558086 :             ++len_;
     104       558086 :             ++it;
     105              :         }
     106       278925 :     }
     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       266609 :     tag_invoke(
     121              :         slice_tag const&,
     122              :         slice_of<BufferSequence>& bs,
     123              :         slice_how how,
     124              :         std::size_t n)
     125              :     {
     126       266609 :         bs.slice_impl(how, n);
     127       266609 :     }
     128              : 
     129              : private:
     130              :     void
     131       131244 :     remove_prefix_impl(
     132              :         std::size_t n)
     133              :     {
     134              :         // nice hack to simplify the loop (M. Nejati)
     135       131244 :         n += prefix_;
     136       131244 :         size_ += prefix_;
     137       131244 :         prefix_ = 0;
     138              : 
     139       201052 :         while(n > 0 && begin_ != end_)
     140              :         {
     141       178354 :             value_type b = *begin_;
     142       178354 :             if(n < b.size())
     143              :             {
     144       108546 :                 prefix_ = n;
     145       108546 :                 size_ -= n;
     146       108546 :                 break;
     147              :             }
     148        69808 :             n -= b.size();
     149        69808 :             size_ -= b.size();
     150        69808 :             ++begin_;
     151        69808 :             --len_;
     152              :         }
     153       131244 :     }
     154              : 
     155              :     void
     156       114831 :     remove_suffix_impl(
     157              :         std::size_t n)
     158              :     {
     159       114831 :         if(size_ == 0)
     160              :         {
     161            0 :             BOOST_ASSERT(begin_ == end_);
     162       114831 :             return;
     163              :         }
     164       114831 :         BOOST_ASSERT(begin_ != end_);
     165       114831 :         n += suffix_;
     166       114831 :         size_ += suffix_;
     167       114831 :         suffix_ = 0;
     168       114831 :         iter_type it = end_;
     169       114831 :         --it;
     170       188846 :         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        74017 :         value_type b = *it;
     186        74017 :         auto m = b.size() - prefix_;
     187        74017 :         if(n < m)
     188              :         {
     189        74017 :             suffix_ = n;
     190        74017 :             size_ -= n;
     191        74017 :             return;
     192              :         }
     193            0 :         end_ = begin_;
     194            0 :         len_ = 0;
     195           72 :     }
     196              : 
     197              :     void
     198       135365 :     keep_prefix_impl(
     199              :         std::size_t n)
     200              :     {
     201       135365 :         if(n >= size_)
     202         8228 :             return;
     203       127137 :         if(n == 0)
     204              :         {
     205        12306 :             end_ = begin_;
     206        12306 :             len_ = 0;
     207        12306 :             size_ = 0;
     208        12306 :             return;
     209              :         }
     210       114831 :         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       266609 :     slice_impl(
     231              :         slice_how how,
     232              :         std::size_t n)
     233              :     {
     234       266609 :         switch(how)
     235              :         {
     236       131244 :         case slice_how::remove_prefix:
     237              :         {
     238       131244 :             remove_prefix_impl(n);
     239       131244 :             break;
     240              :         }
     241       135365 :         case slice_how::keep_prefix:
     242              :         {
     243       135365 :             keep_prefix_impl(n);
     244       135365 :             break;
     245              :         }
     246              :         }
     247       266609 :     }
     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      6414920 :     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      6414920 :         : it_(it)
     276      6414920 :         , prefix_(prefix__)
     277      6414920 :         , suffix_(suffix__)
     278      6414920 :         , i_(i)
     279      6414920 :         , n_(n)
     280              :     {
     281              :         // n_ is the index of the end iterator
     282      6414920 :     }
     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      7769472 :     operator==(
     299              :         const_iterator const& other) const noexcept
     300              :     {
     301              :         return
     302     10974585 :             it_     == other.it_ &&
     303      3207459 :             prefix_ == other.prefix_ &&
     304      3207459 :             suffix_ == other.suffix_ &&
     305     14184390 :             i_      == other.i_ &&
     306     10976931 :             n_      == other.n_;
     307              :     }
     308              : 
     309              :     bool
     310      7769472 :     operator!=(
     311              :         const_iterator const& other) const noexcept
     312              :     {
     313      7769472 :         return !(*this == other);
     314              :     }
     315              : 
     316              :     reference
     317      4562013 :     operator*() const noexcept
     318              :     {
     319      4562013 :         value_type v = *it_;
     320              :         using P = typename std::conditional<
     321              :             is_mutable_buffer_sequence<BufferSequence>::value,
     322              :             char*, char const*>::type;
     323      4562013 :         auto p = reinterpret_cast<P>(v.data());
     324      4562013 :         auto n = v.size();
     325      4562013 :         if(i_ == 0)
     326              :         {
     327      2957571 :             p += prefix_;
     328      2957571 :             n -= prefix_;
     329              :         }
     330      4562013 :         if(i_ == n_ - 1)
     331      2957571 :             n -= suffix_;
     332      4562013 :         return value_type(p, n);
     333              :     }
     334              : 
     335              :     const_iterator&
     336      3004622 :     operator++() noexcept
     337              :     {
     338      3004622 :         BOOST_ASSERT(i_ < n_);
     339      3004622 :         ++it_;
     340      3004622 :         ++i_;
     341      3004622 :         return *this;
     342              :     }
     343              : 
     344              :     const_iterator
     345       778696 :     operator++(int) noexcept
     346              :     {
     347       778696 :         auto temp = *this;
     348       778696 :         ++(*this);
     349       778696 :         return temp;
     350              :     }
     351              : 
     352              :     const_iterator&
     353      1557392 :     operator--() noexcept
     354              :     {
     355      1557392 :         BOOST_ASSERT(i_ > 0);
     356      1557392 :         --it_;
     357      1557392 :         --i_;
     358      1557392 :         return *this;
     359              :     }
     360              : 
     361              :     const_iterator
     362       778696 :     operator--(int) noexcept
     363              :     {
     364       778696 :         auto temp = *this;
     365       778696 :         --(*this);
     366       778696 :         return temp;
     367              :     }
     368              : };
     369              : 
     370              : //------------------------------------------------
     371              : 
     372              : template<class BufferSequence>
     373              : auto
     374      3207461 : slice_of<BufferSequence>::
     375              : begin() const noexcept ->
     376              :     const_iterator
     377              : {
     378              :     return const_iterator(
     379      3207461 :         this->begin_, prefix_, suffix_, 0, len_);
     380              : }
     381              : 
     382              : template<class BufferSequence>
     383              : auto
     384      3207459 : slice_of<BufferSequence>::
     385              : end() const noexcept ->
     386              :     const_iterator
     387              : {
     388              :     return const_iterator(
     389      3207459 :         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       276191 :     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       276191 :         tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n);
     414       276191 :     }
     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       139903 :     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       139903 :         auto n0 = size(bs);
     429       139903 :         if(n < n0)
     430       123437 :             tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n0 - n);
     431       139903 :     }
     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       272194 :     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       272194 :         tag_invoke(slice_tag{}, bs, slice_how::remove_prefix, n);
     446       272194 :     }
     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       139903 :     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       139903 :         auto n0 = size(bs);
     461       139903 :         if(n > 0)
     462              :         {
     463       131670 :             if( n > n0)
     464         8233 :                 n = n0;
     465       131670 :             tag_invoke(slice_tag{}, bs, slice_how::keep_prefix, n0 - n);
     466              :         }
     467       139903 :     }
     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          195 :     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          195 :         slice_type<BufferSequence> result(bs);
     518          195 :         remove_prefix(result, n);
     519          195 :         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