LCOV - code coverage report
Current view: top level - capy/test - bufgrind.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 94.7 % 19 18 1
Test Date: 2026-08-21 22:12:46 Functions: 83.3 % 18 15 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/buffers/buffer_slice.hpp>
      17                 : #include <coroutine>
      18                 : #include <boost/capy/ex/io_env.hpp>
      19                 : 
      20                 : #include <algorithm>
      21                 : #include <cstddef>
      22                 : #include <type_traits>
      23                 : #include <utility>
      24                 : 
      25                 : namespace boost {
      26                 : namespace capy {
      27                 : namespace test {
      28                 : 
      29                 : /** Iterates split points of a buffer sequence into two adjacent halves.
      30                 : 
      31                 :     This class iterates through all possible ways to split a buffer
      32                 :     sequence into two parts (b1, b2) where concatenating them yields
      33                 :     the original sequence. It uses an async-generator-like pattern
      34                 :     that allows `co_await` between iterations.
      35                 : 
      36                 :     The split type automatically preserves mutability: passing a
      37                 :     `MutableBufferSequence` yields halves that model
      38                 :     @ref MutableBufferSequence, while passing a `ConstBufferSequence`
      39                 :     yields halves that model @ref ConstBufferSequence. Each half is
      40                 :     the buffer-sequence view exposed by a @ref buffer_slice over the
      41                 :     corresponding byte range, and can be passed directly to
      42                 :     `read_some`, `write_some`, `buffer_size`, etc.
      43                 : 
      44                 :     @par Thread Safety
      45                 :     Not thread-safe.
      46                 : 
      47                 :     @par Example
      48                 :     @par !example example_1
      49                 : 
      50                 : 
      51                 :     @par Mutable Buffer Example
      52                 :     @par !example example_2
      53                 : 
      54                 : 
      55                 :     @par Step Size Example
      56                 :     @par !example example_3
      57                 : 
      58                 : 
      59                 :     @see buffer_slice
      60                 : */
      61                 : template<ConstBufferSequence BS>
      62                 : class bufgrind
      63                 : {
      64                 :     BS const& bs_;
      65                 :     std::size_t size_;
      66                 :     std::size_t step_;
      67                 :     std::size_t pos_ = 0;
      68                 : 
      69                 : public:
      70                 :     /// Names the buffer-sequence type `buffer_slice` yields for each half.
      71                 :     using slice_type = std::decay_t<
      72                 :         decltype(buffer_slice(std::declval<BS const&>()))>;
      73                 : 
      74                 :     /// Pairs the two `slice_type` halves that @ref next yields together.
      75                 :     using split_type = std::pair<slice_type, slice_type>;
      76                 : 
      77                 :     /** Construct a buffer grinder.
      78                 : 
      79                 :         @param bs The buffer sequence to iterate over.
      80                 : 
      81                 :         @param step The number of bytes to advance on each call to
      82                 :         @ref next. A value of 0 is treated as 1. The final split
      83                 :         at `buffer_size( bs )` is always included regardless of
      84                 :         step alignment.
      85                 :     */
      86                 :     explicit
      87 HIT          39 :     bufgrind(
      88                 :         BS const& bs,
      89                 :         std::size_t step = 1) noexcept
      90              39 :         : bs_(bs)
      91              39 :         , size_(buffer_size(bs))
      92              39 :         , step_(step > 0 ? step : 1)
      93                 :     {
      94              39 :     }
      95                 : 
      96                 :     /** Check if more split points remain.
      97                 : 
      98                 :         @return `true` if @ref next can be called, `false` otherwise.
      99                 :     */
     100             237 :     explicit operator bool() const noexcept
     101                 :     {
     102             237 :         return pos_ <= size_;
     103                 :     }
     104                 : 
     105                 :     /** Computes the current split synchronously, so awaiting it never suspends the caller.
     106                 :     */
     107                 :     struct next_awaitable
     108                 :     {
     109                 :         /// The grinder that produced this awaitable.
     110                 :         bufgrind* self_;
     111                 : 
     112                 :         /** Report whether the awaitable is ready.
     113                 : 
     114                 :             @return `true` always; the split is available without suspending.
     115                 :         */
     116             198 :         bool await_ready() const noexcept { return true; }
     117                 : 
     118                 :         /** Resume the caller inline without suspending.
     119                 : 
     120                 :             @param h The awaiting coroutine handle.
     121                 : 
     122                 :             @return @p h, so the caller resumes immediately.
     123                 :         */
     124 MIS           0 :         std::coroutine_handle<> await_suspend(std::coroutine_handle<> h, io_env const*) const noexcept { return h; }
     125                 : 
     126                 :         /** Return the current split and advance to the next.
     127                 : 
     128                 :             @return The `(b1, b2)` split at the current position.
     129                 :         */
     130                 :         split_type
     131 HIT         198 :         await_resume()
     132                 :         {
     133             198 :             split_type result{
     134             198 :                 buffer_slice(self_->bs_, 0, self_->pos_),
     135             198 :                 buffer_slice(self_->bs_, self_->pos_)
     136                 :             };
     137             198 :             if(self_->pos_ < self_->size_)
     138             161 :                 self_->pos_ = (std::min)(self_->pos_ + self_->step_, self_->size_);
     139                 :             else
     140              37 :                 ++self_->pos_;
     141             198 :             return result;
     142                 :         }
     143                 :     };
     144                 : 
     145                 :     /** Return the next split point.
     146                 : 
     147                 :         Returns an awaitable that yields the current (b1, b2) pair
     148                 :         and advances to the next split point.
     149                 : 
     150                 :         @par Preconditions
     151                 :         `static_cast<bool>( *this )` is `true`.
     152                 : 
     153                 :         @return An awaitable that await-returns `split_type`.
     154                 :     */
     155                 :     next_awaitable
     156             198 :     next() noexcept
     157                 :     {
     158             198 :         return {this};
     159                 :     }
     160                 : };
     161                 : 
     162                 : } // test
     163                 : } // capy
     164                 : } // boost
     165                 : 
     166                 : #endif
        

Generated by: LCOV version 2.3