include/boost/corosio/native/native_win_random_access_handle.hpp

100.0% Lines (16 / 16) 100.0% Branches (3 / 3) 100.0% Functions (5 / 5)
native_win_random_access_handle.hpp
f(x) Functions (5)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Michael Vandeberg
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/corosio
8 //
9
10 #ifndef BOOST_COROSIO_NATIVE_NATIVE_WIN_RANDOM_ACCESS_HANDLE_HPP
11 #define BOOST_COROSIO_NATIVE_NATIVE_WIN_RANDOM_ACCESS_HANDLE_HPP
12
13 #include <boost/corosio/detail/op_base.hpp>
14 #include <boost/corosio/win_random_access_handle.hpp>
15 #include <boost/corosio/backend.hpp>
16
17 #if BOOST_COROSIO_HAS_IOCP || defined(BOOST_COROSIO_MRDOCS)
18
19 #ifndef BOOST_COROSIO_MRDOCS
20 #include <boost/corosio/native/detail/iocp/win_random_access_handle_service.hpp>
21 #endif
22
23 namespace boost::corosio {
24
25 /** Drives an already-open overlapped handle at arbitrary offsets, calling the backend directly.
26
27 This class template inherits from @ref win_random_access_handle
28 and shadows `read_some_at` / `write_some_at` with versions that
29 call the backend implementation directly. The compiler can then
30 inline through the entire call chain.
31
32 Non-async operations (`assign`, `release`, `close`, `cancel`)
33 remain unchanged and dispatch through the compiled library.
34
35 A `native_win_random_access_handle` IS-A
36 `win_random_access_handle` and can be passed to any function
37 expecting `win_random_access_handle&`, in which case virtual
38 dispatch is used transparently.
39
40 @tparam Backend A backend tag value (e.g., `iocp`) whose type
41 provides the concrete implementation types.
42
43 @par Thread Safety
44 Same as @ref win_random_access_handle.
45
46 @par Example
47 @par !example native_win_random_access_handle
48
49 @see @ref win_random_access_handle, @ref iocp_t
50 */
51 template<auto Backend>
52 class native_win_random_access_handle : public win_random_access_handle
53 {
54 using backend_type = decltype(Backend);
55 using impl_type = typename backend_type::random_access_handle_type;
56 using service_type =
57 typename backend_type::random_access_handle_service_type;
58
59 1x impl_type& get_impl() noexcept
60 {
61 1x return *static_cast<impl_type*>(h_.get());
62 }
63
64 template<class MutableBufferSequence>
65 struct native_read_at_awaitable
66 : detail::bytes_op_base<native_read_at_awaitable<MutableBufferSequence>>
67 {
68 native_win_random_access_handle& self_;
69 std::uint64_t offset_;
70 MutableBufferSequence buffers_;
71
72 native_read_at_awaitable(
73 native_win_random_access_handle& self,
74 std::uint64_t offset,
75 MutableBufferSequence buffers) noexcept
76 : self_(self)
77 , offset_(offset)
78 , buffers_(std::move(buffers))
79 {
80 }
81
82 std::coroutine_handle<>
83 dispatch(capy::continuation& cont, capy::executor_ref ex) const
84 {
85 return self_.get_impl().read_some_at(
86 offset_, cont, ex, buffers_, this->token_, &this->ec_,
87 &this->bytes_);
88 }
89 };
90
91 template<class ConstBufferSequence>
92 struct native_write_at_awaitable
93 : detail::bytes_op_base<native_write_at_awaitable<ConstBufferSequence>>
94 {
95 native_win_random_access_handle& self_;
96 std::uint64_t offset_;
97 ConstBufferSequence buffers_;
98
99 1x native_write_at_awaitable(
100 native_win_random_access_handle& self,
101 std::uint64_t offset,
102 ConstBufferSequence buffers) noexcept
103 1x : self_(self)
104 1x , offset_(offset)
105 1x , buffers_(std::move(buffers))
106 {
107 1x }
108
109 std::coroutine_handle<>
110 1x dispatch(capy::continuation& cont, capy::executor_ref ex) const
111 {
112 2x return self_.get_impl().write_some_at(
113
1/1
✓ Branch 5 → 6 taken 1 time.
1x offset_, cont, ex, buffers_, this->token_, &this->ec_,
114 2x &this->bytes_);
115 }
116 };
117
118 public:
119 /** Construct a `native_win_random_access_handle` from an execution context.
120
121 @param ctx The execution context that owns this object.
122 */
123 1x explicit native_win_random_access_handle(capy::execution_context& ctx)
124
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 3 → 4 taken 1 time.
1x : win_random_access_handle(handle(ctx, ctx.use_service<service_type>()))
125 {
126 1x }
127
128 /** Construct a `native_win_random_access_handle` from an executor.
129
130 The overload excludes `native_win_random_access_handle` itself
131 so that it cannot displace the move constructor.
132
133 @tparam Ex A type satisfying `capy::Executor`.
134 @param ex The executor whose context owns this object.
135 */
136 template<class Ex>
137 requires(!std::same_as<
138 std::remove_cvref_t<Ex>,
139 native_win_random_access_handle>) &&
140 capy::Executor<Ex>
141 explicit native_win_random_access_handle(Ex const& ex)
142 : native_win_random_access_handle(ex.context())
143 {
144 }
145
146 /** Transfer ownership of the handle from the source.
147
148 After the move, the source is in a moved-from state and may
149 only be destroyed or assigned to.
150
151 @pre No awaitables returned by the source's methods exist.
152 */
153 native_win_random_access_handle(
154 native_win_random_access_handle&&) noexcept = default;
155
156 /** Close any held handle and transfer ownership from the source.
157
158 After the move, the source is in a moved-from state and may
159 only be destroyed or assigned to.
160
161 @return `*this`.
162 @pre No awaitables returned by either object's methods exist.
163 */
164 native_win_random_access_handle&
165 operator=(native_win_random_access_handle&&) noexcept = default;
166
167 /// Copy construction is disabled; the handle is uniquely owned.
168 native_win_random_access_handle(
169 native_win_random_access_handle const&) = delete;
170 /// Copy assignment is disabled; the handle is uniquely owned.
171 native_win_random_access_handle&
172 operator=(native_win_random_access_handle const&) = delete;
173
174 /** Asynchronously read at the given offset.
175
176 Calls the backend implementation directly, bypassing virtual
177 dispatch. Unlike @ref win_random_access_handle::read_some_at,
178 it skips the `is_open()` check. A closed handle still completes
179 with `errc::bad_file_descriptor`. Do not call it on a moved-from
180 object.
181
182 @param offset The byte offset to read at.
183 @param buffers The buffers to read into.
184
185 @return An awaitable yielding the error code and the byte count read.
186 */
187 template<capy::MutableBufferSequence MB>
188 [[nodiscard]] auto read_some_at(std::uint64_t offset, MB const& buffers)
189 {
190 return native_read_at_awaitable<MB>(*this, offset, buffers);
191 }
192
193 /** Asynchronously write at the given offset.
194
195 Calls the backend implementation directly, bypassing virtual
196 dispatch. Unlike @ref win_random_access_handle::write_some_at,
197 it skips the `is_open()` check. A closed handle still completes
198 with `errc::bad_file_descriptor`. Do not call it on a moved-from
199 object.
200
201 @param offset The byte offset to write at.
202 @param buffers The buffer data to write.
203
204 @return An awaitable yielding the error code and the byte count written.
205 */
206 template<capy::ConstBufferSequence CB>
207 1x [[nodiscard]] auto write_some_at(std::uint64_t offset, CB const& buffers)
208 {
209 1x return native_write_at_awaitable<CB>(*this, offset, buffers);
210 }
211 };
212
213 } // namespace boost::corosio
214
215 #endif // BOOST_COROSIO_HAS_IOCP || BOOST_COROSIO_MRDOCS
216
217 #endif // BOOST_COROSIO_NATIVE_NATIVE_WIN_RANDOM_ACCESS_HANDLE_HPP
218