LCOV - code coverage report
Current view: top level - boost/capy/buffers - buffer_array.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 98.8 % 85 84
Test Date: 2026-02-05 17:34:57 Functions: 100.0 % 49 49

            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         4386 :     buffer_array(buffer_array const& other) noexcept
     110         4386 :         : n_(other.n_)
     111         4386 :         , size_(other.size_)
     112              :     {
     113        11408 :         for(std::size_t i = 0; i < n_; ++i)
     114         7022 :             ::new(&arr_[i]) value_type(other.arr_[i]);
     115         4386 :     }
     116              : 
     117              :     /** Construct from a single buffer.
     118              : 
     119              :         @param b The buffer to store.
     120              :     */
     121           11 :     buffer_array(value_type const& b) noexcept
     122           11 :         : dummy_(0)
     123              :     {
     124           11 :         if(b.size() != 0)
     125              :         {
     126           10 :             ::new(&arr_[0]) value_type(b);
     127           10 :             n_ = 1;
     128           10 :             size_ = b.size();
     129              :         }
     130           11 :     }
     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           38 :     buffer_array(BS const& bs) noexcept
     146           38 :         : dummy_(0)
     147              :     {
     148           38 :         auto it = capy::begin(bs);
     149           38 :         auto const last = capy::end(bs);
     150          116 :         while(it != last && n_ < N)
     151              :         {
     152           78 :             value_type b(*it);
     153           78 :             if(b.size() != 0)
     154              :             {
     155           74 :                 ::new(&arr_[n_++]) value_type(b);
     156           74 :                 size_ += b.size();
     157              :             }
     158           78 :             ++it;
     159              :         }
     160           38 :     }
     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              :     /** Destructor.
     194              :     */
     195         4443 :     ~buffer_array()
     196              :     {
     197        10361 :         while(n_--)
     198         5918 :             arr_[n_].~value_type();
     199         4443 :     }
     200              : 
     201              :     /** Copy assignment.
     202              :     */
     203              :     buffer_array&
     204            4 :     operator=(buffer_array const& other) noexcept
     205              :     {
     206            4 :         if(this != &other)
     207              :         {
     208            4 :             while(n_--)
     209            0 :                 arr_[n_].~value_type();
     210            4 :             n_ = other.n_;
     211            4 :             size_ = other.size_;
     212           10 :             for(std::size_t i = 0; i < n_; ++i)
     213            6 :                 ::new(&arr_[i]) value_type(other.arr_[i]);
     214              :         }
     215            4 :         return *this;
     216              :     }
     217              : 
     218              :     /** Return an iterator to the beginning.
     219              :     */
     220              :     value_type*
     221         8834 :     begin() noexcept
     222              :     {
     223         8834 :         return arr_;
     224              :     }
     225              : 
     226              :     /** Return an iterator to the beginning.
     227              :     */
     228              :     value_type const*
     229        11018 :     begin() const noexcept
     230              :     {
     231        11018 :         return arr_;
     232              :     }
     233              : 
     234              :     /** Return an iterator to the end.
     235              :     */
     236              :     value_type*
     237         8833 :     end() noexcept
     238              :     {
     239         8833 :         return arr_ + n_;
     240              :     }
     241              : 
     242              :     /** Return an iterator to the end.
     243              :     */
     244              :     value_type const*
     245        11018 :     end() const noexcept
     246              :     {
     247        11018 :         return arr_ + n_;
     248              :     }
     249              : 
     250              :     /** Return a span of the buffers.
     251              :     */
     252              :     std::span<value_type>
     253           19 :     to_span() noexcept
     254              :     {
     255           19 :         return { arr_, n_ };
     256              :     }
     257              : 
     258              :     /** Return a span of the buffers.
     259              :     */
     260              :     std::span<value_type const>
     261              :     to_span() const noexcept
     262              :     {
     263              :         return { arr_, n_ };
     264              :     }
     265              : 
     266              :     /** Conversion to mutable span.
     267              :     */
     268            1 :     operator std::span<value_type>() noexcept
     269              :     {
     270            1 :         return { arr_, n_ };
     271              :     }
     272              : 
     273              :     /** Conversion to const span.
     274              :     */
     275              :     operator std::span<value_type const>() const noexcept
     276              :     {
     277              :         return { arr_, n_ };
     278              :     }
     279              : 
     280              :     /** Return the total byte count in O(1).
     281              :     */
     282              :     friend
     283              :     std::size_t
     284         5489 :     tag_invoke(
     285              :         size_tag const&,
     286              :         buffer_array const& ba) noexcept
     287              :     {
     288         5489 :         return ba.size_;
     289              :     }
     290              : 
     291              :     /** Slice customization point.
     292              :     */
     293              :     friend
     294              :     void
     295         2080 :     tag_invoke(
     296              :         slice_tag const&,
     297              :         buffer_array& ba,
     298              :         slice_how how,
     299              :         std::size_t n) noexcept
     300              :     {
     301         2080 :         ba.slice_impl(how, n);
     302         2080 :     }
     303              : 
     304              : private:
     305              :     void
     306         2080 :     slice_impl(
     307              :         slice_how how,
     308              :         std::size_t n) noexcept
     309              :     {
     310         2080 :         switch(how)
     311              :         {
     312         1024 :         case slice_how::remove_prefix:
     313         1024 :             remove_prefix_impl(n);
     314         1024 :             break;
     315              : 
     316         1056 :         case slice_how::keep_prefix:
     317         1056 :             keep_prefix_impl(n);
     318         1056 :             break;
     319              :         }
     320         2080 :     }
     321              : 
     322              :     void
     323         1024 :     remove_prefix_impl(std::size_t n) noexcept
     324              :     {
     325         1024 :         detail::buffer_array_remove_prefix(arr_, &n_, &size_, n);
     326         1024 :     }
     327              : 
     328              :     void
     329         1056 :     keep_prefix_impl(std::size_t n) noexcept
     330              :     {
     331         1056 :         detail::buffer_array_keep_prefix(arr_, &n_, &size_, n);
     332         1056 :     }
     333              : };
     334              : 
     335              : //------------------------------------------------
     336              : 
     337              : /** Alias for buffer_array holding const_buffer.
     338              : 
     339              :     @tparam N Maximum number of buffers.
     340              : */
     341              : template<std::size_t N>
     342              : using const_buffer_array = buffer_array<N, true>;
     343              : 
     344              : /** Alias for buffer_array holding mutable_buffer.
     345              : 
     346              :     @tparam N Maximum number of buffers.
     347              : */
     348              : template<std::size_t N>
     349              : using mutable_buffer_array = buffer_array<N, false>;
     350              : 
     351              : } // namespace capy
     352              : } // namespace boost
     353              : 
     354              : #endif
        

Generated by: LCOV version 2.3