LCOV - code coverage report
Current view: top level - capy/asio - buffers.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 100.0 % 29 29
Test Date: 2026-05-01 02:54:45 Functions: 96.7 % 30 29 1

           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_ASIO_BUFFERS_HPP
      11                 : #define BOOST_CAPY_ASIO_BUFFERS_HPP
      12                 : 
      13                 : #include <boost/capy/buffers.hpp>
      14                 : #include <array>
      15                 : #include <concepts>
      16                 : #include <utility>
      17                 : 
      18                 : namespace asio 
      19                 : {
      20                 : 
      21                 : class mutable_buffer; 
      22                 : class const_buffer; 
      23                 : 
      24                 : }
      25                 : 
      26                 : namespace boost::asio 
      27                 : {
      28                 : 
      29                 : class mutable_buffer; 
      30                 : class const_buffer; 
      31                 : 
      32                 : }
      33                 : 
      34                 : namespace boost::capy
      35                 : {
      36                 : 
      37                 : /** A const buffer type compatible with both capy and Asio.
      38                 : 
      39                 :     Extends capy's `const_buffer` with implicit conversion operators
      40                 :     to both standalone Asio (`::asio::const_buffer`) and Boost.Asio
      41                 :     (`boost::asio::const_buffer`) buffer types.
      42                 : 
      43                 :     This allows seamless use of capy buffers with Asio I/O operations
      44                 :     without explicit conversion.
      45                 : 
      46                 :     @par Example
      47                 :     @code
      48                 :     capy::asio_const_buffer buf(data, size);
      49                 : 
      50                 :     // Works directly with Asio operations
      51                 :     co_await socket.async_write_some(buf, capy::as_io_awaitable);
      52                 :     @endcode
      53                 : 
      54                 :     @see asio_mutable_buffer, as_asio_buffer_sequence
      55                 : */
      56                 : struct asio_const_buffer : const_buffer
      57                 : {
      58                 :     using const_buffer::const_buffer;
      59                 :     using const_buffer::operator=;
      60                 : 
      61                 :     /// Construct from a capy const_buffer.
      62 HIT           2 :     asio_const_buffer(const_buffer cb) : const_buffer(cb) {}
      63                 : 
      64                 :     /// Convert to standalone Asio const_buffer.
      65                 :     inline
      66                 :     operator ::asio::const_buffer() const;
      67                 : 
      68                 :     /// Convert to Boost.Asio const_buffer.
      69                 :     inline
      70                 :     operator boost::asio::const_buffer() const;
      71                 : };
      72                 : 
      73                 : /** A mutable buffer type compatible with both capy and Asio.
      74                 : 
      75                 :     Extends capy's `mutable_buffer` with implicit conversion operators
      76                 :     to both standalone Asio and Boost.Asio buffer types. Supports
      77                 :     conversion to both mutable and const buffer types.
      78                 : 
      79                 :     This allows seamless use of capy buffers with Asio I/O operations
      80                 :     without explicit conversion.
      81                 : 
      82                 :     @par Example
      83                 :     @code
      84                 :     char data[1024];
      85                 :     capy::asio_mutable_buffer buf(data, sizeof(data));
      86                 : 
      87                 :     // Works directly with Asio read operations
      88                 :     auto [ec, n] = co_await socket.async_read_some(buf, capy::as_io_awaitable);
      89                 :     @endcode
      90                 : 
      91                 :     @see asio_const_buffer, as_asio_buffer_sequence
      92                 : */
      93                 : struct asio_mutable_buffer : mutable_buffer
      94                 : {
      95                 :     using mutable_buffer::mutable_buffer;
      96                 :     using mutable_buffer::operator=;
      97                 : 
      98                 :     /// Construct from a capy mutable_buffer.
      99               2 :     asio_mutable_buffer(mutable_buffer mb) : mutable_buffer(mb) {}
     100                 : 
     101                 :     /// Convert to standalone Asio mutable_buffer.
     102                 :     inline
     103                 :     operator ::asio::mutable_buffer() const;
     104                 : 
     105                 :     /// Convert to Boost.Asio mutable_buffer.
     106                 :     inline
     107                 :     operator boost::asio::mutable_buffer() const;
     108                 : 
     109                 :     /// Convert to standalone Asio const_buffer.
     110                 :     inline
     111                 :     operator ::asio::const_buffer() const;
     112                 : 
     113                 :     /// Convert to Boost.Asio const_buffer.
     114                 :     inline
     115                 :     operator boost::asio::const_buffer() const;
     116                 : };
     117                 : 
     118                 : 
     119                 : namespace detail
     120                 : {
     121                 : 
     122                 : struct asio_buffer_transformer_t
     123                 : {
     124                 :   inline
     125                 :   asio_mutable_buffer operator()(const boost::asio::mutable_buffer &mb) const noexcept;
     126                 : 
     127                 :   inline
     128                 :   asio_const_buffer operator()(const boost::asio::const_buffer &cb) const noexcept;
     129                 : 
     130                 :   inline
     131                 :   asio_mutable_buffer operator()(const ::asio::mutable_buffer &mb) const noexcept;
     132                 : 
     133                 :   inline
     134                 :   asio_const_buffer operator()(const ::asio::const_buffer &cb) const noexcept;
     135                 : 
     136                 : 
     137               2 :   asio_mutable_buffer operator()(const mutable_buffer &mb) const noexcept
     138                 :   {
     139               2 :     return mb;
     140                 :   }
     141                 : 
     142               2 :   asio_const_buffer operator()(const const_buffer &cb) const noexcept
     143                 :   {
     144               2 :     return cb;
     145                 :   }
     146                 : 
     147                 :   asio_buffer_transformer_t() noexcept = default;
     148                 :   asio_buffer_transformer_t(const asio_buffer_transformer_t &) noexcept = default;
     149                 : };
     150                 : 
     151                 : constexpr static asio_buffer_transformer_t asio_buffer_transformer;
     152                 : 
     153                 : /** A bidirectional iterator that transforms buffer types using asio_buffer_transformer.
     154                 :  *
     155                 :  *  Wraps an underlying bidirectional iterator and applies asio_buffer_transformer
     156                 :  *  to each dereferenced value, converting between Asio buffer types and capy
     157                 :  *  asio_const_buffer/asio_mutable_buffer types.
     158                 :  *
     159                 :  *  @tparam Iterator The underlying bidirectional iterator type
     160                 :  */
     161                 : template<typename Iterator>
     162                 : class asio_buffer_iterator
     163                 : {
     164                 : public:
     165                 :     using iterator_type     = Iterator;
     166                 :     using iterator_category = std::bidirectional_iterator_tag;
     167                 :     using difference_type   = typename std::iterator_traits<Iterator>::difference_type;
     168                 :     using underlying_value  = typename std::iterator_traits<Iterator>::value_type;
     169                 :     using value_type        = decltype(asio_buffer_transformer(std::declval<underlying_value>()));
     170                 :     using reference         = value_type;
     171                 :     using pointer           = void;
     172                 : 
     173                 :     asio_buffer_iterator() = default;
     174                 : 
     175              20 :     explicit asio_buffer_iterator(Iterator it)
     176                 :         noexcept(std::is_nothrow_move_constructible_v<Iterator>)
     177              20 :         : it_(std::move(it))
     178                 :     {
     179              20 :     }
     180                 : 
     181                 :     asio_buffer_iterator(const asio_buffer_iterator&) = default;
     182                 :     asio_buffer_iterator(asio_buffer_iterator&&) = default;
     183                 :     asio_buffer_iterator& operator=(const asio_buffer_iterator&) = default;
     184                 :     asio_buffer_iterator& operator=(asio_buffer_iterator&&) = default;
     185                 : 
     186              10 :     reference operator*() const
     187                 :         noexcept(noexcept(asio_buffer_transformer(*std::declval<Iterator>())))
     188                 :     {
     189              10 :         return asio_buffer_transformer(*it_);
     190                 :     }
     191                 : 
     192               4 :     asio_buffer_iterator& operator++()
     193                 :         noexcept(noexcept(++std::declval<Iterator&>()))
     194                 :     {
     195               4 :         ++it_;
     196               4 :         return *this;
     197                 :     }
     198                 : 
     199               3 :     asio_buffer_iterator operator++(int)
     200                 :         noexcept(noexcept(std::declval<Iterator&>()++))
     201                 :     {
     202               3 :         asio_buffer_iterator tmp(*this);
     203               3 :         ++it_;
     204               3 :         return tmp;
     205                 :     }
     206                 : 
     207                 :     asio_buffer_iterator& operator--()
     208                 :         noexcept(noexcept(--std::declval<Iterator&>()))
     209                 :     {
     210                 :         --it_;
     211                 :         return *this;
     212                 :     }
     213                 : 
     214                 :     asio_buffer_iterator operator--(int)
     215                 :         noexcept(noexcept(std::declval<Iterator&>()--))
     216                 :     {
     217                 :         asio_buffer_iterator tmp(*this);
     218                 :         --it_;
     219                 :         return tmp;
     220                 :     }
     221                 : 
     222                 :     bool operator==(const asio_buffer_iterator& other) const
     223                 :         noexcept(noexcept(std::declval<Iterator>() == std::declval<Iterator>()))
     224                 :     {
     225                 :         return it_ == other.it_;
     226                 :     }
     227                 : 
     228              13 :     bool operator!=(const asio_buffer_iterator& other) const
     229                 :         noexcept(noexcept(std::declval<Iterator>() != std::declval<Iterator>()))
     230                 :     {
     231              13 :         return it_ != other.it_;
     232                 :     }
     233                 : 
     234                 :     /// Returns the underlying iterator.
     235                 :     Iterator base() const noexcept(std::is_nothrow_copy_constructible_v<Iterator>)
     236                 :     {
     237                 :         return it_;
     238                 :     }
     239                 : 
     240                 : private:
     241                 :     Iterator it_{};
     242                 : };
     243                 : 
     244                 : // Deduction guide
     245                 : template<typename Iterator>
     246                 : asio_buffer_iterator(Iterator) -> asio_buffer_iterator<Iterator>;
     247                 : 
     248                 : 
     249                 : /** A bidirectional range that transforms buffer sequences using asio_buffer_transformer.
     250                 :  *
     251                 :  *  Wraps a buffer sequence and provides begin/end iterators that transform
     252                 :  *  buffer elements via asio_buffer_transformer. Satisfies the requirements
     253                 :  *  of std::ranges::bidirectional_range.
     254                 :  *
     255                 :  *  @tparam Sequence The underlying buffer sequence type
     256                 :  */
     257                 : template<typename Sequence>
     258                 : class asio_buffer_range
     259                 : {
     260                 : public:
     261                 :     using sequence_type = Sequence;
     262                 :     using iterator      = asio_buffer_iterator<
     263                 :                             decltype(std::ranges::begin(std::declval<const Sequence&>()))>;
     264                 :     using const_iterator = iterator;
     265                 : 
     266                 :     asio_buffer_range() = default;
     267                 : 
     268               2 :     explicit asio_buffer_range(Sequence seq)
     269                 :         noexcept(std::is_nothrow_move_constructible_v<Sequence>)
     270               2 :         : seq_(std::move(seq))
     271                 :     {
     272               2 :     }
     273                 : 
     274                 :     asio_buffer_range(const asio_buffer_range&) = default;
     275                 :     asio_buffer_range(asio_buffer_range&&) = default;
     276                 :     asio_buffer_range& operator=(const asio_buffer_range&) = default;
     277                 :     asio_buffer_range& operator=(asio_buffer_range&&) = default;
     278                 : 
     279               4 :     iterator begin() const
     280                 :         noexcept(noexcept(std::ranges::begin(std::declval<const Sequence&>())))
     281                 :     {
     282               4 :         return iterator(std::ranges::begin(seq_));
     283                 :     }
     284                 : 
     285               4 :     iterator end() const
     286                 :         noexcept(noexcept(std::ranges::end(std::declval<const Sequence&>())))
     287                 :     {
     288               4 :         return iterator(std::ranges::end(seq_));
     289                 :     }
     290                 : 
     291                 :     /// Returns true if the range is empty.
     292                 :     bool empty() const
     293                 :         noexcept(noexcept(std::ranges::empty(std::declval<const Sequence&>())))
     294                 :     {
     295                 :         return std::ranges::empty(seq_);
     296                 :     }
     297                 : 
     298                 :     /// Returns the underlying sequence.
     299                 :     const Sequence& base() const noexcept { return seq_; }
     300                 : 
     301                 : private:
     302                 :     Sequence seq_{};
     303                 : };
     304                 : 
     305                 : // Deduction guide
     306                 : template<typename Sequence>
     307                 : asio_buffer_range(Sequence) -> asio_buffer_range<Sequence>;
     308                 : 
     309                 : }
     310                 : 
     311                 : 
     312                 : /** @defgroup as_asio_buffer_sequence as_asio_buffer_sequence
     313                 : 
     314                 :     Bidirectional conversion between Asio and capy buffer sequences.
     315                 : 
     316                 :     The `as_asio_buffer_sequence` function provides seamless conversion
     317                 :     in both directions:
     318                 : 
     319                 :     - **Capy to Asio**: Convert capy buffer sequences for use with Asio
     320                 :       I/O operations. The returned range satisfies Asio's
     321                 :       `MutableBufferSequence` or `ConstBufferSequence` requirements.
     322                 : 
     323                 :     - **Asio to Capy**: Convert Asio buffer sequences for use with capy's
     324                 :       buffer concepts. The returned range satisfies capy's
     325                 :       `MutableBufferSequence` or `ConstBufferSequence` concepts.
     326                 : 
     327                 :     @par Example: Capy to Asio
     328                 :     @code
     329                 :     capy::mutable_buffer_pair buffers = ...;
     330                 :     auto seq = capy::as_asio_buffer_sequence(buffers);
     331                 :     co_await socket.async_read_some(seq, capy::as_io_awaitable);
     332                 :     @endcode
     333                 : 
     334                 :     @par Example: Asio to Capy
     335                 :     @code
     336                 :     std::vector<boost::asio::mutable_buffer> asio_bufs = ...;
     337                 :     auto seq = capy::as_asio_buffer_sequence(asio_bufs);
     338                 :     std::size_t total = capy::buffer_size(seq);  // Use capy algorithms
     339                 :     @endcode
     340                 : 
     341                 :     @{
     342                 : */
     343                 : 
     344                 : /** Pass through a range already containing asio_const_buffer elements.
     345                 : 
     346                 :     @param rng A bidirectional range of asio_const_buffer
     347                 :     @return The range forwarded unchanged
     348                 : */
     349                 : template<std::ranges::bidirectional_range<> Range>
     350                 :     requires std::same_as<std::ranges::range_value_t<Range>, asio_const_buffer>
     351                 : auto as_asio_buffer_sequence(Range && rng)
     352                 : {
     353                 :     return std::forward<Range>(rng);
     354                 : }
     355                 : 
     356                 : /** Pass through a range already containing asio_mutable_buffer elements.
     357                 : 
     358                 :     @param rng A bidirectional range of asio_mutable_buffer
     359                 :     @return The range forwarded unchanged
     360                 : */
     361                 : template<std::ranges::bidirectional_range<> Range>
     362                 :     requires std::same_as<std::ranges::range_value_t<Range>, asio_mutable_buffer>
     363                 : auto as_asio_buffer_sequence(Range && rng)
     364                 : {
     365                 :     return std::forward<Range>(rng);
     366                 : }
     367                 : 
     368                 : /** Convert a single asio_mutable_buffer to a buffer sequence.
     369                 : 
     370                 :     @param mb The mutable buffer
     371                 :     @return A single-element array containing the buffer
     372                 : */
     373                 : inline
     374                 : auto as_asio_buffer_sequence(asio_mutable_buffer mb)
     375                 : {
     376                 :     return std::array<asio_mutable_buffer, 1u>{mb};
     377                 : }
     378                 : 
     379                 : /** Convert a single asio_const_buffer to a buffer sequence.
     380                 : 
     381                 :     @param cb The const buffer
     382                 :     @return A single-element array containing the buffer
     383                 : */
     384                 : inline
     385                 : auto as_asio_buffer_sequence(asio_const_buffer cb)
     386                 : {
     387                 :     return std::array<asio_const_buffer, 1u>{cb};
     388                 : }
     389                 : 
     390                 : /** Convert a single capy mutable_buffer to a buffer sequence.
     391                 : 
     392                 :     @param mb The mutable buffer
     393                 :     @return A single-element array containing an asio_mutable_buffer
     394                 : */
     395                 : inline
     396                 : auto as_asio_buffer_sequence(mutable_buffer mb)
     397                 : {
     398                 :     return std::array<asio_mutable_buffer, 1u>{mb};
     399                 : }
     400                 : 
     401                 : /** Convert a buffer type that might support both mutable & const buffer
     402                 :     to an asio buffer sequence.
     403                 : 
     404                 :     @param buf The const buffer
     405                 :     @return A single-element array containing an asio_mutable_buffer
     406                 : 
     407                 : */
     408                 : template<std::convertible_to<mutable_buffer> Buffer>
     409                 : inline
     410                 : auto as_asio_buffer_sequence(const Buffer & buf)
     411                 : {
     412                 :     return as_asio_buffer_sequence(static_cast<mutable_buffer>(buf));
     413                 : }
     414                 : 
     415                 : /** Convert a single capy const_buffer to a buffer sequence.
     416                 :     @param cb The const buffer
     417                 :     @return A single-element array containing an asio_const_buffer
     418                 : 
     419                 : */
     420                 : inline
     421                 : auto as_asio_buffer_sequence(const_buffer cb)
     422                 : {
     423                 :     return std::array<asio_const_buffer, 1u>{cb};
     424                 : }
     425                 : 
     426                 : /** Convert any buffer sequence for bidirectional Asio/capy compatibility.
     427                 : 
     428                 :     Wraps the buffer sequence in a transforming range that converts
     429                 :     each buffer element to asio_const_buffer or asio_mutable_buffer.
     430                 :     The returned range satisfies both Asio's buffer sequence requirements
     431                 :     and capy's buffer sequence concepts.
     432                 : 
     433                 :     This overload handles:
     434                 :     - Capy buffer sequences (for use with Asio operations)
     435                 :     - Asio buffer sequences (for use with capy concepts/algorithms)
     436                 : 
     437                 :     @param seq The buffer sequence to convert
     438                 :     @return A transforming range over the buffer sequence
     439                 : */
     440                 : template<ConstBufferSequence Seq>
     441                 :   requires (!std::convertible_to<Seq, const_buffer> && !std::convertible_to<Seq, mutable_buffer>)
     442                 : inline
     443               2 : auto as_asio_buffer_sequence(const Seq & seq)
     444                 : {
     445               2 :     return detail::asio_buffer_range(seq);
     446                 : }
     447                 : 
     448                 : /** @} */
     449                 : 
     450                 : }
     451                 : 
     452                 : 
     453                 : #endif // BOOST_CAPY_ASIO_BUFFERS_HPP
     454                 : 
        

Generated by: LCOV version 2.3