LCOV - code coverage report
Current view: top level - capy/buffers - buffer_array.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 99.1 % 107 106 1
Test Date: 2026-03-09 21:20:58 Functions: 100.0 % 75 75

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

Generated by: LCOV version 2.3