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