98.85% Lines (86/87) 100.00% Functions (16/16)
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_DETAIL_BUFFER_ARRAY_HPP 10   #ifndef BOOST_CAPY_DETAIL_BUFFER_ARRAY_HPP
11   #define BOOST_CAPY_DETAIL_BUFFER_ARRAY_HPP 11   #define BOOST_CAPY_DETAIL_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   namespace detail { 24   namespace detail {
25   25  
26   /** A buffer sequence holding up to N buffers. 26   /** A buffer sequence holding up to N buffers.
27   27  
28   This class template stores a fixed-capacity array of buffer 28   This class template stores a fixed-capacity array of buffer
29   descriptors, where the actual count can vary from 0 to N. 29   descriptors, where the actual count can vary from 0 to N.
30   It provides efficient storage for small buffer sequences 30   It provides efficient storage for small buffer sequences
31   without dynamic allocation. 31   without dynamic allocation.
32   32  
33   @par Example 33   @par Example
34   @code 34   @code
35   void process(ConstBufferSequence auto const& buffers) 35   void process(ConstBufferSequence auto const& buffers)
36   { 36   {
37   detail::const_buffer_array<4> bufs(buffers); 37   detail::const_buffer_array<4> bufs(buffers);
38   // use bufs.begin(), bufs.end(), bufs.to_span() 38   // use bufs.begin(), bufs.end(), bufs.to_span()
39   } 39   }
40   @endcode 40   @endcode
41   41  
42   @tparam N Maximum number of buffers the array can hold. 42   @tparam N Maximum number of buffers the array can hold.
43   @tparam IsConst If true, holds const_buffer; otherwise mutable_buffer. 43   @tparam IsConst If true, holds const_buffer; otherwise mutable_buffer.
44   */ 44   */
45   template<std::size_t N, bool IsConst> 45   template<std::size_t N, bool IsConst>
46   class buffer_array 46   class buffer_array
47   { 47   {
48   public: 48   public:
49   /** The type of buffer stored in the array. 49   /** The type of buffer stored in the array.
50   */ 50   */
51   using value_type = std::conditional_t<IsConst, const_buffer, mutable_buffer>; 51   using value_type = std::conditional_t<IsConst, const_buffer, mutable_buffer>;
52   52  
53   private: 53   private:
54   std::size_t n_ = 0; 54   std::size_t n_ = 0;
55   std::size_t size_ = 0; 55   std::size_t size_ = 0;
56   union { 56   union {
57   int dummy_; 57   int dummy_;
58   value_type arr_[N]; 58   value_type arr_[N];
59   }; 59   };
60   60  
61   public: 61   public:
62   /** Construct a default instance. 62   /** Construct a default instance.
63   63  
64   Constructs an empty buffer array. 64   Constructs an empty buffer array.
65   */ 65   */
HITCBC 66   6 buffer_array() noexcept 66   6 buffer_array() noexcept
HITCBC 67   6 : dummy_(0) 67   6 : dummy_(0)
68   { 68   {
HITCBC 69   6 } 69   6 }
70   70  
71   /** Construct a copy. 71   /** Construct a copy.
72   */ 72   */
HITCBC 73   292 buffer_array(buffer_array const& other) noexcept 73   292 buffer_array(buffer_array const& other) noexcept
HITCBC 74   292 : n_(other.n_) 74   292 : n_(other.n_)
HITCBC 75   292 , size_(other.size_) 75   292 , size_(other.size_)
76   { 76   {
HITCBC 77   811 for(std::size_t i = 0; i < n_; ++i) 77   811 for(std::size_t i = 0; i < n_; ++i)
HITCBC 78   519 ::new(&arr_[i]) value_type(other.arr_[i]); 78   519 ::new(&arr_[i]) value_type(other.arr_[i]);
HITCBC 79   292 } 79   292 }
80   80  
81   /** Construct from a single buffer. 81   /** Construct from a single buffer.
82   82  
83   @param b The buffer to store. 83   @param b The buffer to store.
84   */ 84   */
HITCBC 85   130 buffer_array(value_type const& b) noexcept 85   130 buffer_array(value_type const& b) noexcept
HITCBC 86   130 : dummy_(0) 86   130 : dummy_(0)
87   { 87   {
HITCBC 88   130 if(b.size() != 0) 88   130 if(b.size() != 0)
89   { 89   {
HITCBC 90   122 ::new(&arr_[0]) value_type(b); 90   122 ::new(&arr_[0]) value_type(b);
HITCBC 91   122 n_ = 1; 91   122 n_ = 1;
HITCBC 92   122 size_ = b.size(); 92   122 size_ = b.size();
93   } 93   }
HITCBC 94   130 } 94   130 }
95   95  
96   /** Construct from a buffer sequence. 96   /** Construct from a buffer sequence.
97   97  
98   Copies up to N buffer descriptors from the source 98   Copies up to N buffer descriptors from the source
99   sequence into the internal array. If the sequence 99   sequence into the internal array. If the sequence
100   contains more than N non-empty buffers, excess 100   contains more than N non-empty buffers, excess
101   buffers are silently ignored. 101   buffers are silently ignored.
102   102  
103   @param bs The buffer sequence to copy from. 103   @param bs The buffer sequence to copy from.
104   */ 104   */
105   template<class BS> 105   template<class BS>
106   requires (IsConst ? ConstBufferSequence<BS> : MutableBufferSequence<BS>) 106   requires (IsConst ? ConstBufferSequence<BS> : MutableBufferSequence<BS>)
107   && (!std::same_as<std::remove_cvref_t<BS>, buffer_array>) 107   && (!std::same_as<std::remove_cvref_t<BS>, buffer_array>)
108   && (!std::same_as<std::remove_cvref_t<BS>, value_type>) 108   && (!std::same_as<std::remove_cvref_t<BS>, value_type>)
HITCBC 109   185 buffer_array(BS const& bs) noexcept 109   185 buffer_array(BS const& bs) noexcept
HITCBC 110   185 : dummy_(0) 110   185 : dummy_(0)
111   { 111   {
HITCBC 112   185 auto it = capy::begin(bs); 112   185 auto it = capy::begin(bs);
HITCBC 113   185 auto const last = capy::end(bs); 113   185 auto const last = capy::end(bs);
HITCBC 114   618 while(it != last && n_ < N) 114   618 while(it != last && n_ < N)
115   { 115   {
HITCBC 116   433 value_type b(*it); 116   433 value_type b(*it);
HITCBC 117   433 if(b.size() != 0) 117   433 if(b.size() != 0)
118   { 118   {
HITCBC 119   427 ::new(&arr_[n_++]) value_type(b); 119   427 ::new(&arr_[n_++]) value_type(b);
HITCBC 120   427 size_ += b.size(); 120   427 size_ += b.size();
121   } 121   }
HITCBC 122   433 ++it; 122   433 ++it;
123   } 123   }
HITCBC 124   185 } 124   185 }
125   125  
126   /** Construct from a buffer sequence with overflow checking. 126   /** Construct from a buffer sequence with overflow checking.
127   127  
128   Copies buffer descriptors from the source sequence 128   Copies buffer descriptors from the source sequence
129   into the internal array. 129   into the internal array.
130   130  
131   @param bs The buffer sequence to copy from. 131   @param bs The buffer sequence to copy from.
132   132  
133   @throws std::length_error if the sequence contains 133   @throws std::length_error if the sequence contains
134   more than N non-empty buffers. 134   more than N non-empty buffers.
135   */ 135   */
136   template<class BS> 136   template<class BS>
137   requires (IsConst ? ConstBufferSequence<BS> : MutableBufferSequence<BS>) 137   requires (IsConst ? ConstBufferSequence<BS> : MutableBufferSequence<BS>)
HITCBC 138   4 buffer_array(std::in_place_t, BS const& bs) 138   4 buffer_array(std::in_place_t, BS const& bs)
HITCBC 139   4 : dummy_(0) 139   4 : dummy_(0)
140   { 140   {
HITCBC 141   4 auto it = capy::begin(bs); 141   4 auto it = capy::begin(bs);
HITCBC 142   4 auto const last = capy::end(bs); 142   4 auto const last = capy::end(bs);
HITCBC 143   14 while(it != last) 143   14 while(it != last)
144   { 144   {
HITCBC 145   12 value_type b(*it); 145   12 value_type b(*it);
HITCBC 146   12 if(b.size() != 0) 146   12 if(b.size() != 0)
147   { 147   {
HITCBC 148   12 if(n_ >= N) 148   12 if(n_ >= N)
HITCBC 149   2 detail::throw_length_error(); 149   2 detail::throw_length_error();
HITCBC 150   10 ::new(&arr_[n_++]) value_type(b); 150   10 ::new(&arr_[n_++]) value_type(b);
HITCBC 151   10 size_ += b.size(); 151   10 size_ += b.size();
152   } 152   }
HITCBC 153   10 ++it; 153   10 ++it;
154   } 154   }
HITCBC 155   2 } 155   2 }
156   156  
157   /** Construct from an iterator range. 157   /** Construct from an iterator range.
158   158  
159   Copies up to N non-empty buffer descriptors from the 159   Copies up to N non-empty buffer descriptors from the
160   range `[first, last)`. If the range contains more than 160   range `[first, last)`. If the range contains more than
161   N non-empty buffers, excess buffers are silently ignored. 161   N non-empty buffers, excess buffers are silently ignored.
162   162  
163   @param first Iterator to the first buffer descriptor. 163   @param first Iterator to the first buffer descriptor.
164   @param last Iterator past the last buffer descriptor. 164   @param last Iterator past the last buffer descriptor.
165   */ 165   */
166   template<class Iterator> 166   template<class Iterator>
HITCBC 167   8 buffer_array(Iterator first, Iterator last) noexcept 167   8 buffer_array(Iterator first, Iterator last) noexcept
HITCBC 168   8 : dummy_(0) 168   8 : dummy_(0)
169   { 169   {
HITCBC 170   26 while(first != last && n_ < N) 170   26 while(first != last && n_ < N)
171   { 171   {
HITCBC 172   18 value_type b(*first); 172   18 value_type b(*first);
HITCBC 173   18 if(b.size() != 0) 173   18 if(b.size() != 0)
174   { 174   {
HITCBC 175   14 ::new(&arr_[n_++]) value_type(b); 175   14 ::new(&arr_[n_++]) value_type(b);
HITCBC 176   14 size_ += b.size(); 176   14 size_ += b.size();
177   } 177   }
HITCBC 178   18 ++first; 178   18 ++first;
179   } 179   }
HITCBC 180   8 } 180   8 }
181   181  
182   /** Construct from an iterator range with overflow checking. 182   /** Construct from an iterator range with overflow checking.
183   183  
184   Copies all non-empty buffer descriptors from the range 184   Copies all non-empty buffer descriptors from the range
185   `[first, last)` into the internal array. 185   `[first, last)` into the internal array.
186   186  
187   @param first Iterator to the first buffer descriptor. 187   @param first Iterator to the first buffer descriptor.
188   @param last Iterator past the last buffer descriptor. 188   @param last Iterator past the last buffer descriptor.
189   189  
190   @throws std::length_error if the range contains more 190   @throws std::length_error if the range contains more
191   than N non-empty buffers. 191   than N non-empty buffers.
192   */ 192   */
193   template<class Iterator> 193   template<class Iterator>
HITCBC 194   4 buffer_array(std::in_place_t, Iterator first, Iterator last) 194   4 buffer_array(std::in_place_t, Iterator first, Iterator last)
HITCBC 195   4 : dummy_(0) 195   4 : dummy_(0)
196   { 196   {
HITCBC 197   14 while(first != last) 197   14 while(first != last)
198   { 198   {
HITCBC 199   12 value_type b(*first); 199   12 value_type b(*first);
HITCBC 200   12 if(b.size() != 0) 200   12 if(b.size() != 0)
201   { 201   {
HITCBC 202   12 if(n_ >= N) 202   12 if(n_ >= N)
HITCBC 203   2 detail::throw_length_error(); 203   2 detail::throw_length_error();
HITCBC 204   10 ::new(&arr_[n_++]) value_type(b); 204   10 ::new(&arr_[n_++]) value_type(b);
HITCBC 205   10 size_ += b.size(); 205   10 size_ += b.size();
206   } 206   }
HITCBC 207   10 ++first; 207   10 ++first;
208   } 208   }
HITCBC 209   2 } 209   2 }
210   210  
211   /** Destructor. 211   /** Destructor.
212   */ 212   */
HITCBC 213   625 ~buffer_array() 213   625 ~buffer_array()
214   { 214   {
HITCBC 215   1725 while(n_--) 215   1725 while(n_--)
HITCBC 216   1100 arr_[n_].~value_type(); 216   1100 arr_[n_].~value_type();
HITCBC 217   625 } 217   625 }
218   218  
219   /** Assign by copying. 219   /** Assign by copying.
220   */ 220   */
221   buffer_array& 221   buffer_array&
HITCBC 222   4 operator=(buffer_array const& other) noexcept 222   4 operator=(buffer_array const& other) noexcept
223   { 223   {
HITCBC 224   4 if(this != &other) 224   4 if(this != &other)
225   { 225   {
HITCBC 226   4 while(n_--) 226   4 while(n_--)
MISUBC 227   arr_[n_].~value_type(); 227   arr_[n_].~value_type();
HITCBC 228   4 n_ = other.n_; 228   4 n_ = other.n_;
HITCBC 229   4 size_ = other.size_; 229   4 size_ = other.size_;
HITCBC 230   10 for(std::size_t i = 0; i < n_; ++i) 230   10 for(std::size_t i = 0; i < n_; ++i)
HITCBC 231   6 ::new(&arr_[i]) value_type(other.arr_[i]); 231   6 ::new(&arr_[i]) value_type(other.arr_[i]);
232   } 232   }
HITCBC 233   4 return *this; 233   4 return *this;
234   } 234   }
235   235  
236   /** Return an iterator to the beginning. 236   /** Return an iterator to the beginning.
237   */ 237   */
238   value_type* 238   value_type*
HITCBC 239   130 begin() noexcept 239   130 begin() noexcept
240   { 240   {
HITCBC 241   130 return arr_; 241   130 return arr_;
242   } 242   }
243   243  
244   /** Return an iterator to the beginning. 244   /** Return an iterator to the beginning.
245   */ 245   */
246   value_type const* 246   value_type const*
HITCBC 247   2441 begin() const noexcept 247   2441 begin() const noexcept
248   { 248   {
HITCBC 249   2441 return arr_; 249   2441 return arr_;
250   } 250   }
251   251  
252   /** Return an iterator to the end. 252   /** Return an iterator to the end.
253   */ 253   */
254   value_type* 254   value_type*
HITCBC 255   129 end() noexcept 255   129 end() noexcept
256   { 256   {
HITCBC 257   129 return arr_ + n_; 257   129 return arr_ + n_;
258   } 258   }
259   259  
260   /** Return an iterator to the end. 260   /** Return an iterator to the end.
261   */ 261   */
262   value_type const* 262   value_type const*
HITCBC 263   2441 end() const noexcept 263   2441 end() const noexcept
264   { 264   {
HITCBC 265   2441 return arr_ + n_; 265   2441 return arr_ + n_;
266   } 266   }
267   267  
268   /** Return a span of the buffers. 268   /** Return a span of the buffers.
269   */ 269   */
270   std::span<value_type> 270   std::span<value_type>
HITCBC 271   379 to_span() noexcept 271   379 to_span() noexcept
272   { 272   {
HITCBC 273   379 return { arr_, n_ }; 273   379 return { arr_, n_ };
274   } 274   }
275   275  
276   /** Return a span of the buffers. 276   /** Return a span of the buffers.
277   */ 277   */
278   std::span<value_type const> 278   std::span<value_type const>
HITCBC 279   175 to_span() const noexcept 279   175 to_span() const noexcept
280   { 280   {
HITCBC 281   175 return { arr_, n_ }; 281   175 return { arr_, n_ };
282   } 282   }
283   283  
284   /** Conversion to mutable span. 284   /** Conversion to mutable span.
285   */ 285   */
HITCBC 286   1 operator std::span<value_type>() noexcept 286   1 operator std::span<value_type>() noexcept
287   { 287   {
HITCBC 288   1 return { arr_, n_ }; 288   1 return { arr_, n_ };
289   } 289   }
290   290  
291   /** Conversion to const span. 291   /** Conversion to const span.
292   */ 292   */
293   operator std::span<value_type const>() const noexcept 293   operator std::span<value_type const>() const noexcept
294   { 294   {
295   return { arr_, n_ }; 295   return { arr_, n_ };
296   } 296   }
297   297  
298   /** Return the total byte count in O(1). 298   /** Return the total byte count in O(1).
299   */ 299   */
300   std::size_t 300   std::size_t
301   byte_size() const noexcept 301   byte_size() const noexcept
302   { 302   {
303   return size_; 303   return size_;
304   } 304   }
305   }; 305   };
306   306  
307   /** Alias for buffer_array holding const_buffer. 307   /** Alias for buffer_array holding const_buffer.
308   308  
309   @tparam N Maximum number of buffers. 309   @tparam N Maximum number of buffers.
310   */ 310   */
311   template<std::size_t N> 311   template<std::size_t N>
312   using const_buffer_array = buffer_array<N, true>; 312   using const_buffer_array = buffer_array<N, true>;
313   313  
314   /** Alias for buffer_array holding mutable_buffer. 314   /** Alias for buffer_array holding mutable_buffer.
315   315  
316   @tparam N Maximum number of buffers. 316   @tparam N Maximum number of buffers.
317   */ 317   */
318   template<std::size_t N> 318   template<std::size_t N>
319   using mutable_buffer_array = buffer_array<N, false>; 319   using mutable_buffer_array = buffer_array<N, false>;
320   320  
321   } // namespace detail 321   } // namespace detail
322   } // namespace capy 322   } // namespace capy
323   } // namespace boost 323   } // namespace boost
324   324  
325   #endif 325   #endif