LCOV - code coverage report
Current view: top level - boost/capy/test - bufgrind.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 94.4 % 18 17
Test Date: 2026-01-30 23:43:15 Functions: 83.3 % 18 15

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

Generated by: LCOV version 2.3