LCOV - code coverage report
Current view: top level - capy/detail - buffer_array.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 98.9 % 87 86 1
Test Date: 2026-05-14 20:50:55 Functions: 100.0 % 67 67

           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_DETAIL_BUFFER_ARRAY_HPP
      11                 : #define BOOST_CAPY_DETAIL_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                 : namespace detail {
      25                 : 
      26                 : /** A buffer sequence holding up to N buffers.
      27                 : 
      28                 :     This class template stores a fixed-capacity array of buffer
      29                 :     descriptors, where the actual count can vary from 0 to N.
      30                 :     It provides efficient storage for small buffer sequences
      31                 :     without dynamic allocation.
      32                 : 
      33                 :     @par Example
      34                 :     @code
      35                 :     void process(ConstBufferSequence auto const& buffers)
      36                 :     {
      37                 :         detail::const_buffer_array<4> bufs(buffers);
      38                 :         // use bufs.begin(), bufs.end(), bufs.to_span()
      39                 :     }
      40                 :     @endcode
      41                 : 
      42                 :     @tparam N Maximum number of buffers the array can hold.
      43                 :     @tparam IsConst If true, holds const_buffer; otherwise mutable_buffer.
      44                 : */
      45                 : template<std::size_t N, bool IsConst>
      46                 : class buffer_array
      47                 : {
      48                 : public:
      49                 :     /** The type of buffer stored in the array.
      50                 :     */
      51                 :     using value_type = std::conditional_t<IsConst, const_buffer, mutable_buffer>;
      52                 : 
      53                 : private:
      54                 :     std::size_t n_ = 0;
      55                 :     std::size_t size_ = 0;
      56                 :     union {
      57                 :         int dummy_;
      58                 :         value_type arr_[N];
      59                 :     };
      60                 : 
      61                 : public:
      62                 :     /** Construct a default instance.
      63                 : 
      64                 :         Constructs an empty buffer array.
      65                 :     */
      66 HIT           6 :     buffer_array() noexcept
      67               6 :         : dummy_(0)
      68                 :     {
      69               6 :     }
      70                 : 
      71                 :     /** Construct a copy.
      72                 :     */
      73             292 :     buffer_array(buffer_array const& other) noexcept
      74             292 :         : n_(other.n_)
      75             292 :         , size_(other.size_)
      76                 :     {
      77             811 :         for(std::size_t i = 0; i < n_; ++i)
      78             519 :             ::new(&arr_[i]) value_type(other.arr_[i]);
      79             292 :     }
      80                 : 
      81                 :     /** Construct from a single buffer.
      82                 : 
      83                 :         @param b The buffer to store.
      84                 :     */
      85             130 :     buffer_array(value_type const& b) noexcept
      86             130 :         : dummy_(0)
      87                 :     {
      88             130 :         if(b.size() != 0)
      89                 :         {
      90             122 :             ::new(&arr_[0]) value_type(b);
      91             122 :             n_ = 1;
      92             122 :             size_ = b.size();
      93                 :         }
      94             130 :     }
      95                 : 
      96                 :     /** Construct from a buffer sequence.
      97                 : 
      98                 :         Copies up to N buffer descriptors from the source
      99                 :         sequence into the internal array. If the sequence
     100                 :         contains more than N non-empty buffers, excess
     101                 :         buffers are silently ignored.
     102                 : 
     103                 :         @param bs The buffer sequence to copy from.
     104                 :     */
     105                 :     template<class BS>
     106                 :         requires (IsConst ? ConstBufferSequence<BS> : MutableBufferSequence<BS>)
     107                 :             && (!std::same_as<std::remove_cvref_t<BS>, buffer_array>)
     108                 :             && (!std::same_as<std::remove_cvref_t<BS>, value_type>)
     109             185 :     buffer_array(BS const& bs) noexcept
     110             185 :         : dummy_(0)
     111                 :     {
     112             185 :         auto it = capy::begin(bs);
     113             185 :         auto const last = capy::end(bs);
     114             618 :         while(it != last && n_ < N)
     115                 :         {
     116             433 :             value_type b(*it);
     117             433 :             if(b.size() != 0)
     118                 :             {
     119             427 :                 ::new(&arr_[n_++]) value_type(b);
     120             427 :                 size_ += b.size();
     121                 :             }
     122             433 :             ++it;
     123                 :         }
     124             185 :     }
     125                 : 
     126                 :     /** Construct from a buffer sequence with overflow checking.
     127                 : 
     128                 :         Copies buffer descriptors from the source sequence
     129                 :         into the internal array.
     130                 : 
     131                 :         @param bs The buffer sequence to copy from.
     132                 : 
     133                 :         @throws std::length_error if the sequence contains
     134                 :         more than N non-empty buffers.
     135                 :     */
     136                 :     template<class BS>
     137                 :         requires (IsConst ? ConstBufferSequence<BS> : MutableBufferSequence<BS>)
     138               4 :     buffer_array(std::in_place_t, BS const& bs)
     139               4 :         : dummy_(0)
     140                 :     {
     141               4 :         auto it = capy::begin(bs);
     142               4 :         auto const last = capy::end(bs);
     143              14 :         while(it != last)
     144                 :         {
     145              12 :             value_type b(*it);
     146              12 :             if(b.size() != 0)
     147                 :             {
     148              12 :                 if(n_ >= N)
     149               2 :                     detail::throw_length_error();
     150              10 :                 ::new(&arr_[n_++]) value_type(b);
     151              10 :                 size_ += b.size();
     152                 :             }
     153              10 :             ++it;
     154                 :         }
     155               2 :     }
     156                 : 
     157                 :     /** Construct from an iterator range.
     158                 : 
     159                 :         Copies up to N non-empty buffer descriptors from the
     160                 :         range `[first, last)`. If the range contains more than
     161                 :         N non-empty buffers, excess buffers are silently ignored.
     162                 : 
     163                 :         @param first Iterator to the first buffer descriptor.
     164                 :         @param last Iterator past the last buffer descriptor.
     165                 :     */
     166                 :     template<class Iterator>
     167               8 :     buffer_array(Iterator first, Iterator last) noexcept
     168               8 :         : dummy_(0)
     169                 :     {
     170              26 :         while(first != last && n_ < N)
     171                 :         {
     172              18 :             value_type b(*first);
     173              18 :             if(b.size() != 0)
     174                 :             {
     175              14 :                 ::new(&arr_[n_++]) value_type(b);
     176              14 :                 size_ += b.size();
     177                 :             }
     178              18 :             ++first;
     179                 :         }
     180               8 :     }
     181                 : 
     182                 :     /** Construct from an iterator range with overflow checking.
     183                 : 
     184                 :         Copies all non-empty buffer descriptors from the range
     185                 :         `[first, last)` into the internal array.
     186                 : 
     187                 :         @param first Iterator to the first buffer descriptor.
     188                 :         @param last Iterator past the last buffer descriptor.
     189                 : 
     190                 :         @throws std::length_error if the range contains more
     191                 :         than N non-empty buffers.
     192                 :     */
     193                 :     template<class Iterator>
     194               4 :     buffer_array(std::in_place_t, Iterator first, Iterator last)
     195               4 :         : dummy_(0)
     196                 :     {
     197              14 :         while(first != last)
     198                 :         {
     199              12 :             value_type b(*first);
     200              12 :             if(b.size() != 0)
     201                 :             {
     202              12 :                 if(n_ >= N)
     203               2 :                     detail::throw_length_error();
     204              10 :                 ::new(&arr_[n_++]) value_type(b);
     205              10 :                 size_ += b.size();
     206                 :             }
     207              10 :             ++first;
     208                 :         }
     209               2 :     }
     210                 : 
     211                 :     /** Destructor.
     212                 :     */
     213             625 :     ~buffer_array()
     214                 :     {
     215            1725 :         while(n_--)
     216            1100 :             arr_[n_].~value_type();
     217             625 :     }
     218                 : 
     219                 :     /** Assign by copying.
     220                 :     */
     221                 :     buffer_array&
     222               4 :     operator=(buffer_array const& other) noexcept
     223                 :     {
     224               4 :         if(this != &other)
     225                 :         {
     226               4 :             while(n_--)
     227 MIS           0 :                 arr_[n_].~value_type();
     228 HIT           4 :             n_ = other.n_;
     229               4 :             size_ = other.size_;
     230              10 :             for(std::size_t i = 0; i < n_; ++i)
     231               6 :                 ::new(&arr_[i]) value_type(other.arr_[i]);
     232                 :         }
     233               4 :         return *this;
     234                 :     }
     235                 : 
     236                 :     /** Return an iterator to the beginning.
     237                 :     */
     238                 :     value_type*
     239             130 :     begin() noexcept
     240                 :     {
     241             130 :         return arr_;
     242                 :     }
     243                 : 
     244                 :     /** Return an iterator to the beginning.
     245                 :     */
     246                 :     value_type const*
     247            2441 :     begin() const noexcept
     248                 :     {
     249            2441 :         return arr_;
     250                 :     }
     251                 : 
     252                 :     /** Return an iterator to the end.
     253                 :     */
     254                 :     value_type*
     255             129 :     end() noexcept
     256                 :     {
     257             129 :         return arr_ + n_;
     258                 :     }
     259                 : 
     260                 :     /** Return an iterator to the end.
     261                 :     */
     262                 :     value_type const*
     263            2441 :     end() const noexcept
     264                 :     {
     265            2441 :         return arr_ + n_;
     266                 :     }
     267                 : 
     268                 :     /** Return a span of the buffers.
     269                 :     */
     270                 :     std::span<value_type>
     271             379 :     to_span() noexcept
     272                 :     {
     273             379 :         return { arr_, n_ };
     274                 :     }
     275                 : 
     276                 :     /** Return a span of the buffers.
     277                 :     */
     278                 :     std::span<value_type const>
     279             175 :     to_span() const noexcept
     280                 :     {
     281             175 :         return { arr_, n_ };
     282                 :     }
     283                 : 
     284                 :     /** Conversion to mutable span.
     285                 :     */
     286               1 :     operator std::span<value_type>() noexcept
     287                 :     {
     288               1 :         return { arr_, n_ };
     289                 :     }
     290                 : 
     291                 :     /** Conversion to const span.
     292                 :     */
     293                 :     operator std::span<value_type const>() const noexcept
     294                 :     {
     295                 :         return { arr_, n_ };
     296                 :     }
     297                 : 
     298                 :     /** Return the total byte count in O(1).
     299                 :     */
     300                 :     std::size_t
     301                 :     byte_size() const noexcept
     302                 :     {
     303                 :         return size_;
     304                 :     }
     305                 : };
     306                 : 
     307                 : /** Alias for buffer_array holding const_buffer.
     308                 : 
     309                 :     @tparam N Maximum number of buffers.
     310                 : */
     311                 : template<std::size_t N>
     312                 : using const_buffer_array = buffer_array<N, true>;
     313                 : 
     314                 : /** Alias for buffer_array holding mutable_buffer.
     315                 : 
     316                 :     @tparam N Maximum number of buffers.
     317                 : */
     318                 : template<std::size_t N>
     319                 : using mutable_buffer_array = buffer_array<N, false>;
     320                 : 
     321                 : } // namespace detail
     322                 : } // namespace capy
     323                 : } // namespace boost
     324                 : 
     325                 : #endif
        

Generated by: LCOV version 2.3