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