0.00% Lines (0/0) 0.00% Functions (0/0)
TLA Baseline Branch
Line Hits Code Line Hits Code
1 - //  
2 - // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)  
3 - // Copyright (c) 2026 Michael Vandeberg  
4 - // Copyright (c) 2026 Steve Gerbino  
5 - //  
6 - // Distributed under the Boost Software License, Version 1.0. (See accompanying  
7 - // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)  
8 - //  
9 - // Official repository: https://github.com/cppalliance/capy  
10 - //  
11 -  
12 - /*  
13 - COROUTINE BUFFER SEQUENCE LIFETIME REQUIREMENT  
14 - ===============================================  
15 - Buffer sequence parameters in coroutine APIs MUST be passed BY VALUE,  
16 - never by reference. When a coroutine suspends, reference parameters may  
17 - dangle if the caller's object goes out of scope before resumption.  
18 -  
19 - CORRECT: task<> read_some(MutableBufferSequence auto buffers)  
20 - WRONG: task<> read_some(MutableBufferSequence auto& buffers)  
21 - WRONG: task<> read_some(MutableBufferSequence auto const& buffers)  
22 -  
23 - The buffer_param class works with this model: it takes a const& in its  
24 - constructor (for the non-coroutine scope) but the caller's template  
25 - function accepts the buffer sequence by value, ensuring the sequence  
26 - lives in the coroutine frame.  
27 - */  
28 -  
29 - #ifndef BOOST_CAPY_BUFFERS_BUFFER_PARAM_HPP  
30 - #define BOOST_CAPY_BUFFERS_BUFFER_PARAM_HPP  
31 -  
32 - #include <boost/capy/detail/config.hpp>  
33 - #include <boost/capy/buffers.hpp>  
34 -  
35 - #include <new>  
36 - #include <span>  
37 - #include <type_traits>  
38 -  
39 - namespace boost {  
40 - namespace capy {  
41 -  
42 - /** A buffer sequence wrapper providing windowed access.  
43 -  
44 - This template class wraps any buffer sequence and provides  
45 - incremental access through a sliding window of buffer  
46 - descriptors. It handles both const and mutable buffer  
47 - sequences automatically.  
48 -  
49 - @par Coroutine Lifetime Requirement  
50 -  
51 - When used in coroutine APIs, the outer template function  
52 - MUST accept the buffer sequence parameter BY VALUE:  
53 -  
54 - @par !example example_1  
55 -  
56 -  
57 - Pass-by-value ensures the buffer sequence is copied into  
58 - the coroutine frame and remains valid across suspension  
59 - points. References would dangle when the caller's scope  
60 - exits before the coroutine resumes.  
61 -  
62 - @par Purpose  
63 -  
64 - When iterating through large buffer sequences, it is often  
65 - more efficient to process buffers in batches rather than  
66 - one at a time. This class maintains a window of up to a  
67 - fixed, implementation-defined number of buffer descriptors  
68 - (currently 16). It refills the window from the underlying  
69 - sequence as buffers are consumed.  
70 -  
71 - @par Example  
72 -  
73 - Create a `buffer_param` from any buffer sequence and use  
74 - `data()` to get the current window of buffers. After  
75 - processing some bytes, call `consume()` to advance through  
76 - the sequence.  
77 -  
78 - @par !example example_2  
79 -  
80 -  
81 - @par Virtual Interface Pattern  
82 -  
83 - This class enables passing arbitrary buffer sequences through  
84 - a virtual function boundary. The template function captures  
85 - the buffer sequence by value and drives the iteration, while  
86 - the virtual function receives a simple span. Plain CTAD  
87 - (`buffer_param bp(buffers)`) deduces `BS`'s own buffer type, so a  
88 - mutable sequence yields `span<mutable_buffer>`. That does not match  
89 - `write_impl`'s `span<const_buffer>` parameter. Use @ref const_buffer_param  
90 - to force `const_buffer` storage regardless of what `BS` is:  
91 -  
92 - @par !example example_3  
93 -  
94 -  
95 - @tparam BS The buffer sequence type. Must satisfy  
96 - @ref ConstBufferSequence.  
97 -  
98 - @see @ref ConstBufferSequence, @ref MutableBufferSequence  
99 - */  
100 - template<class BS, bool MakeConst = false>  
101 - requires ConstBufferSequence<BS>  
102 - class buffer_param  
103 - {  
104 - public:  
105 - /// Names `const_buffer` when `MakeConst`, else `BS`'s own buffer type.  
106 - using buffer_type = std::conditional_t<  
107 - MakeConst,  
108 - const_buffer,  
109 - capy::buffer_type<BS>>;  
110 -  
111 - private:  
112 - decltype(begin(std::declval<BS const&>())) it_;  
113 - decltype(end(std::declval<BS const&>())) end_;  
114 - union {  
115 - int dummy_;  
116 - buffer_type arr_[detail::max_iovec_];  
117 - };  
118 - std::size_t size_ = 0;  
119 - std::size_t pos_ = 0;  
120 -  
121 - void  
DCB 122 - 28 refill()  
123 - {  
DCB 124 - 28 pos_ = 0;  
DCB 125 - 28 size_ = 0;  
DCB 126 - 128 for(; it_ != end_ && size_ < detail::max_iovec_; ++it_)  
127 - {  
DCB 128 - 100 buffer_type buf(*it_);  
DCB 129 - 100 if(buf.size() > 0)  
DCB 130 - 96 ::new(&arr_[size_++]) buffer_type(buf);  
131 - }  
DCB 132 - 28 }  
133 -  
134 - public:  
135 - /** Construct from a buffer sequence.  
136 -  
137 - @param bs The buffer sequence to wrap. The caller must  
138 - ensure the buffer sequence remains valid for the  
139 - lifetime of this object.  
140 - */  
141 - explicit  
DCB 142 - 15 buffer_param(BS const& bs)  
DCB 143 - 15 : it_(begin(bs))  
DCB 144 - 15 , end_(end(bs))  
DCB 145 - 15 , dummy_(0)  
146 - {  
DCB 147 - 15 refill();  
DCB 148 - 15 }  
149 -  
150 - /** Return the current window of buffer descriptors.  
151 -  
152 - Returns a span of buffer descriptors representing the  
153 - currently available portion of the buffer sequence.  
154 - The span contains at most a fixed, implementation-defined  
155 - number of buffers (currently 16).  
156 -  
157 - When the current window is exhausted, this function  
158 - automatically refills from the underlying sequence.  
159 -  
160 - @return A span of buffer descriptors. Empty span  
161 - indicates no more data is available.  
162 - */  
163 - std::span<buffer_type>  
DCB 164 - 27 data()  
165 - {  
DCB 166 - 27 if(pos_ >= size_)  
DCB 167 - 13 refill();  
DCB 168 - 27 if(size_ == 0)  
DCB 169 - 9 return {};  
DCB 170 - 18 return {arr_ + pos_, size_ - pos_};  
171 - }  
172 -  
173 - /** Check if more buffers exist beyond the current window.  
174 -  
175 - Returns `true` if the underlying buffer sequence has  
176 - additional buffers that have not yet been loaded into  
177 - the current window. Call after @ref data to determine  
178 - whether the current window is the last one.  
179 -  
180 - @return `true` if more buffers remain in the sequence.  
181 - */  
182 - bool  
DCB 183 - 5 more() const noexcept  
184 - {  
DCB 185 - 5 return it_ != end_;  
186 - }  
187 -  
188 - /** Consume bytes from the buffer sequence.  
189 -  
190 - Advances the current position by `n` bytes, consuming  
191 - data from the front of the sequence. Partially consumed  
192 - buffers are adjusted in place.  
193 -  
194 - @param n Number of bytes to consume.  
195 - */  
196 - void  
DCB 197 - 16 consume(std::size_t n)  
198 - {  
DCB 199 - 98 while(n > 0 && pos_ < size_)  
200 - {  
DCB 201 - 82 auto avail = arr_[pos_].size();  
DCB 202 - 82 if(n < avail)  
203 - {  
DCB 204 - 5 arr_[pos_] += n;  
DCB 205 - 5 n = 0;  
206 - }  
207 - else  
208 - {  
DCB 209 - 77 n -= avail;  
DCB 210 - 77 ++pos_;  
211 - }  
212 - }  
DCB 213 - 16 }  
214 - };  
215 -  
216 - /** Deduce the sequence type from the constructor argument.  
217 -  
218 - @tparam BS The buffer sequence type.  
219 - */  
220 - template<class BS>  
221 - buffer_param(BS const&) -> buffer_param<BS>;  
222 -  
223 - /// Forces `buffer_param` to store windows as `const_buffer`, regardless of `BS`.  
224 - template<class BS>  
225 - using const_buffer_param = buffer_param<BS, true>;  
226 -  
227 - } // namespace capy  
228 - } // namespace boost  
229 -  
230 - #endif