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