LCOV - code coverage report
Current view: top level - boost/capy - buffers.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 84 84
Test Date: 2026-01-15 18:27:21 Functions: 100.0 % 103 103

            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_HPP
      11              : #define BOOST_CAPY_BUFFERS_HPP
      12              : 
      13              : #include <boost/capy/detail/config.hpp>
      14              : #include <concepts>
      15              : #include <cstddef>
      16              : #include <iterator>
      17              : #include <memory>
      18              : #include <ranges>
      19              : #include <type_traits>
      20              : 
      21              : // https://www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/reference/ConstBufferSequence.html
      22              : 
      23              : namespace boost {
      24              : 
      25              : namespace asio {
      26              : class const_buffer;
      27              : class mutable_buffer;
      28              : } // asio
      29              : 
      30              : namespace capy {
      31              : 
      32              : class const_buffer;
      33              : class mutable_buffer;
      34              : 
      35              : namespace detail {
      36              : 
      37              : // satisfies Asio's buffer constructors, CANNOT be removed!
      38              : template<class T, std::size_t Extent = (std::size_t)(-1)>
      39              : class basic_buffer
      40              : {
      41            4 :     constexpr auto data() const noexcept ->
      42              :         std::conditional_t<std::is_const_v<T>, void const*, void*>
      43              :     {
      44            4 :         return p_;
      45              :     }
      46              : 
      47            4 :     constexpr std::size_t size() const noexcept
      48              :     {
      49            4 :         return n_;
      50              :     }
      51              : 
      52              :     friend class capy::const_buffer;
      53              :     friend class capy::mutable_buffer;
      54              :     friend class asio::const_buffer;
      55              :     friend class asio::mutable_buffer;
      56       147647 :     basic_buffer() = default;
      57      5320836 :     constexpr basic_buffer(T* p, std::size_t n) noexcept : p_(p), n_(n) {}
      58              :     constexpr basic_buffer<T, (std::size_t)(-1)> subspan(
      59              :         std::size_t, std::size_t = (std::size_t)(-1)) const noexcept;
      60              : 
      61              :     T* p_ = nullptr;
      62              :     std::size_t n_ = 0;
      63              : };
      64              : 
      65              : } // detail
      66              : 
      67              : //------------------------------------------------
      68              : 
      69              : /** size tag for `tag_invoke`
      70              : 
      71              :     This type is used in overloads of `tag_invoke`
      72              :     for user-defined types to customize the `size()`
      73              :     algorithm.
      74              : */
      75              : struct size_tag {};
      76              : 
      77              : /** slice tag for `tag_invoke`
      78              : 
      79              :     This type is used in overloads of `tag_invoke`
      80              :     for user-defined types to customize the slicing
      81              :     algorithms.
      82              : */
      83              : struct slice_tag {};
      84              : 
      85              : /** slice constants for slice customization
      86              : 
      87              :     This defines the possible values passed to
      88              :     overloads of `tag_invoke` for user-defined
      89              :     types which customize the slicing algorithms.
      90              : */
      91              : enum class slice_how
      92              : {
      93              :     /// Indicates that the front of the buffer sequence should be trimmed
      94              :     remove_prefix,
      95              : 
      96              :     /// Indicates that the front of the buffer sequence should be preserved
      97              :     keep_prefix
      98              : };
      99              : 
     100              : //------------------------------------------------
     101              : 
     102              : /** Holds a contiguous range of modifiable bytes
     103              : */
     104              : class mutable_buffer
     105              :     : public detail::basic_buffer<unsigned char>
     106              : {
     107              : public:
     108              :     /** Constructor.
     109              :     */
     110          575 :     mutable_buffer() = default;
     111              : 
     112              :     /** Constructor.
     113              :     */
     114              :     mutable_buffer(
     115              :         mutable_buffer const&) = default;
     116              : 
     117              :     /** Assignment.
     118              :     */
     119              :     mutable_buffer& operator=(
     120              :         mutable_buffer const&) = default;
     121              : 
     122              :     /** Constructor.
     123              :     */
     124       639132 :     constexpr mutable_buffer(
     125              :         void* data, std::size_t size) noexcept
     126       639132 :         : basic_buffer<unsigned char>(
     127       639132 :             static_cast<unsigned char*>(data), size)
     128              :     {
     129       639132 :     }
     130              : 
     131              :     /** Constructor
     132              :     */
     133              :     template<class MutableBuffer>
     134              :         requires std::same_as<MutableBuffer, asio::mutable_buffer>
     135              :     constexpr mutable_buffer(
     136              :         MutableBuffer const& b) noexcept
     137              :         : basic_buffer<unsigned char>(
     138              :             static_cast<unsigned char*>(
     139              :                 b.data()), b.size())
     140              :     {
     141              :     }
     142              : 
     143              :     /** Return a pointer to the beginning of the memory region
     144              :     */
     145       800649 :     constexpr void* data() const noexcept
     146              :     {
     147       800649 :         return p_;
     148              :     }
     149              : 
     150              :     /** Return the number of valid bytes in the referenced memory region
     151              :     */
     152      2106908 :     constexpr std::size_t size() const noexcept
     153              :     {
     154      2106908 :         return n_;
     155              :     }
     156              : 
     157              :     /** Remove a prefix of the memory region
     158              : 
     159              :         If the requested number of bytes is larger than the current size,
     160              :         the resulting buffer will have size 0.
     161              : 
     162              :         @param n The number of bytes to remove.
     163              :     */
     164              :     mutable_buffer&
     165      1026737 :     operator+=(std::size_t n) noexcept
     166              :     {
     167      1026737 :         if( n > n_)
     168           16 :             n = n_;
     169      1026737 :         p_ += n;
     170      1026737 :         n_ -= n;
     171      1026737 :         return *this;
     172              :     }
     173              : 
     174              :     /** Remove a slice from the buffer
     175              :     */
     176              :     friend
     177              :     void
     178         1088 :     tag_invoke(
     179              :         slice_tag const&,
     180              :         mutable_buffer& b,
     181              :         slice_how how,
     182              :         std::size_t n) noexcept
     183              :     {
     184         1088 :         b.do_slice(how, n);
     185         1088 :     }
     186              : 
     187              : private:
     188         1088 :     void do_slice(
     189              :         slice_how how, std::size_t n) noexcept
     190              :     {
     191         1088 :         switch(how)
     192              :         {
     193          512 :         case slice_how::remove_prefix:
     194          512 :             *this += n;
     195          512 :             return;
     196              : 
     197          576 :         case slice_how::keep_prefix:
     198          576 :             if( n < n_)
     199          476 :                 n_ = n;
     200          576 :             return;
     201              :         }
     202              :     }
     203              : };
     204              : 
     205              : //------------------------------------------------
     206              : 
     207              : /** Holds a contiguous range of unmodifiable bytes
     208              : */
     209              : class const_buffer
     210              :     : public detail::basic_buffer<unsigned char const>
     211              : {
     212              : public:
     213              :     /** Constructor
     214              :     */
     215       147072 :     const_buffer() = default;
     216              : 
     217              :     /** Constructor
     218              :     */
     219              :     const_buffer(const_buffer const&) = default;
     220              : 
     221              :     /** Assignment
     222              : 
     223              :         @par Postconditions
     224              :         @code
     225              :         this->data() == other.data() && this->size() == other.size()
     226              :         @endcode
     227              :     */
     228              :     const_buffer& operator=(
     229              :         const_buffer const& other) = default;
     230              : 
     231              :     /** Constructor
     232              :     */
     233      4672750 :     constexpr const_buffer(
     234              :         void const* data, std::size_t size) noexcept
     235      4672750 :         : basic_buffer<unsigned char const>(
     236      4672750 :             static_cast<unsigned char const*>(data), size)
     237              :     {
     238      4672750 :     }
     239              : 
     240              :     /** Constructor
     241              :     */
     242         8954 :     constexpr const_buffer(
     243              :         mutable_buffer const& b) noexcept
     244         8954 :         : basic_buffer<unsigned char const>(
     245         8954 :             static_cast<unsigned char const*>(b.data()), b.size())
     246              :     {
     247         8954 :     }
     248              : 
     249              :     /** Constructor
     250              :     */
     251              :     template<class ConstBuffer>
     252              :         requires (std::same_as<ConstBuffer, asio::const_buffer> ||
     253              :                   std::same_as<ConstBuffer, asio::mutable_buffer>)
     254              :     constexpr const_buffer(
     255              :         ConstBuffer const& b) noexcept
     256              :         : basic_buffer<unsigned char const>(
     257              :             static_cast<unsigned char const*>(
     258              :                 b.data()), b.size())
     259              :     {
     260              :     }
     261              : 
     262              :     /** Return a pointer to the beginning of the memory region
     263              :     */
     264     13069677 :     constexpr void const* data() const noexcept
     265              :     {
     266     13069677 :         return p_;
     267              :     }
     268              : 
     269              :     /** Return the number of valid bytes in the referenced memory region
     270              :     */
     271     18416594 :     constexpr std::size_t size() const noexcept
     272              :     {
     273     18416594 :         return n_;
     274              :     }
     275              : 
     276              :     /** Remove a prefix of the memory region
     277              : 
     278              :         If the requested number of bytes is larger than the current size,
     279              :         the resulting buffer will have size 0.
     280              : 
     281              :         @param n The number of bytes to remove.
     282              :     */
     283              :     const_buffer&
     284      1157878 :     operator+=(std::size_t n) noexcept
     285              :     {
     286      1157878 :         if( n > n_)
     287         4112 :             n = n_;
     288      1157878 :         p_ += n;
     289      1157878 :         n_ -= n;
     290      1157878 :         return *this;
     291              :     }
     292              : 
     293              :     /** Remove a slice from the buffer
     294              :     */
     295              :     friend
     296              :     void
     297       267349 :     tag_invoke(
     298              :         slice_tag const&,
     299              :         const_buffer& b,
     300              :         slice_how how,
     301              :         std::size_t n) noexcept
     302              :     {
     303       267349 :         b.do_slice(how, n);
     304       267349 :     }
     305              : 
     306              : private:
     307       267349 :     void do_slice(
     308              :         slice_how how, std::size_t n) noexcept
     309              :     {
     310       267349 :         switch(how)
     311              :         {
     312       131653 :         case slice_how::remove_prefix:
     313       131653 :             *this += n;
     314       131653 :             return;
     315              : 
     316       135696 :         case slice_how::keep_prefix:
     317       135696 :             if( n < n_)
     318       121169 :                 n_ = n;
     319       135696 :             return;
     320              :         }
     321              :     }
     322              : };
     323              : 
     324              : //------------------------------------------------
     325              : 
     326              : /** Concept for types that model ConstBufferSequence.
     327              : 
     328              :     A type satisfies `const_buffer_sequence` if it is convertible
     329              :     to `const_buffer`, or if it is a bidirectional range whose
     330              :     value type is convertible to `const_buffer`.
     331              : */
     332              : template<typename T>
     333              : concept const_buffer_sequence =
     334              :     std::is_convertible_v<T, const_buffer> || (
     335              :         std::ranges::bidirectional_range<T> &&
     336              :         std::is_convertible_v<std::ranges::range_value_t<T>, const_buffer>);
     337              : 
     338              : /** Concept for types that model MutableBufferSequence.
     339              : 
     340              :     A type satisfies `mutable_buffer_sequence` if it is convertible
     341              :     to `mutable_buffer`, or if it is a bidirectional range whose
     342              :     value type is convertible to `mutable_buffer`.
     343              : */
     344              : template<typename T>
     345              : concept mutable_buffer_sequence =
     346              :     std::is_convertible_v<T, mutable_buffer> || (
     347              :         std::ranges::bidirectional_range<T> &&
     348              :         std::is_convertible_v<std::ranges::range_value_t<T>, mutable_buffer>);
     349              : 
     350              : //------------------------------------------------------------------------------
     351              : 
     352              : /** Return an iterator pointing to the first element of a buffer sequence
     353              : 
     354              :     This function returns an iterator to the beginning of the range denoted by
     355              :     `t`. It handles both ranges and single buffers uniformly.
     356              : 
     357              :     @par Constraints
     358              :     @code
     359              :     const_buffer_sequence<T>
     360              :     @endcode
     361              : 
     362              :     @param t The buffer sequence
     363              : */
     364              : constexpr struct begin_mrdocs_workaround_t
     365              : {
     366              :     template<std::convertible_to<const_buffer> ConvertibleToBuffer>
     367       593313 :     auto operator()(ConvertibleToBuffer const& b) const noexcept -> ConvertibleToBuffer const*
     368              :     {
     369       593313 :         return std::addressof(b);
     370              :     }
     371              : 
     372              :     template<const_buffer_sequence BufferSequence>
     373              :         requires (!std::convertible_to<BufferSequence, const_buffer>)
     374     11093944 :     auto operator()(BufferSequence const& bs) const noexcept
     375              :     {
     376     11093944 :         return std::ranges::begin(bs);
     377              :     }
     378              : 
     379              :     template<const_buffer_sequence BufferSequence>
     380              :         requires (!std::convertible_to<BufferSequence, const_buffer>)
     381      2549260 :     auto operator()(BufferSequence& bs) const noexcept
     382              :     {
     383      2549260 :         return std::ranges::begin(bs);
     384              :     }
     385              : } begin {};
     386              : 
     387              : //------------------------------------------------------------------------------
     388              : 
     389              : /** Return an iterator to the end of the buffer sequence
     390              : 
     391              :     This function returns an iterator to the end of the range denoted by
     392              :     `t`. It handles both ranges and single buffers uniformly.
     393              : 
     394              :     @par Constraints
     395              :     @code
     396              :     const_buffer_sequence<T>
     397              :     @endcode
     398              : 
     399              :     @param t The buffer sequence
     400              : */
     401              : constexpr struct end_mrdocs_workaround_t
     402              : {
     403              :     template<std::convertible_to<const_buffer> ConvertibleToBuffer>
     404       593313 :     auto operator()(ConvertibleToBuffer const& b) const noexcept -> ConvertibleToBuffer const*
     405              :     {
     406       593313 :         return std::addressof(b) + 1;
     407              :     }
     408              : 
     409              :     template<const_buffer_sequence BufferSequence>
     410              :         requires (!std::convertible_to<BufferSequence, const_buffer>)
     411      4319874 :     auto operator()(BufferSequence const& bs) const noexcept
     412              :     {
     413      4319874 :         return std::ranges::end(bs);
     414              :     }
     415              : 
     416              :     template<const_buffer_sequence BufferSequence>
     417              :         requires (!std::convertible_to<BufferSequence, const_buffer>)
     418      2549260 :     auto operator()(BufferSequence& bs) const noexcept
     419              :     {
     420      2549260 :         return std::ranges::end(bs);
     421              :     }
     422              : } end {};
     423              : 
     424              : //------------------------------------------------------------------------------
     425              : 
     426              : template<const_buffer_sequence ConstBufferSequence>
     427              : std::size_t
     428      1407618 : tag_invoke(
     429              :     size_tag const&,
     430              :     ConstBufferSequence const& bs) noexcept
     431              : {
     432      1407618 :     std::size_t n = 0;
     433      1407618 :     auto const e = end(bs);
     434      3888384 :     for(auto it = begin(bs); it != e; ++it)
     435      2480766 :         n += const_buffer(*it).size();
     436      1407618 :     return n;
     437              : }
     438              : 
     439              : //------------------------------------------------------------------------------
     440              : 
     441              : /** Return the total number of bytes in a buffer sequence
     442              : 
     443              :     This function returns the sum of the number of bytes in each contiguous
     444              :     buffer contained in the range or value. This is different from the length
     445              :     of the sequence returned by `std::ranges::size(t)`
     446              : 
     447              :     @par Constraints
     448              :     @code
     449              :     const_buffer_sequence<T>
     450              :     @endcode
     451              : 
     452              :     @par Example
     453              :     @code
     454              :     template<const_buffer_sequence ConstBufferSequence>
     455              :     bool is_small( ConstBufferSequence const& bs ) noexcept
     456              :     {
     457              :         return buffer_size(bs) < 100;
     458              :     }
     459              :     @endcode
     460              : */
     461              : constexpr struct buffer_size_mrdocs_workaround_t
     462              : {
     463              :     template<const_buffer_sequence ConstBufferSequence>
     464      1407618 :     constexpr std::size_t operator()(
     465              :         ConstBufferSequence const& bs) const noexcept
     466              :     {
     467      1407618 :         return tag_invoke(size_tag{}, bs);
     468              :     }
     469              : } buffer_size {};
     470              : 
     471              : //-----------------------------------------------
     472              : 
     473              : namespace detail {
     474              : 
     475              : template<class It>
     476              : auto
     477              : length_impl(It first, It last, int)
     478              :     -> decltype(static_cast<std::size_t>(last - first))
     479              : {
     480              :     return static_cast<std::size_t>(last - first);
     481              : }
     482              : 
     483              : template<class It>
     484              : std::size_t
     485              : length_impl(It first, It last, long)
     486              : {
     487              :     std::size_t n = 0;
     488              :     while(first != last)
     489              :     {
     490              :         ++first;
     491              :         ++n;
     492              :     }
     493              :     return n;
     494              : }
     495              : 
     496              : } // detail
     497              : 
     498              : /** Return the number of elements in a buffer sequence.
     499              : */
     500              : template<const_buffer_sequence ConstBufferSequence>
     501              : std::size_t
     502              : buffer_length(ConstBufferSequence const& bs)
     503              : {
     504              :     return detail::length_impl(
     505              :         begin(bs), end(bs), 0);
     506              : }
     507              : 
     508              : /** Alias for const_buffer or mutable_buffer depending on sequence type.
     509              : */
     510              : template<typename BufferSequence>
     511              : using buffer_type = std::conditional_t<
     512              :     mutable_buffer_sequence<BufferSequence>,
     513              :     mutable_buffer, const_buffer>;
     514              : 
     515              : } // capy
     516              : } // boost
     517              : 
     518              : #endif
        

Generated by: LCOV version 2.3