Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot 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_PARAM_HPP
11 : #define BOOST_CAPY_BUFFERS_BUFFER_PARAM_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <boost/capy/buffers.hpp>
15 :
16 : #include <cstddef>
17 :
18 : namespace boost {
19 : namespace capy {
20 :
21 : /** A type-erased buffer sequence I/O parameter.
22 :
23 : This class provides a type-erased interface for iterating
24 : over buffer sequences without knowing the concrete type.
25 : It allows asynchronous operations to efficiently type-erase
26 : the buffer sequence parameter, avoiding the need to
27 : templatize the implementation.
28 :
29 : @par Passing Convention
30 :
31 : This type is designed to be passed by value. It contains only
32 : two pointers (16 bytes on 64-bit systems), making copies trivial.
33 : Pass-by-value is preferred as it clearly communicates the
34 : lightweight, transient nature of this parameter type:
35 :
36 : @code
37 : // Preferred: pass by value
38 : void process_buffers( buffer_param buffers );
39 :
40 : // Also acceptable: pass by const reference
41 : void process_buffers( buffer_param const& buffers );
42 : @endcode
43 :
44 : @par Example
45 :
46 : The following shows the minimal form of an awaitable, templated on the
47 : buffer sequence type, with only an `await_suspend` method. The example
48 : demonstrates that you can pass buffers directly to a virtual interface
49 : through implicit conversion.
50 :
51 : @code
52 : template<class Buffers>
53 : struct awaitable
54 : {
55 : Buffers b;
56 :
57 : void await_suspend( std::coroutine_handle<> )
58 : {
59 : my_virtual_engine_submit( b );
60 : }
61 : };
62 :
63 : // Example virtual interface accepting buffer_param by value
64 : void my_virtual_engine_submit( buffer_param p )
65 : {
66 : capy::mutable_buffer temp[8];
67 : std::size_t n = p.copy_to( temp, 8 );
68 : // ... handle the buffers ...
69 : }
70 : @endcode
71 : */
72 : class buffer_param
73 : {
74 : public:
75 : /** Construct from a const buffer sequence.
76 :
77 : @param bs The buffer sequence to adapt.
78 : */
79 : template<ConstBufferSequence BS>
80 23 : buffer_param(BS const& bs) noexcept
81 23 : : bs_(&bs)
82 23 : , fn_(©_impl<BS>)
83 : {
84 23 : }
85 :
86 : /** Fill an array with buffers from the sequence.
87 :
88 : Copies buffer descriptors from the sequence into the
89 : destination array. If the total number of bytes across
90 : all copied buffers is zero, returns 0 regardless of
91 : how many buffer descriptors were copied.
92 :
93 : @param dest Pointer to array of mutable buffer descriptors.
94 : @param n Maximum number of buffers to copy.
95 :
96 : @return The number of buffers actually copied, or 0 if
97 : the total byte count is zero.
98 : */
99 : std::size_t
100 23 : copy_to(
101 : mutable_buffer* dest,
102 : std::size_t n) const noexcept
103 : {
104 23 : return fn_(bs_, dest, n);
105 : }
106 :
107 : private:
108 : template<ConstBufferSequence BS>
109 : static std::size_t
110 23 : copy_impl(
111 : void const* p,
112 : mutable_buffer* dest,
113 : std::size_t n)
114 : {
115 23 : auto const& bs = *static_cast<BS const*>(p);
116 23 : auto it = begin(bs);
117 23 : auto const end_it = end(bs);
118 :
119 23 : std::size_t i = 0;
120 23 : std::size_t bytes = 0;
121 : if constexpr (MutableBufferSequence<BS>)
122 : {
123 10 : for(; it != end_it && i < n; ++it, ++i)
124 : {
125 6 : dest[i] = *it;
126 6 : bytes += dest[i].size();
127 : }
128 : }
129 : else
130 : {
131 52 : for(; it != end_it && i < n; ++it, ++i)
132 : {
133 33 : auto const& buf = *it;
134 66 : dest[i] = mutable_buffer(
135 : const_cast<char*>(
136 33 : static_cast<char const*>(buf.data())),
137 : buf.size());
138 33 : bytes += buf.size();
139 : }
140 : }
141 : // Return 0 if total bytes is 0 (empty buffer sequence)
142 23 : return bytes == 0 ? 0 : i;
143 : }
144 :
145 : using fn_t = std::size_t(*)(void const*,
146 : mutable_buffer*, std::size_t);
147 :
148 : void const* bs_;
149 : fn_t fn_;
150 : };
151 :
152 : } // namespace capy
153 : } // namespace boost
154 :
155 : #endif
|