100.00% Lines (65/65) 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 - // Copyright (c) 2026 Steve Gerbino  
4   // Copyright (c) 2026 Michael Vandeberg 3   // Copyright (c) 2026 Michael Vandeberg
5   // 4   //
6   // Distributed under the Boost Software License, Version 1.0. (See accompanying 5   // 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) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8   // 7   //
9   // Official repository: https://github.com/cppalliance/capy 8   // Official repository: https://github.com/cppalliance/capy
10   // 9   //
11   10  
12   #ifndef BOOST_CAPY_BUFFERS_HPP 11   #ifndef BOOST_CAPY_BUFFERS_HPP
13   #define BOOST_CAPY_BUFFERS_HPP 12   #define BOOST_CAPY_BUFFERS_HPP
14   13  
15   #include <boost/capy/detail/config.hpp> 14   #include <boost/capy/detail/config.hpp>
16   #include <concepts> 15   #include <concepts>
17   #include <cstddef> 16   #include <cstddef>
18   #include <iterator> 17   #include <iterator>
19   #include <memory> 18   #include <memory>
20   #include <ranges> 19   #include <ranges>
21   #include <type_traits> 20   #include <type_traits>
22   21  
23   // https://www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/reference/ConstBufferSequence.html 22   // https://www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/reference/ConstBufferSequence.html
24   23  
25   namespace boost { 24   namespace boost {
26   25  
27   namespace asio { 26   namespace asio {
28   class const_buffer; 27   class const_buffer;
29   class mutable_buffer; 28   class mutable_buffer;
30   } // asio 29   } // asio
31   30  
32   namespace capy { 31   namespace capy {
33   32  
34   class const_buffer; 33   class const_buffer;
35   class mutable_buffer; 34   class mutable_buffer;
36   35  
37   /** A reference to a contiguous region of writable memory. 36   /** A reference to a contiguous region of writable memory.
38   37  
39   Represents a pointer and size pair for a modifiable byte range. 38   Represents a pointer and size pair for a modifiable byte range.
40   Does not own the memory. Satisfies `MutableBufferSequence` (as a 39   Does not own the memory. Satisfies `MutableBufferSequence` (as a
41   single-element sequence) and is implicitly convertible to 40   single-element sequence) and is implicitly convertible to
42   `const_buffer`. 41   `const_buffer`.
43   42  
44   @see @ref const_buffer, @ref MutableBufferSequence 43   @see @ref const_buffer, @ref MutableBufferSequence
45   */ 44   */
46   class mutable_buffer 45   class mutable_buffer
47   { 46   {
48   unsigned char* p_ = nullptr; 47   unsigned char* p_ = nullptr;
49   std::size_t n_ = 0; 48   std::size_t n_ = 0;
50   49  
51   public: 50   public:
52   /// Construct an empty buffer. 51   /// Construct an empty buffer.
HITCBC 53   22 mutable_buffer() = default; 52   19 mutable_buffer() = default;
54   53  
55   /** Construct a copy. 54   /** Construct a copy.
56   55  
57   @param other The buffer to copy. 56   @param other The buffer to copy.
58   */ 57   */
59   mutable_buffer( 58   mutable_buffer(
60   mutable_buffer const& other) = default; 59   mutable_buffer const& other) = default;
61   60  
62   /** Assign by copying. 61   /** Assign by copying.
63   62  
64   @param other The buffer to copy. 63   @param other The buffer to copy.
65   64  
66   @return A reference to `*this`. 65   @return A reference to `*this`.
67   */ 66   */
68   mutable_buffer& operator=( 67   mutable_buffer& operator=(
69   mutable_buffer const& other) = default; 68   mutable_buffer const& other) = default;
70   69  
71   /** Construct from a pointer and size. 70   /** Construct from a pointer and size.
72   71  
73   Takes `void*` so a pointer to any object type binds without a 72   Takes `void*` so a pointer to any object type binds without a
74   cast, since the buffer represents a raw, untyped writable 73   cast, since the buffer represents a raw, untyped writable
75   region. Stored internally as `unsigned char*` for byte-wise 74   region. Stored internally as `unsigned char*` for byte-wise
76   pointer arithmetic (see `operator+=`). 75   pointer arithmetic (see `operator+=`).
77   76  
78   @param data A pointer to the first byte of the region. 77   @param data A pointer to the first byte of the region.
79   78  
80   @param size The size of the region, in bytes. 79   @param size The size of the region, in bytes.
81   */ 80   */
HITCBC 82   35269 constexpr mutable_buffer( 81   35294 constexpr mutable_buffer(
83   void* data, std::size_t size) noexcept 82   void* data, std::size_t size) noexcept
HITCBC 84   35269 : p_(static_cast<unsigned char*>(data)) 83   35294 : p_(static_cast<unsigned char*>(data))
HITCBC 85   35269 , n_(size) 84   35294 , n_(size)
86   { 85   {
HITCBC 87   35269 } 86   35294 }
88   87  
89   /** Return a pointer to the memory region. 88   /** Return a pointer to the memory region.
90   89  
91   Returns `void*`, symmetric with the constructor, so the 90   Returns `void*`, symmetric with the constructor, so the
92   caller can reinterpret the raw region as whatever type it needs. 91   caller can reinterpret the raw region as whatever type it needs.
93   92  
94   @return A pointer to the first byte of the region. 93   @return A pointer to the first byte of the region.
95   */ 94   */
HITCBC 96   53991 constexpr void* data() const noexcept 95   54030 constexpr void* data() const noexcept
97   { 96   {
HITCBC 98   53991 return p_; 97   54030 return p_;
99   } 98   }
100   99  
101   /** Return the size in bytes. 100   /** Return the size in bytes.
102   101  
103   @return The size of the region, in bytes. 102   @return The size of the region, in bytes.
104   */ 103   */
HITCBC 105   80492 constexpr std::size_t size() const noexcept 104   80554 constexpr std::size_t size() const noexcept
106   { 105   {
HITCBC 107   80492 return n_; 106   80554 return n_;
108   } 107   }
109   108  
110   /** Advance the buffer start, shrinking the region. 109   /** Advance the buffer start, shrinking the region.
111   110  
112   @param n Bytes to skip. Clamped to `size()`. 111   @param n Bytes to skip. Clamped to `size()`.
113   112  
114   @return A reference to `*this`. 113   @return A reference to `*this`.
115   */ 114   */
116   mutable_buffer& 115   mutable_buffer&
HITCBC 117   17716 operator+=(std::size_t n) noexcept 116   17722 operator+=(std::size_t n) noexcept
118   { 117   {
HITCBC 119   17716 if( n > n_) 118   17722 if( n > n_)
HITCBC 120   1 n = n_; 119   1 n = n_;
HITCBC 121   17716 p_ += n; 120   17722 p_ += n;
HITCBC 122   17716 n_ -= n; 121   17722 n_ -= n;
HITCBC 123   17716 return *this; 122   17722 return *this;
124   } 123   }
125   }; 124   };
126   125  
127   /** A reference to a contiguous region of read-only memory. 126   /** A reference to a contiguous region of read-only memory.
128   127  
129   Represents a pointer and size pair for a non-modifiable byte range. 128   Represents a pointer and size pair for a non-modifiable byte range.
130   Does not own the memory. Satisfies `ConstBufferSequence` (as a 129   Does not own the memory. Satisfies `ConstBufferSequence` (as a
131   single-element sequence). Implicitly constructible from 130   single-element sequence). Implicitly constructible from
132   `mutable_buffer`. 131   `mutable_buffer`.
133   132  
134   @see @ref mutable_buffer, @ref ConstBufferSequence 133   @see @ref mutable_buffer, @ref ConstBufferSequence
135   */ 134   */
136   class const_buffer 135   class const_buffer
137   { 136   {
138   unsigned char const* p_ = nullptr; 137   unsigned char const* p_ = nullptr;
139   std::size_t n_ = 0; 138   std::size_t n_ = 0;
140   139  
141   public: 140   public:
142   /// Construct an empty buffer. 141   /// Construct an empty buffer.
HITCBC 143   58 const_buffer() = default; 142   16 const_buffer() = default;
144   143  
145   /** Construct a copy. 144   /** Construct a copy.
146   145  
147   @param other The buffer to copy. 146   @param other The buffer to copy.
148   */ 147   */
149   const_buffer(const_buffer const& other) = default; 148   const_buffer(const_buffer const& other) = default;
150   149  
151   /** Assign by copying. 150   /** Assign by copying.
152   151  
153   @param other The buffer to copy. 152   @param other The buffer to copy.
154   153  
155   @return A reference to `*this`. 154   @return A reference to `*this`.
156   */ 155   */
157   const_buffer& operator=( 156   const_buffer& operator=(
158   const_buffer const& other) = default; 157   const_buffer const& other) = default;
159   158  
160   /** Construct from a pointer and size. 159   /** Construct from a pointer and size.
161   160  
162   Takes `void const*` so a pointer to any object type binds 161   Takes `void const*` so a pointer to any object type binds
163   without a cast, since the buffer represents a raw, untyped 162   without a cast, since the buffer represents a raw, untyped
164   read-only region. Stored internally as `unsigned char const*` 163   read-only region. Stored internally as `unsigned char const*`
165   for byte-wise pointer arithmetic (see `operator+=`). 164   for byte-wise pointer arithmetic (see `operator+=`).
166   165  
167   @param data A pointer to the first byte of the region. 166   @param data A pointer to the first byte of the region.
168   167  
169   @param size The size of the region, in bytes. 168   @param size The size of the region, in bytes.
170   */ 169   */
HITCBC 171   31999 constexpr const_buffer( 170   32063 constexpr const_buffer(
172   void const* data, std::size_t size) noexcept 171   void const* data, std::size_t size) noexcept
HITCBC 173   31999 : p_(static_cast<unsigned char const*>(data)) 172   32063 : p_(static_cast<unsigned char const*>(data))
HITCBC 174   31999 , n_(size) 173   32063 , n_(size)
175   { 174   {
HITCBC 176   31999 } 175   32063 }
177   176  
178   /** Construct from mutable_buffer. 177   /** Construct from mutable_buffer.
179   178  
180   @param b The writable buffer whose region is referenced. 179   @param b The writable buffer whose region is referenced.
181   */ 180   */
HITCBC 182   7865 constexpr const_buffer( 181   7890 constexpr const_buffer(
183   mutable_buffer const& b) noexcept 182   mutable_buffer const& b) noexcept
HITCBC 184   7865 : p_(static_cast<unsigned char const*>(b.data())) 183   7890 : p_(static_cast<unsigned char const*>(b.data()))
HITCBC 185   7865 , n_(b.size()) 184   7890 , n_(b.size())
186   { 185   {
HITCBC 187   7865 } 186   7890 }
188   187  
189   /** Return a pointer to the memory region. 188   /** Return a pointer to the memory region.
190   189  
191   Returns `void const*`, symmetric with the constructor, so the 190   Returns `void const*`, symmetric with the constructor, so the
192   caller can reinterpret the raw region as whatever type it needs. 191   caller can reinterpret the raw region as whatever type it needs.
193   192  
194   @return A pointer to the first byte of the region. 193   @return A pointer to the first byte of the region.
195   */ 194   */
HITCBC 196   46540 constexpr void const* data() const noexcept 195   46504 constexpr void const* data() const noexcept
197   { 196   {
HITCBC 198   46540 return p_; 197   46504 return p_;
199   } 198   }
200   199  
201   /** Return the size in bytes. 200   /** Return the size in bytes.
202   201  
203   @return The size of the region, in bytes. 202   @return The size of the region, in bytes.
204   */ 203   */
HITCBC 205   78400 constexpr std::size_t size() const noexcept 204   77578 constexpr std::size_t size() const noexcept
206   { 205   {
HITCBC 207   78400 return n_; 206   77578 return n_;
208   } 207   }
209   208  
210   /** Advance the buffer start, shrinking the region. 209   /** Advance the buffer start, shrinking the region.
211   210  
212   @param n Bytes to skip. Clamped to `size()`. 211   @param n Bytes to skip. Clamped to `size()`.
213   212  
214   @return A reference to `*this`. 213   @return A reference to `*this`.
215   */ 214   */
216   const_buffer& 215   const_buffer&
HITCBC 217   17361 operator+=(std::size_t n) noexcept 216   17368 operator+=(std::size_t n) noexcept
218   { 217   {
HITCBC 219   17361 if( n > n_) 218   17368 if( n > n_)
HITCBC 220   1 n = n_; 219   1 n = n_;
HITCBC 221   17361 p_ += n; 220   17368 p_ += n;
HITCBC 222   17361 n_ -= n; 221   17368 n_ -= n;
HITCBC 223   17361 return *this; 222   17368 return *this;
224   } 223   }
225   }; 224   };
226   225  
227 - /** Requires a type to convert to `const_buffer`. 226 + /** Requires a type to convert to `const_buffer`, or be a range of such buffers.
228 -  
229 - This is the element requirement of @ref ConstBufferSequence.  
230 -  
231 - For a `T const` lvalue `x`, both `const_buffer b = x;` and  
232 - `const_buffer(x)` must be valid, since algorithms convert elements  
233 - through a const reference and may use either form. A conversion  
234 - operator must therefore be `const`.  
235 -  
236 - @note Algorithms that read buffer sequences are `noexcept`, so a  
237 - conversion that throws terminates the program. Conversion operators  
238 - should be `noexcept`.  
239 -  
240 - @see @ref const_buffer, @ref MutableBuffer  
241 - */  
242 - template<typename T>  
243 - concept ConstBuffer =  
244 - std::convertible_to<T const&, const_buffer>;  
245 -  
246 - /** Requires a type to convert to both `mutable_buffer` and `const_buffer`.  
247 -  
248 - This is the element requirement of @ref MutableBufferSequence.  
249 -  
250 - A type that converts only to `mutable_buffer` does not qualify.  
251 - Reaching `const_buffer` from it takes two user-defined conversions,  
252 - and an implicit conversion sequence allows one. Such a type must  
253 - also provide a conversion to `const_buffer`.  
254 -  
255 - As with @ref ConstBuffer, the conversion is from a `T const` lvalue,  
256 - and conversion operators should be `noexcept`.  
257 -  
258 - @see @ref mutable_buffer, @ref ConstBuffer  
259 - */  
260 - template<typename T>  
261 - concept MutableBuffer =  
262 - ConstBuffer<T> && std::convertible_to<T const&, mutable_buffer>;  
263 -  
264 - /** Requires a type to be a @ref ConstBuffer, or a range of them.  
265   227  
266   A type satisfies `ConstBufferSequence` if it represents one or more 228   A type satisfies `ConstBufferSequence` if it represents one or more
267   contiguous memory regions that can be read. This includes single 229   contiguous memory regions that can be read. This includes single
268 - buffers and ranges of buffers. 230 + buffers (convertible to `const_buffer`) and ranges of buffers.
269   231  
270   @par Syntactic Requirements 232   @par Syntactic Requirements
271 - @li @ref ConstBuffer, OR 233 + @li Convertible to `const_buffer`, OR
272 - @li A bidirectional range whose value type is a @ref ConstBuffer 234 + @li A bidirectional range with value type convertible to `const_buffer`
273   235  
274   @see @ref const_buffer, @ref MutableBufferSequence 236   @see @ref const_buffer, @ref MutableBufferSequence
275   */ 237   */
276   // tag::const_buffer_sequence_concept[] 238   // tag::const_buffer_sequence_concept[]
277   template<typename T> 239   template<typename T>
278   concept ConstBufferSequence = 240   concept ConstBufferSequence =
279 - ConstBuffer<T> || ( 241 + std::is_convertible_v<T, const_buffer> || (
280   std::ranges::bidirectional_range<T> && 242   std::ranges::bidirectional_range<T> &&
281 - ConstBuffer<std::ranges::range_value_t<T>>); 243 + std::is_convertible_v<std::ranges::range_value_t<T>, const_buffer>);
282   // end::const_buffer_sequence_concept[] 244   // end::const_buffer_sequence_concept[]
283   245  
284 - /** Requires a type to be a @ref MutableBuffer, or a range of them. 246 + /** Requires a type to convert to `mutable_buffer`, or be a range of such buffers.
285   247  
286   A type satisfies `MutableBufferSequence` if it represents one or more 248   A type satisfies `MutableBufferSequence` if it represents one or more
287   contiguous memory regions that can be written. This includes single 249   contiguous memory regions that can be written. This includes single
288 - buffers and ranges of buffers. 250 + buffers (convertible to `mutable_buffer`) and ranges of buffers.
289 -  
290 - Every `MutableBufferSequence` is also a @ref ConstBufferSequence.  
291   251  
292 - A @ref ConstBuffer is a single buffer, even if it is also a range, 252 + This does not imply `ConstBufferSequence`. A type reaching
293 - so only its own conversion to `mutable_buffer` is considered. 253 + `mutable_buffer` through its own conversion operator would need a
  254 + second conversion, to `const_buffer`. An implicit conversion
  255 + sequence allows only one user-defined step.
294   256  
295   @par Syntactic Requirements 257   @par Syntactic Requirements
296 - @li @ref MutableBuffer, OR 258 + @li Convertible to `mutable_buffer`, OR
297 - @li A bidirectional range, not a @ref ConstBuffer, whose value type 259 + @li A bidirectional range with value type convertible to `mutable_buffer`
298 - is a @ref MutableBuffer  
299   260  
300   @see @ref mutable_buffer, @ref ConstBufferSequence 261   @see @ref mutable_buffer, @ref ConstBufferSequence
301   */ 262   */
302   // tag::mutable_buffer_sequence_concept[] 263   // tag::mutable_buffer_sequence_concept[]
303   template<typename T> 264   template<typename T>
304   concept MutableBufferSequence = 265   concept MutableBufferSequence =
305 - ConstBufferSequence<T> && (MutableBuffer<T> || ( 266 + std::is_convertible_v<T, mutable_buffer> || (
306 - !ConstBuffer<T> &&  
307   std::ranges::bidirectional_range<T> && 267   std::ranges::bidirectional_range<T> &&
308 - MutableBuffer<std::ranges::range_value_t<T>>)); 268 + std::is_convertible_v<std::ranges::range_value_t<T>, mutable_buffer>);
309   // end::mutable_buffer_sequence_concept[] 269   // end::mutable_buffer_sequence_concept[]
310   270  
311   /** Return an iterator to the first buffer in a sequence. 271   /** Return an iterator to the first buffer in a sequence.
312   272  
313   @functionobject 273   @functionobject
314   */ 274   */
315   constexpr struct 275   constexpr struct
316   { 276   {
317   /** Return a pointer to a single buffer, forming a one-element range. 277   /** Return a pointer to a single buffer, forming a one-element range.
318   278  
319   @param b A single buffer. 279   @param b A single buffer.
320   280  
321   @return A pointer to `b`. 281   @return A pointer to `b`.
322   */ 282   */
323 - template<ConstBuffer ConvertibleToBuffer> 283 + template<std::convertible_to<const_buffer> ConvertibleToBuffer>
HITCBC 324   6657 auto operator()(ConvertibleToBuffer const& b) const noexcept -> ConvertibleToBuffer const* 284   6658 auto operator()(ConvertibleToBuffer const& b) const noexcept -> ConvertibleToBuffer const*
325   { 285   {
HITCBC 326   6657 return std::addressof(b); 286   6658 return std::addressof(b);
327   } 287   }
328   288  
329   /** Return an iterator to the first buffer of a sequence. 289   /** Return an iterator to the first buffer of a sequence.
330   290  
331   @param bs The buffer sequence. 291   @param bs The buffer sequence.
332   292  
333   @return An iterator to the first buffer of `bs`. 293   @return An iterator to the first buffer of `bs`.
334   */ 294   */
335   template<ConstBufferSequence BS> 295   template<ConstBufferSequence BS>
336 - requires (!ConstBuffer<BS>) 296 + requires (!std::convertible_to<BS, const_buffer>)
HITCBC 337   33657 auto operator()(BS const& bs) const noexcept 297   33650 auto operator()(BS const& bs) const noexcept
338   { 298   {
HITCBC 339   33657 return std::ranges::begin(bs); 299   33650 return std::ranges::begin(bs);
340   } 300   }
341   301  
342   /** Return an iterator to the first buffer of a sequence. 302   /** Return an iterator to the first buffer of a sequence.
343   303  
344   @param bs The buffer sequence. 304   @param bs The buffer sequence.
345   305  
346   @return An iterator to the first buffer of `bs`. 306   @return An iterator to the first buffer of `bs`.
347   */ 307   */
348   template<ConstBufferSequence BS> 308   template<ConstBufferSequence BS>
349 - requires (!ConstBuffer<BS>) 309 + requires (!std::convertible_to<BS, const_buffer>)
HITCBC 350   9196 auto operator()(BS& bs) const noexcept 310   9196 auto operator()(BS& bs) const noexcept
351   { 311   {
HITCBC 352   9196 return std::ranges::begin(bs); 312   9196 return std::ranges::begin(bs);
353   } 313   }
354 - } buffer_sequence_begin {}; 314 + } begin {};
355   315  
356   /** Return an iterator past the last buffer in a sequence. 316   /** Return an iterator past the last buffer in a sequence.
357   317  
358   @functionobject 318   @functionobject
359   */ 319   */
360   constexpr struct 320   constexpr struct
361   { 321   {
362   /** Return a pointer one past a single buffer, forming a one-element range. 322   /** Return a pointer one past a single buffer, forming a one-element range.
363   323  
364   @param b A single buffer. 324   @param b A single buffer.
365   325  
366   @return A pointer one past `b`. 326   @return A pointer one past `b`.
367   */ 327   */
368 - template<ConstBuffer ConvertibleToBuffer> 328 + template<std::convertible_to<const_buffer> ConvertibleToBuffer>
HITCBC 369   6660 auto operator()(ConvertibleToBuffer const& b) const noexcept -> ConvertibleToBuffer const* 329   6660 auto operator()(ConvertibleToBuffer const& b) const noexcept -> ConvertibleToBuffer const*
370   { 330   {
HITCBC 371   6660 return std::addressof(b) + 1; 331   6660 return std::addressof(b) + 1;
372   } 332   }
373   333  
374   /** Return an iterator past the last buffer of a sequence. 334   /** Return an iterator past the last buffer of a sequence.
375   335  
376   @param bs The buffer sequence. 336   @param bs The buffer sequence.
377   337  
378   @return An iterator one past the last buffer of `bs`. 338   @return An iterator one past the last buffer of `bs`.
379   */ 339   */
380   template<ConstBufferSequence BS> 340   template<ConstBufferSequence BS>
381 - requires (!ConstBuffer<BS>) 341 + requires (!std::convertible_to<BS, const_buffer>)
HITCBC 382   33696 auto operator()(BS const& bs) const noexcept 342   33672 auto operator()(BS const& bs) const noexcept
383   { 343   {
HITCBC 384   33696 return std::ranges::end(bs); 344   33672 return std::ranges::end(bs);
385   } 345   }
386   346  
387   /** Return an iterator past the last buffer of a sequence. 347   /** Return an iterator past the last buffer of a sequence.
388   348  
389   @param bs The buffer sequence. 349   @param bs The buffer sequence.
390   350  
391   @return An iterator one past the last buffer of `bs`. 351   @return An iterator one past the last buffer of `bs`.
392   */ 352   */
393   template<ConstBufferSequence BS> 353   template<ConstBufferSequence BS>
394 - requires (!ConstBuffer<BS>) 354 + requires (!std::convertible_to<BS, const_buffer>)
HITCBC 395   9196 auto operator()(BS& bs) const noexcept 355   9196 auto operator()(BS& bs) const noexcept
396   { 356   {
HITCBC 397   9196 return std::ranges::end(bs); 357   9196 return std::ranges::end(bs);
398   } 358   }
399 - } buffer_sequence_end {}; 359 + } end {};
400   360  
401   /** Return the total byte count across all buffers in a sequence. 361   /** Return the total byte count across all buffers in a sequence.
402   362  
403   @functionobject 363   @functionobject
404   */ 364   */
405   constexpr struct 365   constexpr struct
406   { 366   {
407   // GCC 13 falsely flags reads of arr_[i].n_ in detail::buffer_array 367   // GCC 13 falsely flags reads of arr_[i].n_ in detail::buffer_array
408   // when iterating here. The class uses union storage with placement 368   // when iterating here. The class uses union storage with placement
409   // new for slots 0..n_-1, so reads inside this bounded loop are 369   // new for slots 0..n_-1, so reads inside this bounded loop are
410   // well-defined, but the optimizer can't prove the loop bound and 370   // well-defined, but the optimizer can't prove the loop bound and
411   // warns. The runtime cost of value-initializing all N slots is 371   // warns. The runtime cost of value-initializing all N slots is
412   // non-trivial for non-trivial value types, so we suppress instead. 372   // non-trivial for non-trivial value types, so we suppress instead.
413   #if defined(__GNUC__) && !defined(__clang__) 373   #if defined(__GNUC__) && !defined(__clang__)
414   #pragma GCC diagnostic push 374   #pragma GCC diagnostic push
415   #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 375   #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
416   #endif 376   #endif
417   /** Return the total byte count across all buffers in a sequence. 377   /** Return the total byte count across all buffers in a sequence.
418   378  
419   Sums the `size()` of each buffer in the sequence. This differs 379   Sums the `size()` of each buffer in the sequence. This differs
420 - from `buffers_count` which counts the number of buffer elements. 380 + from `buffer_length` which counts the number of buffer elements.
421   381  
422   @param bs The buffer sequence. 382   @param bs The buffer sequence.
423   383  
424   @return The sum of the sizes of all buffers in `bs`. 384   @return The sum of the sizes of all buffers in `bs`.
425   385  
426   @par Example 386   @par Example
427   @par !example example 387   @par !example example
428   388  
429   */ 389   */
430   template<ConstBufferSequence CB> 390   template<ConstBufferSequence CB>
HITCBC 431   6291 constexpr std::size_t operator()( 391   6274 constexpr std::size_t operator()(
432   CB const& bs) const noexcept 392   CB const& bs) const noexcept
433   { 393   {
HITCBC 434   6291 std::size_t n = 0; 394   6274 std::size_t n = 0;
HITCBC 435 - 6291 auto const e = capy::buffer_sequence_end(bs); 395 + 6274 auto const e = capy::end(bs);
HITCBC 436 - 14581 for(auto it = capy::buffer_sequence_begin(bs); it != e; ++it) 396 + 14475 for(auto it = capy::begin(bs); it != e; ++it)
HITCBC 437   8290 n += const_buffer(*it).size(); 397   8201 n += const_buffer(*it).size();
HITCBC 438   6291 return n; 398   6274 return n;
439   } 399   }
440   #if defined(__GNUC__) && !defined(__clang__) 400   #if defined(__GNUC__) && !defined(__clang__)
441   #pragma GCC diagnostic pop 401   #pragma GCC diagnostic pop
442   #endif 402   #endif
443   } buffer_size {}; 403   } buffer_size {};
444   404  
445   /** Check if a buffer sequence contains no data. 405   /** Check if a buffer sequence contains no data.
446   406  
447   @functionobject 407   @functionobject
448   */ 408   */
449   constexpr struct 409   constexpr struct
450   { 410   {
451   // See note on buffer_size above — same union-storage false positive. 411   // See note on buffer_size above — same union-storage false positive.
452   #if defined(__GNUC__) && !defined(__clang__) 412   #if defined(__GNUC__) && !defined(__clang__)
453   #pragma GCC diagnostic push 413   #pragma GCC diagnostic push
454   #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 414   #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
455   #endif 415   #endif
456   /** Check if a buffer sequence contains no data. 416   /** Check if a buffer sequence contains no data.
457   417  
458   @param bs The buffer sequence. 418   @param bs The buffer sequence.
459   419  
460   @return `true` if all buffers have size zero or the sequence 420   @return `true` if all buffers have size zero or the sequence
461   is empty. 421   is empty.
462   */ 422   */
463   template<ConstBufferSequence CB> 423   template<ConstBufferSequence CB>
HITCBC 464   1569 constexpr bool operator()( 424   1575 constexpr bool operator()(
465   CB const& bs) const noexcept 425   CB const& bs) const noexcept
466   { 426   {
HITCBC 467 - 1569 auto it = buffer_sequence_begin(bs); 427 + 1575 auto it = begin(bs);
HITCBC 468 - 1569 auto const end_ = buffer_sequence_end(bs); 428 + 1575 auto const end_ = end(bs);
HITCBC 469   1617 while(it != end_) 429   1623 while(it != end_)
470   { 430   {
HITCBC 471   1581 const_buffer b(*it++); 431   1587 const_buffer b(*it++);
HITCBC 472   1581 if(b.size() != 0) 432   1587 if(b.size() != 0)
HITCBC 473   1533 return false; 433   1539 return false;
474   } 434   }
HITCBC 475   36 return true; 435   36 return true;
476   } 436   }
477   #if defined(__GNUC__) && !defined(__clang__) 437   #if defined(__GNUC__) && !defined(__clang__)
478   #pragma GCC diagnostic pop 438   #pragma GCC diagnostic pop
479   #endif 439   #endif
480 - } buffers_empty {}; 440 + } buffer_empty {};
481   441  
482   namespace detail { 442   namespace detail {
483   443  
484   template<class It> 444   template<class It>
485   auto 445   auto
HITCBC 486   8 length_impl(It first, It last, int) 446   8 length_impl(It first, It last, int)
487   -> decltype(static_cast<std::size_t>(last - first)) 447   -> decltype(static_cast<std::size_t>(last - first))
488   { 448   {
HITCBC 489   8 return static_cast<std::size_t>(last - first); 449   8 return static_cast<std::size_t>(last - first);
490   } 450   }
491   451  
492   template<class It> 452   template<class It>
493   std::size_t 453   std::size_t
494   length_impl(It first, It last, long) 454   length_impl(It first, It last, long)
495   { 455   {
496   std::size_t n = 0; 456   std::size_t n = 0;
497   while(first != last) 457   while(first != last)
498   { 458   {
499   ++first; 459   ++first;
500   ++n; 460   ++n;
501   } 461   }
502   return n; 462   return n;
503   } 463   }
504   464  
505   } // detail 465   } // detail
506   466  
507   /** Return the number of buffer elements in a sequence. 467   /** Return the number of buffer elements in a sequence.
508   468  
509   Counts the number of individual buffer objects, not bytes. 469   Counts the number of individual buffer objects, not bytes.
510   For a single buffer, returns 1. For a range, returns the 470   For a single buffer, returns 1. For a range, returns the
511 - distance from `buffer_sequence_begin` to `buffer_sequence_end`. 471 + distance from `begin` to `end`.
512   472  
513   @param bs The buffer sequence. 473   @param bs The buffer sequence.
514   474  
515   @return The number of buffers in `bs`. 475   @return The number of buffers in `bs`.
516   476  
517   @see @ref buffer_size 477   @see @ref buffer_size
518   */ 478   */
519   template<ConstBufferSequence CB> 479   template<ConstBufferSequence CB>
520   std::size_t 480   std::size_t
HITCBC 521 - 8 buffers_count(CB const& bs) 481 + 8 buffer_length(CB const& bs)
522   { 482   {
HITCBC 523   8 return detail::length_impl( 483   8 return detail::length_impl(
HITCBC 524 - 8 buffer_sequence_begin(bs), buffer_sequence_end(bs), 0); 484 + 8 begin(bs), end(bs), 0);
525   } 485   }
526   486  
527   /// Names `mutable_buffer` for a mutable sequence, `const_buffer` otherwise. 487   /// Names `mutable_buffer` for a mutable sequence, `const_buffer` otherwise.
528   template<typename BS> 488   template<typename BS>
529   using buffer_type = std::conditional_t< 489   using buffer_type = std::conditional_t<
530   MutableBufferSequence<BS>, 490   MutableBufferSequence<BS>,
531   mutable_buffer, const_buffer>; 491   mutable_buffer, const_buffer>;
532   492  
533   } // capy 493   } // capy
534   } // boost 494   } // boost
535   495  
536   #endif 496   #endif