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_ANY_BUFREF_HPP
11 : #define BOOST_CAPY_ANY_BUFREF_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 Example
30 : The following shows the minimal form of an awaitable, templated on the
31 : buffer sequence type, with only an `await_suspend` method. The example
32 : demonstrates that you can construct an `any_bufref` in the parameter
33 : list when calling a virtual interface; there is no need to create a
34 : separate variable if not desired.
35 :
36 : @code
37 : template<class Buffers>
38 : struct awaitable
39 : {
40 : Buffers b;
41 :
42 : void await_suspend( std::coroutine_handle<> )
43 : {
44 : my_virtual_engine_submit( any_bufref( b ) );
45 : }
46 : };
47 :
48 : // Example virtual interface accepting any_bufref
49 : void my_virtual_engine_submit( any_bufref p )
50 : {
51 : capy::mutable_buffer temp[8];
52 : std::size_t n = p.copy_to( temp, 8 );
53 : // ... handle the buffers ...
54 : }
55 : @endcode
56 : */
57 : class any_bufref
58 : {
59 : public:
60 : /** Construct from a const buffer sequence.
61 :
62 : @param bs The buffer sequence to adapt.
63 : */
64 : template<ConstBufferSequence BS>
65 : explicit
66 18 : any_bufref(BS const& bs) noexcept
67 18 : : bs_(&bs)
68 18 : , fn_(©_impl<BS>)
69 : {
70 18 : }
71 :
72 : /** Fill an array with buffers from the sequence.
73 :
74 : Copies buffer descriptors from the sequence into the
75 : destination array. If the total number of bytes across
76 : all copied buffers is zero, returns 0 regardless of
77 : how many buffer descriptors were copied.
78 :
79 : @param dest Pointer to array of mutable buffer descriptors.
80 : @param n Maximum number of buffers to copy.
81 :
82 : @return The number of buffers actually copied, or 0 if
83 : the total byte count is zero.
84 : */
85 : std::size_t
86 18 : copy_to(
87 : mutable_buffer* dest,
88 : std::size_t n) const noexcept
89 : {
90 18 : return fn_(bs_, dest, n);
91 : }
92 :
93 : private:
94 : template<ConstBufferSequence BS>
95 : static std::size_t
96 18 : copy_impl(
97 : void const* p,
98 : mutable_buffer* dest,
99 : std::size_t n)
100 : {
101 18 : auto const& bs = *static_cast<BS const*>(p);
102 18 : auto it = begin(bs);
103 18 : auto const end_it = end(bs);
104 :
105 18 : std::size_t i = 0;
106 18 : std::size_t bytes = 0;
107 : if constexpr (MutableBufferSequence<BS>)
108 : {
109 10 : for(; it != end_it && i < n; ++it, ++i)
110 : {
111 6 : dest[i] = *it;
112 6 : bytes += dest[i].size();
113 : }
114 : }
115 : else
116 : {
117 40 : for(; it != end_it && i < n; ++it, ++i)
118 : {
119 26 : auto const& buf = *it;
120 52 : dest[i] = mutable_buffer(
121 : const_cast<char*>(
122 26 : static_cast<char const*>(buf.data())),
123 : buf.size());
124 26 : bytes += buf.size();
125 : }
126 : }
127 : // Return 0 if total bytes is 0 (empty buffer sequence)
128 18 : return bytes == 0 ? 0 : i;
129 : }
130 :
131 : using fn_t = std::size_t(*)(void const*,
132 : mutable_buffer*, std::size_t);
133 :
134 : void const* bs_;
135 : fn_t fn_;
136 : };
137 :
138 : } // namespace capy
139 : } // namespace boost
140 :
141 : #endif
|