LCOV - code coverage report
Current view: top level - capy/buffers - buffer_array.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 99.1 % 107 106
Test Date: 2026-02-07 18:59:16 Functions: 100.0 % 75 75

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

Generated by: LCOV version 2.3