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-02-17 18:14:47 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                 :     @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 HIT           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 MIS           0 :                 arr_[n_].~value_type();
     264 HIT           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