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 - //  
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_BUFFERS_BUFFER_ARRAY_HPP  
11 - #define BOOST_CAPY_BUFFERS_BUFFER_ARRAY_HPP  
12 -  
13 - #include <boost/capy/detail/config.hpp>  
14 - #include <boost/capy/detail/except.hpp>  
15 - #include <boost/capy/buffers.hpp>  
16 -  
17 - #include <cstddef>  
18 - #include <new>  
19 - #include <span>  
20 - #include <utility>  
21 -  
22 - namespace boost {  
23 - namespace capy {  
24 -  
25 - namespace detail {  
26 -  
27 - BOOST_CAPY_DECL  
28 - void  
29 - buffer_array_remove_prefix(  
30 - const_buffer* arr,  
31 - std::size_t* count,  
32 - std::size_t* total_size,  
33 - std::size_t n) noexcept;  
34 -  
35 - BOOST_CAPY_DECL  
36 - void  
37 - buffer_array_remove_prefix(  
38 - mutable_buffer* arr,  
39 - std::size_t* count,  
40 - std::size_t* total_size,  
41 - std::size_t n) noexcept;  
42 -  
43 - BOOST_CAPY_DECL  
44 - void  
45 - buffer_array_keep_prefix(  
46 - const_buffer* arr,  
47 - std::size_t* count,  
48 - std::size_t* total_size,  
49 - std::size_t n) noexcept;  
50 -  
51 - BOOST_CAPY_DECL  
52 - void  
53 - buffer_array_keep_prefix(  
54 - mutable_buffer* arr,  
55 - std::size_t* count,  
56 - std::size_t* total_size,  
57 - std::size_t n) noexcept;  
58 -  
59 - } // namespace detail  
60 -  
61 - /** A buffer sequence holding up to N buffers.  
62 -  
63 - This class template stores a fixed-capacity array of buffer  
64 - descriptors, where the actual count can vary from 0 to N.  
65 - It provides efficient storage for small buffer sequences  
66 - without dynamic allocation.  
67 -  
68 - @par Example  
69 - @code  
70 - void process(ConstBufferSequence auto const& buffers)  
71 - {  
72 - const_buffer_array<4> bufs(buffers);  
73 - // use bufs.begin(), bufs.end(), bufs.to_span()  
74 - }  
75 - @endcode  
76 -  
77 - @tparam N Maximum number of buffers the array can hold.  
78 - @tparam IsConst If true, holds const_buffer; otherwise mutable_buffer.  
79 - */  
80 - template<std::size_t N, bool IsConst>  
81 - class buffer_array  
82 - {  
83 - public:  
84 - /** The type of buffer stored in the array.  
85 - */  
86 - using value_type = std::conditional_t<IsConst, const_buffer, mutable_buffer>;  
87 -  
88 - private:  
89 - std::size_t n_ = 0;  
90 - std::size_t size_ = 0;  
91 - union {  
92 - int dummy_;  
93 - value_type arr_[N];  
94 - };  
95 -  
96 - public:  
97 - /** Construct a default instance.  
98 -  
99 - Constructs an empty buffer array.  
100 - */  
DCB 101 - 6 buffer_array() noexcept  
DCB 102 - 6 : dummy_(0)  
103 - {  
DCB 104 - 6 }  
105 -  
106 - /** Construct a copy.  
107 - */  
DCB 108 - 4644 buffer_array(buffer_array const& other) noexcept  
DCB 109 - 4644 : n_(other.n_)  
DCB 110 - 4644 , size_(other.size_)  
111 - {  
DCB 112 - 12123 for(std::size_t i = 0; i < n_; ++i)  
DCB 113 - 7479 ::new(&arr_[i]) value_type(other.arr_[i]);  
DCB 114 - 4644 }  
115 -  
116 - /** Construct from a single buffer.  
117 -  
118 - @param b The buffer to store.  
119 - */  
DCB 120 - 130 buffer_array(value_type const& b) noexcept  
DCB 121 - 130 : dummy_(0)  
122 - {  
DCB 123 - 130 if(b.size() != 0)  
124 - {  
DCB 125 - 122 ::new(&arr_[0]) value_type(b);  
DCB 126 - 122 n_ = 1;  
DCB 127 - 122 size_ = b.size();  
128 - }  
DCB 129 - 130 }  
130 -  
131 - /** Construct from a buffer sequence.  
132 -  
133 - Copies up to N buffer descriptors from the source  
134 - sequence into the internal array. If the sequence  
135 - contains more than N non-empty buffers, excess  
136 - buffers are silently ignored.  
137 -  
138 - @param bs The buffer sequence to copy from.  
139 - */  
140 - template<class BS>  
141 - requires (IsConst ? ConstBufferSequence<BS> : MutableBufferSequence<BS>)  
142 - && (!std::same_as<std::remove_cvref_t<BS>, buffer_array>)  
143 - && (!std::same_as<std::remove_cvref_t<BS>, value_type>)  
DCB 144 - 185 buffer_array(BS const& bs) noexcept  
DCB 145 - 185 : dummy_(0)  
146 - {  
DCB 147 - 185 auto it = capy::begin(bs);  
DCB 148 - 185 auto const last = capy::end(bs);  
DCB 149 - 618 while(it != last && n_ < N)  
150 - {  
DCB 151 - 433 value_type b(*it);  
DCB 152 - 433 if(b.size() != 0)  
153 - {  
DCB 154 - 427 ::new(&arr_[n_++]) value_type(b);  
DCB 155 - 427 size_ += b.size();  
156 - }  
DCB 157 - 433 ++it;  
158 - }  
DCB 159 - 185 }  
160 -  
161 - /** Construct from a buffer sequence with overflow checking.  
162 -  
163 - Copies buffer descriptors from the source sequence  
164 - into the internal array.  
165 -  
166 - @param bs The buffer sequence to copy from.  
167 -  
168 - @throws std::length_error if the sequence contains  
169 - more than N non-empty buffers.  
170 - */  
171 - template<class BS>  
172 - requires (IsConst ? ConstBufferSequence<BS> : MutableBufferSequence<BS>)  
DCB 173 - 4 buffer_array(std::in_place_t, BS const& bs)  
DCB 174 - 4 : dummy_(0)  
175 - {  
DCB 176 - 4 auto it = capy::begin(bs);  
DCB 177 - 4 auto const last = capy::end(bs);  
DCB 178 - 14 while(it != last)  
179 - {  
DCB 180 - 12 value_type b(*it);  
DCB 181 - 12 if(b.size() != 0)  
182 - {  
DCB 183 - 12 if(n_ >= N)  
DCB 184 - 2 detail::throw_length_error();  
DCB 185 - 10 ::new(&arr_[n_++]) value_type(b);  
DCB 186 - 10 size_ += b.size();  
187 - }  
DCB 188 - 10 ++it;  
189 - }  
DCB 190 - 2 }  
191 -  
192 - /** Construct from an iterator range.  
193 -  
194 - Copies up to N non-empty buffer descriptors from the  
195 - range `[first, last)`. If the range contains more than  
196 - N non-empty buffers, excess buffers are silently ignored.  
197 -  
198 - @param first Iterator to the first buffer descriptor.  
199 - @param last Iterator past the last buffer descriptor.  
200 - */  
201 - template<class Iterator>  
DCB 202 - 8 buffer_array(Iterator first, Iterator last) noexcept  
DCB 203 - 8 : dummy_(0)  
204 - {  
DCB 205 - 26 while(first != last && n_ < N)  
206 - {  
DCB 207 - 18 value_type b(*first);  
DCB 208 - 18 if(b.size() != 0)  
209 - {  
DCB 210 - 14 ::new(&arr_[n_++]) value_type(b);  
DCB 211 - 14 size_ += b.size();  
212 - }  
DCB 213 - 18 ++first;  
214 - }  
DCB 215 - 8 }  
216 -  
217 - /** Construct from an iterator range with overflow checking.  
218 -  
219 - Copies all non-empty buffer descriptors from the range  
220 - `[first, last)` into the internal array.  
221 -  
222 - @param first Iterator to the first buffer descriptor.  
223 - @param last Iterator past the last buffer descriptor.  
224 -  
225 - @throws std::length_error if the range contains more  
226 - than N non-empty buffers.  
227 - */  
228 - template<class Iterator>  
DCB 229 - 4 buffer_array(std::in_place_t, Iterator first, Iterator last)  
DCB 230 - 4 : dummy_(0)  
231 - {  
DCB 232 - 14 while(first != last)  
233 - {  
DCB 234 - 12 value_type b(*first);  
DCB 235 - 12 if(b.size() != 0)  
236 - {  
DCB 237 - 12 if(n_ >= N)  
DCB 238 - 2 detail::throw_length_error();  
DCB 239 - 10 ::new(&arr_[n_++]) value_type(b);  
DCB 240 - 10 size_ += b.size();  
241 - }  
DCB 242 - 10 ++first;  
243 - }  
DCB 244 - 2 }  
245 -  
246 - /** Destructor.  
247 - */  
DCB 248 - 4977 ~buffer_array()  
249 - {  
DCB 250 - 11837 while(n_--)  
DCB 251 - 6860 arr_[n_].~value_type();  
DCB 252 - 4977 }  
253 -  
254 - /** Assign by copying.  
255 - */  
256 - buffer_array&  
DCB 257 - 4 operator=(buffer_array const& other) noexcept  
258 - {  
DCB 259 - 4 if(this != &other)  
260 - {  
DCB 261 - 4 while(n_--)  
DUB 262 - arr_[n_].~value_type();  
DCB 263 - 4 n_ = other.n_;  
DCB 264 - 4 size_ = other.size_;  
DCB 265 - 10 for(std::size_t i = 0; i < n_; ++i)  
DCB 266 - 6 ::new(&arr_[i]) value_type(other.arr_[i]);  
267 - }  
DCB 268 - 4 return *this;  
269 - }  
270 -  
271 - /** Return an iterator to the beginning.  
272 - */  
273 - value_type*  
DCB 274 - 8834 begin() noexcept  
275 - {  
DCB 276 - 8834 return arr_;  
277 - }  
278 -  
279 - /** Return an iterator to the beginning.  
280 - */  
281 - value_type const*  
DCB 282 - 11022 begin() const noexcept  
283 - {  
DCB 284 - 11022 return arr_;  
285 - }  
286 -  
287 - /** Return an iterator to the end.  
288 - */  
289 - value_type*  
DCB 290 - 8833 end() noexcept  
291 - {  
DCB 292 - 8833 return arr_ + n_;  
293 - }  
294 -  
295 - /** Return an iterator to the end.  
296 - */  
297 - value_type const*  
DCB 298 - 11022 end() const noexcept  
299 - {  
DCB 300 - 11022 return arr_ + n_;  
301 - }  
302 -  
303 - /** Return a span of the buffers.  
304 - */  
305 - std::span<value_type>  
DCB 306 - 379 to_span() noexcept  
307 - {  
DCB 308 - 379 return { arr_, n_ };  
309 - }  
310 -  
311 - /** Return a span of the buffers.  
312 - */  
313 - std::span<value_type const>  
DCB 314 - 175 to_span() const noexcept  
315 - {  
DCB 316 - 175 return { arr_, n_ };  
317 - }  
318 -  
319 - /** Conversion to mutable span.  
320 - */  
DCB 321 - 1 operator std::span<value_type>() noexcept  
322 - {  
DCB 323 - 1 return { arr_, n_ };  
324 - }  
325 -  
326 - /** Conversion to const span.  
327 - */  
328 - operator std::span<value_type const>() const noexcept  
329 - {  
330 - return { arr_, n_ };  
331 - }  
332 -  
333 - /** Return the total byte count in O(1).  
334 - */  
335 - friend  
336 - std::size_t  
DCB 337 - 5499 tag_invoke(  
338 - size_tag const&,  
339 - buffer_array const& ba) noexcept  
340 - {  
DCB 341 - 5499 return ba.size_;  
342 - }  
343 -  
344 - /** Slice customization point.  
345 - */  
346 - friend  
347 - void  
DCB 348 - 2080 tag_invoke(  
349 - slice_tag const&,  
350 - buffer_array& ba,  
351 - slice_how how,  
352 - std::size_t n) noexcept  
353 - {  
DCB 354 - 2080 ba.slice_impl(how, n);  
DCB 355 - 2080 }  
356 -  
357 - private:  
358 - void  
DCB 359 - 2080 slice_impl(  
360 - slice_how how,  
361 - std::size_t n) noexcept  
362 - {  
DCB 363 - 2080 switch(how)  
364 - {  
DCB 365 - 1024 case slice_how::remove_prefix:  
DCB 366 - 1024 remove_prefix_impl(n);  
DCB 367 - 1024 break;  
368 -  
DCB 369 - 1056 case slice_how::keep_prefix:  
DCB 370 - 1056 keep_prefix_impl(n);  
DCB 371 - 1056 break;  
372 - }  
DCB 373 - 2080 }  
374 -  
375 - void  
DCB 376 - 1024 remove_prefix_impl(std::size_t n) noexcept  
377 - {  
DCB 378 - 1024 detail::buffer_array_remove_prefix(arr_, &n_, &size_, n);  
DCB 379 - 1024 }  
380 -  
381 - void  
DCB 382 - 1056 keep_prefix_impl(std::size_t n) noexcept  
383 - {  
DCB 384 - 1056 detail::buffer_array_keep_prefix(arr_, &n_, &size_, n);  
DCB 385 - 1056 }  
386 - };  
387 -  
388 - /** Alias for buffer_array holding const_buffer.  
389 -  
390 - @tparam N Maximum number of buffers.  
391 - */  
392 - template<std::size_t N>  
393 - using const_buffer_array = buffer_array<N, true>;  
394 -  
395 - /** Alias for buffer_array holding mutable_buffer.  
396 -  
397 - @tparam N Maximum number of buffers.  
398 - */  
399 - template<std::size_t N>  
400 - using mutable_buffer_array = buffer_array<N, false>;  
401 -  
402 - } // namespace capy  
403 - } // namespace boost  
404 -  
405 - #endif