LCOV - code coverage report
Current view: top level - capy/test - bufgrind.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 96.2 % 26 25 1
Test Date: 2026-10-30 18:56:53 Functions: 85.7 % 21 18 3

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
       3                 : // Copyright (c) 2026 Michael Vandeberg
       4                 : //
       5                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       6                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       7                 : //
       8                 : // Official repository: https://github.com/cppalliance/capy
       9                 : //
      10                 : 
      11                 : #ifndef BOOST_CAPY_TEST_BUFGRIND_HPP
      12                 : #define BOOST_CAPY_TEST_BUFGRIND_HPP
      13                 : 
      14                 : #include <boost/capy/detail/config.hpp>
      15                 : #include <boost/capy/buffers.hpp>
      16                 : #include <boost/capy/detail/slice_of.hpp>
      17                 : #include <coroutine>
      18                 : #include <boost/capy/ex/await_context.hpp>
      19                 : 
      20                 : #include <algorithm>
      21                 : #include <cstddef>
      22                 : #include <limits>
      23                 : #include <type_traits>
      24                 : #include <utility>
      25                 : 
      26                 : namespace boost {
      27                 : namespace capy {
      28                 : namespace test {
      29                 : 
      30                 : /** Iterates split points of a buffer sequence into two adjacent halves.
      31                 : 
      32                 :     This class iterates through all possible ways to split a buffer
      33                 :     sequence into two parts (b1, b2) where concatenating them yields
      34                 :     the original sequence. It uses an async-generator-like pattern
      35                 :     that allows `co_await` between iterations.
      36                 : 
      37                 :     The split type automatically preserves mutability: passing a
      38                 :     `MutableBufferSequence` yields halves that model
      39                 :     @ref MutableBufferSequence, while passing a `ConstBufferSequence`
      40                 :     yields halves that model @ref ConstBufferSequence. A single buffer
      41                 :     splits into two `mutable_buffer` or `const_buffer` values; any other
      42                 :     sequence splits into two borrowed views. Either way each half can be
      43                 :     passed directly to `read_some`, `write_some`, `buffer_size`, etc.
      44                 : 
      45                 :     @par Thread Safety
      46                 :     Not thread-safe.
      47                 : 
      48                 :     @par Example
      49                 :     @par !example example_1
      50                 : 
      51                 : 
      52                 :     @par Mutable Buffer Example
      53                 :     @par !example example_2
      54                 : 
      55                 : 
      56                 :     @par Step Size Example
      57                 :     @par !example example_3
      58                 : 
      59                 : */
      60                 : template<ConstBufferSequence BS>
      61                 : class bufgrind
      62                 : {
      63                 :     BS const& bs_;
      64                 :     std::size_t size_;
      65                 :     std::size_t step_;
      66                 :     std::size_t pos_ = 0;
      67                 : 
      68                 : public:
      69                 :     /// Names the buffer-sequence type of each half.
      70                 :     using slice_type = std::conditional_t<
      71                 :         ConstBuffer<BS>,
      72                 :         buffer_type<BS>,
      73                 :         detail::slice_of<BS>>;
      74                 : 
      75                 :     /// Pairs the two `slice_type` halves that @ref next yields together.
      76                 :     using split_type = std::pair<slice_type, slice_type>;
      77                 : 
      78                 : private:
      79                 :     static slice_type
      80 HIT         396 :     slice(
      81                 :         BS const& bs,
      82                 :         std::size_t offset,
      83                 :         std::size_t length =
      84                 :             (std::numeric_limits<std::size_t>::max)()) noexcept
      85                 :     {
      86                 :         if constexpr (ConstBuffer<BS>)
      87                 :         {
      88             382 :             slice_type b = bs;
      89             382 :             b += offset;
      90             382 :             if(length < b.size())
      91             155 :                 b = slice_type(b.data(), length);
      92             382 :             return b;
      93                 :         }
      94                 :         else
      95                 :         {
      96              14 :             return slice_type(bs, offset, length);
      97                 :         }
      98                 :     }
      99                 : 
     100                 : public:
     101                 : 
     102                 :     /** Construct a buffer grinder.
     103                 : 
     104                 :         @param bs The buffer sequence to iterate over.
     105                 : 
     106                 :         @param step The number of bytes to advance on each call to
     107                 :         @ref next. A value of 0 is treated as 1. The final split
     108                 :         at `buffer_size( bs )` is always included regardless of
     109                 :         step alignment.
     110                 :     */
     111                 :     explicit
     112              39 :     bufgrind(
     113                 :         BS const& bs,
     114                 :         std::size_t step = 1) noexcept
     115              39 :         : bs_(bs)
     116              39 :         , size_(buffer_size(bs))
     117              39 :         , step_(step > 0 ? step : 1)
     118                 :     {
     119              39 :     }
     120                 : 
     121                 :     /** Check if more split points remain.
     122                 : 
     123                 :         @return `true` if @ref next can be called, `false` otherwise.
     124                 :     */
     125             237 :     explicit operator bool() const noexcept
     126                 :     {
     127             237 :         return pos_ <= size_;
     128                 :     }
     129                 : 
     130                 :     /** Computes the current split synchronously, so awaiting it never suspends the caller.
     131                 :     */
     132                 :     struct next_awaitable
     133                 :     {
     134                 :         /// The grinder that produced this awaitable.
     135                 :         bufgrind* self_;
     136                 : 
     137                 :         /** Report whether the awaitable is ready.
     138                 : 
     139                 :             @return `true` always; the split is available without suspending.
     140                 :         */
     141             198 :         bool await_ready() const noexcept { return true; }
     142                 : 
     143                 :         /** Resume the caller inline without suspending.
     144                 : 
     145                 :             @param h The awaiting coroutine handle.
     146                 : 
     147                 :             @return @p h, so the caller resumes immediately.
     148                 :         */
     149 MIS           0 :         std::coroutine_handle<> await_suspend(std::coroutine_handle<> h, await_context const*) const noexcept { return h; }
     150                 : 
     151                 :         /** Return the current split and advance to the next.
     152                 : 
     153                 :             @return The `(b1, b2)` split at the current position.
     154                 :         */
     155                 :         split_type
     156 HIT         198 :         await_resume()
     157                 :         {
     158             198 :             split_type result{
     159             198 :                 slice(self_->bs_, 0, self_->pos_),
     160             198 :                 slice(self_->bs_, self_->pos_)
     161                 :             };
     162             198 :             if(self_->pos_ < self_->size_)
     163             161 :                 self_->pos_ = (std::min)(self_->pos_ + self_->step_, self_->size_);
     164                 :             else
     165              37 :                 ++self_->pos_;
     166             198 :             return result;
     167                 :         }
     168                 :     };
     169                 : 
     170                 :     /** Return the next split point.
     171                 : 
     172                 :         Returns an awaitable that yields the current (b1, b2) pair
     173                 :         and advances to the next split point.
     174                 : 
     175                 :         @par Preconditions
     176                 :         `static_cast<bool>( *this )` is `true`.
     177                 : 
     178                 :         @return An awaitable that await-returns `split_type`.
     179                 :     */
     180                 :     next_awaitable
     181             198 :     next() noexcept
     182                 :     {
     183             198 :         return {this};
     184                 :     }
     185                 : };
     186                 : 
     187                 : } // test
     188                 : } // capy
     189                 : } // boost
     190                 : 
     191                 : #endif
        

Generated by: LCOV version 2.3