LCOV - code coverage report
Current view: top level - capy/test - bufgrind.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 94.4 % 18 17 1
Test Date: 2026-02-17 18:14:47 Functions: 83.3 % 18 15 3

           TLA  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_TEST_BUFGRIND_HPP
      11                 : #define BOOST_CAPY_TEST_BUFGRIND_HPP
      12                 : 
      13                 : #include <boost/capy/detail/config.hpp>
      14                 : #include <boost/capy/buffers.hpp>
      15                 : #include <boost/capy/buffers/slice.hpp>
      16                 : #include <coroutine>
      17                 : #include <boost/capy/ex/io_env.hpp>
      18                 : 
      19                 : #include <algorithm>
      20                 : #include <cstddef>
      21                 : #include <utility>
      22                 : 
      23                 : namespace boost {
      24                 : namespace capy {
      25                 : namespace test {
      26                 : 
      27                 : /** A test utility for iterating buffer sequence split points.
      28                 : 
      29                 :     This class iterates through all possible ways to split a buffer
      30                 :     sequence into two parts (b1, b2) where concatenating them yields
      31                 :     the original sequence. It uses an async-generator-like pattern
      32                 :     that allows `co_await` between iterations.
      33                 : 
      34                 :     The split type automatically preserves mutability: passing a
      35                 :     `MutableBufferSequence` yields mutable slices, while passing a
      36                 :     `ConstBufferSequence` yields const slices. This is handled
      37                 :     automatically through `slice_type<BS>`.
      38                 : 
      39                 :     @par Thread Safety
      40                 :     Not thread-safe.
      41                 : 
      42                 :     @par Example
      43                 :     @code
      44                 :     // Test all split points of a buffer
      45                 :     std::string data = "hello world";
      46                 :     auto cb = make_buffer( data );
      47                 : 
      48                 :     fuse f;
      49                 :     auto r = f.inert( [&]( fuse& ) -> task<> {
      50                 :         bufgrind bg( cb );
      51                 :         while( bg ) {
      52                 :             auto [b1, b2] = co_await bg.next();
      53                 :             // b1 contains first N bytes
      54                 :             // b2 contains remaining bytes
      55                 :             // concatenating b1 + b2 equals original
      56                 :             co_await some_async_operation( b1, b2 );
      57                 :         }
      58                 :     } );
      59                 :     @endcode
      60                 : 
      61                 :     @par Mutable Buffer Example
      62                 :     @code
      63                 :     // Mutable buffers preserve mutability
      64                 :     char data[100];
      65                 :     mutable_buffer mb( data, sizeof( data ) );
      66                 : 
      67                 :     bufgrind bg( mb );
      68                 :     while( bg ) {
      69                 :         auto [b1, b2] = co_await bg.next();
      70                 :         // b1, b2 yield mutable_buffer when iterated
      71                 :     }
      72                 :     @endcode
      73                 : 
      74                 :     @par Step Size Example
      75                 :     @code
      76                 :     // Skip by 10 bytes for faster iteration
      77                 :     bufgrind bg( cb, 10 );
      78                 :     while( bg ) {
      79                 :         auto [b1, b2] = co_await bg.next();
      80                 :         // Visits positions 0, 10, 20, ..., and always size
      81                 :     }
      82                 :     @endcode
      83                 : 
      84                 :     @see prefix, sans_prefix, slice_type
      85                 : */
      86                 : template<ConstBufferSequence BS>
      87                 : class bufgrind
      88                 : {
      89                 :     BS const& bs_;
      90                 :     std::size_t size_;
      91                 :     std::size_t step_;
      92                 :     std::size_t pos_ = 0;
      93                 : 
      94                 : public:
      95                 :     /// The type returned by @ref next.
      96                 :     using split_type = std::pair<slice_type<BS>, slice_type<BS>>;
      97                 : 
      98                 :     /** Construct a buffer grinder.
      99                 : 
     100                 :         @param bs The buffer sequence to iterate over.
     101                 : 
     102                 :         @param step The number of bytes to advance on each call to
     103                 :         @ref next. A value of 0 is treated as 1. The final split
     104                 :         at `buffer_size( bs )` is always included regardless of
     105                 :         step alignment.
     106                 :     */
     107                 :     explicit
     108 HIT         178 :     bufgrind(
     109                 :         BS const& bs,
     110                 :         std::size_t step = 1) noexcept
     111             178 :         : bs_(bs)
     112             178 :         , size_(buffer_size(bs))
     113             178 :         , step_(step > 0 ? step : 1)
     114                 :     {
     115             178 :     }
     116                 : 
     117                 :     /** Check if more split points remain.
     118                 : 
     119                 :         @return `true` if @ref next can be called, `false` otherwise.
     120                 :     */
     121             986 :     explicit operator bool() const noexcept
     122                 :     {
     123             986 :         return pos_ <= size_;
     124                 :     }
     125                 : 
     126                 :     /** Awaitable returned by @ref next.
     127                 :     */
     128                 :     struct next_awaitable
     129                 :     {
     130                 :         bufgrind* self_;
     131                 : 
     132             944 :         bool await_ready() const noexcept { return true; }
     133 MIS           0 :         std::coroutine_handle<> await_suspend(std::coroutine_handle<> h, io_env const*) const noexcept { return h; }
     134                 : 
     135                 :         split_type
     136 HIT         944 :         await_resume()
     137                 :         {
     138             944 :             auto b1 = prefix(self_->bs_, self_->pos_);
     139             944 :             auto b2 = sans_prefix(self_->bs_, self_->pos_);
     140             944 :             if(self_->pos_ < self_->size_)
     141             888 :                 self_->pos_ = (std::min)(self_->pos_ + self_->step_, self_->size_);
     142                 :             else
     143              56 :                 ++self_->pos_;
     144             944 :             return {std::move(b1), std::move(b2)};
     145                 :         }
     146                 :     };
     147                 : 
     148                 :     /** Return the next split point.
     149                 : 
     150                 :         Returns an awaitable that yields the current (b1, b2) pair
     151                 :         and advances to the next split point.
     152                 : 
     153                 :         @par Preconditions
     154                 :         `static_cast<bool>( *this )` is `true`.
     155                 : 
     156                 :         @return An awaitable yielding `split_type`.
     157                 :     */
     158                 :     next_awaitable
     159             944 :     next() noexcept
     160                 :     {
     161             944 :         return {this};
     162                 :     }
     163                 : };
     164                 : 
     165                 : } // test
     166                 : } // capy
     167                 : } // boost
     168                 : 
     169                 : #endif
        

Generated by: LCOV version 2.3