TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Steve Gerbino
3 : // Copyright (c) 2026 Michael Vandeberg
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/corosio
9 : //
10 :
11 : #ifndef BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP
12 : #define BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP
13 :
14 : #include <boost/corosio/random_access_file.hpp>
15 : #include <boost/corosio/backend.hpp>
16 : #include <boost/corosio/detail/op_base.hpp>
17 :
18 : #ifndef BOOST_COROSIO_MRDOCS
19 : #if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_SELECT || \
20 : BOOST_COROSIO_HAS_KQUEUE
21 : #include <boost/corosio/native/detail/posix/posix_random_access_file_service.hpp>
22 : #endif
23 :
24 : #if BOOST_COROSIO_HAS_URING
25 : #include <boost/corosio/native/detail/uring/uring_random_access_file.hpp>
26 : #endif
27 :
28 : #if BOOST_COROSIO_HAS_IOCP
29 : #include <boost/corosio/native/detail/iocp/win_random_access_file_service.hpp>
30 : #endif
31 : #endif // !BOOST_COROSIO_MRDOCS
32 :
33 : namespace boost::corosio {
34 :
35 : /** Reads and writes a file at arbitrary offsets, calling the backend directly.
36 :
37 : This class template inherits from @ref random_access_file. It
38 : shadows `read_some_at` / `write_some_at` with versions that call the
39 : backend implementation directly. The compiler can then inline
40 : through the entire call chain.
41 :
42 : Non-async operations (`open`, `close`, `size`, `resize`,
43 : `sync_data`, `sync_all`) remain unchanged and dispatch through
44 : the compiled library.
45 :
46 : A `native_random_access_file` IS-A `random_access_file` and
47 : can be passed to any function expecting `random_access_file&`,
48 : in which case virtual dispatch is used transparently.
49 :
50 : @note On POSIX platforms, file I/O is dispatched to a thread pool
51 : regardless of the chosen reactor backend. All three reactor tags
52 : (`epoll`, `select`, `kqueue`) therefore resolve to the same
53 : underlying implementation. The `Backend` template parameter
54 : exists for API symmetry with @ref native_tcp_socket and friends.
55 : The vtable savings are smaller relative to the thread-pool /
56 : overlapped-I/O cost than they are for socket operations.
57 :
58 : @tparam Backend A backend tag value (e.g., `epoll`, `iocp`).
59 :
60 : @par Thread Safety
61 : Same as @ref random_access_file.
62 :
63 : @par Example
64 : @par !example native_random_access_file
65 :
66 : @see random_access_file, epoll_t, iocp_t
67 : */
68 : template<auto Backend>
69 : class native_random_access_file : public random_access_file
70 : {
71 : using backend_type = decltype(Backend);
72 : using impl_type = typename backend_type::random_access_file_type;
73 : using service_type = typename backend_type::random_access_file_service_type;
74 :
75 HIT 10 : impl_type& get_impl() noexcept
76 : {
77 10 : return *static_cast<impl_type*>(h_.get());
78 : }
79 :
80 : template<class MutableBufferSequence>
81 : struct native_read_at_awaitable
82 : : detail::bytes_op_base<native_read_at_awaitable<MutableBufferSequence>>
83 : {
84 : native_random_access_file& self_;
85 : std::uint64_t offset_;
86 : MutableBufferSequence buffers_;
87 : mutable capy::continuation cont_;
88 :
89 8 : native_read_at_awaitable(
90 : native_random_access_file& self,
91 : std::uint64_t offset,
92 : MutableBufferSequence buffers) noexcept
93 8 : : self_(self)
94 8 : , offset_(offset)
95 8 : , buffers_(std::move(buffers))
96 : {
97 8 : }
98 :
99 : std::coroutine_handle<>
100 6 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
101 : {
102 6 : cont_.h = h;
103 12 : return self_.get_impl().read_some_at(
104 6 : offset_, cont_, ex, buffers_, this->token_, &this->ec_,
105 12 : &this->bytes_);
106 : }
107 : };
108 :
109 : template<class ConstBufferSequence>
110 : struct native_write_at_awaitable
111 : : detail::bytes_op_base<native_write_at_awaitable<ConstBufferSequence>>
112 : {
113 : native_random_access_file& self_;
114 : std::uint64_t offset_;
115 : ConstBufferSequence buffers_;
116 : mutable capy::continuation cont_;
117 :
118 6 : native_write_at_awaitable(
119 : native_random_access_file& self,
120 : std::uint64_t offset,
121 : ConstBufferSequence buffers) noexcept
122 6 : : self_(self)
123 6 : , offset_(offset)
124 6 : , buffers_(std::move(buffers))
125 : {
126 6 : }
127 :
128 : std::coroutine_handle<>
129 4 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
130 : {
131 4 : cont_.h = h;
132 8 : return self_.get_impl().write_some_at(
133 4 : offset_, cont_, ex, buffers_, this->token_, &this->ec_,
134 8 : &this->bytes_);
135 : }
136 : };
137 :
138 : public:
139 : /** Construct a native random-access file from an execution context.
140 :
141 : @param ctx The execution context that owns this file.
142 : */
143 16 : explicit native_random_access_file(capy::execution_context& ctx)
144 16 : : random_access_file(handle(ctx, ctx.use_service<service_type>()))
145 : {
146 16 : }
147 :
148 : /** Construct a native random-access file from an executor.
149 :
150 : @param ex The executor whose context owns this file.
151 : */
152 : template<class Ex>
153 : requires(!std::same_as<
154 : std::remove_cvref_t<Ex>,
155 : native_random_access_file>) &&
156 : capy::Executor<Ex>
157 : explicit native_random_access_file(Ex const& ex)
158 : : native_random_access_file(ex.context())
159 : {
160 : }
161 :
162 : /// Move construct.
163 : native_random_access_file(native_random_access_file&&) noexcept = default;
164 :
165 : /// Move assign.
166 : native_random_access_file&
167 : operator=(native_random_access_file&&) noexcept = default;
168 :
169 : /// Copy construction is disabled; the handle is uniquely owned.
170 : native_random_access_file(native_random_access_file const&) = delete;
171 : /// Copy assignment is disabled; the handle is uniquely owned.
172 : native_random_access_file&
173 : operator=(native_random_access_file const&) = delete;
174 :
175 : /** Asynchronously read at the given offset.
176 :
177 : Calls the backend implementation directly, bypassing virtual
178 : dispatch. Otherwise identical to @ref random_access_file::read_some_at.
179 :
180 : @param offset The byte offset to read at.
181 : @param buffers The buffers to read into.
182 :
183 : @return An awaitable yielding the error code and the byte count read.
184 : */
185 : template<capy::MutableBufferSequence MB>
186 8 : [[nodiscard]] auto read_some_at(std::uint64_t offset, MB const& buffers)
187 : {
188 8 : return native_read_at_awaitable<MB>(*this, offset, buffers);
189 : }
190 :
191 : /** Asynchronously write at the given offset.
192 :
193 : Calls the backend implementation directly, bypassing virtual
194 : dispatch. Otherwise identical to @ref random_access_file::write_some_at.
195 :
196 : @param offset The byte offset to write at.
197 : @param buffers The buffer data to write.
198 :
199 : @return An awaitable yielding the error code and the byte count written.
200 : */
201 : template<capy::ConstBufferSequence CB>
202 6 : [[nodiscard]] auto write_some_at(std::uint64_t offset, CB const& buffers)
203 : {
204 6 : return native_write_at_awaitable<CB>(*this, offset, buffers);
205 : }
206 : };
207 :
208 : } // namespace boost::corosio
209 :
210 : #endif // BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP
|