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