95.12% Lines (39/41) 100.00% Functions (12/12)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Steve Gerbino 2   // Copyright (c) 2026 Steve Gerbino
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/corosio 7   // Official repository: https://github.com/cppalliance/corosio
8   // 8   //
9   9  
10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP 10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP
11   #define BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP 11   #define BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP
12   12  
13   #include <boost/corosio/random_access_file.hpp> 13   #include <boost/corosio/random_access_file.hpp>
14   #include <boost/corosio/backend.hpp> 14   #include <boost/corosio/backend.hpp>
15   15  
16   #ifndef BOOST_COROSIO_MRDOCS 16   #ifndef BOOST_COROSIO_MRDOCS
17   #if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_SELECT || \ 17   #if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_SELECT || \
18   BOOST_COROSIO_HAS_KQUEUE 18   BOOST_COROSIO_HAS_KQUEUE
19   #include <boost/corosio/native/detail/posix/posix_random_access_file_service.hpp> 19   #include <boost/corosio/native/detail/posix/posix_random_access_file_service.hpp>
20   #endif 20   #endif
21   21  
22   #if BOOST_COROSIO_HAS_IO_URING 22   #if BOOST_COROSIO_HAS_IO_URING
23   #include <boost/corosio/native/detail/io_uring/io_uring_random_access_file.hpp> 23   #include <boost/corosio/native/detail/io_uring/io_uring_random_access_file.hpp>
24   #endif 24   #endif
25   25  
26   #if BOOST_COROSIO_HAS_IOCP 26   #if BOOST_COROSIO_HAS_IOCP
27   #include <boost/corosio/native/detail/iocp/win_random_access_file_service.hpp> 27   #include <boost/corosio/native/detail/iocp/win_random_access_file_service.hpp>
28   #endif 28   #endif
29   #endif // !BOOST_COROSIO_MRDOCS 29   #endif // !BOOST_COROSIO_MRDOCS
30   30  
31   namespace boost::corosio { 31   namespace boost::corosio {
32   32  
33   /** A random-access file with devirtualized async I/O operations. 33   /** A random-access file with devirtualized async I/O operations.
34   34  
35   This class template inherits from @ref random_access_file and 35   This class template inherits from @ref random_access_file and
36   shadows `read_some_at` / `write_some_at` with versions that 36   shadows `read_some_at` / `write_some_at` with versions that
37   call the backend implementation directly, allowing the compiler 37   call the backend implementation directly, allowing the compiler
38   to inline through the entire call chain. 38   to inline through the entire call chain.
39   39  
40   Non-async operations (`open`, `close`, `size`, `resize`, 40   Non-async operations (`open`, `close`, `size`, `resize`,
41   `sync_data`, `sync_all`) remain unchanged and dispatch through 41   `sync_data`, `sync_all`) remain unchanged and dispatch through
42   the compiled library. 42   the compiled library.
43   43  
44   A `native_random_access_file` IS-A `random_access_file` and 44   A `native_random_access_file` IS-A `random_access_file` and
45   can be passed to any function expecting `random_access_file&`, 45   can be passed to any function expecting `random_access_file&`,
46   in which case virtual dispatch is used transparently. 46   in which case virtual dispatch is used transparently.
47   47  
48   @note On POSIX platforms, file I/O is dispatched to a thread 48   @note On POSIX platforms, file I/O is dispatched to a thread
49   pool regardless of the chosen reactor backend, so all three 49   pool regardless of the chosen reactor backend, so all three
50   reactor tags (`epoll`, `select`, `kqueue`) resolve to the same 50   reactor tags (`epoll`, `select`, `kqueue`) resolve to the same
51   underlying implementation. The `Backend` template parameter 51   underlying implementation. The `Backend` template parameter
52   exists for API symmetry with @ref native_tcp_socket and friends. 52   exists for API symmetry with @ref native_tcp_socket and friends.
53   The vtable savings are smaller relative to the thread-pool / 53   The vtable savings are smaller relative to the thread-pool /
54   overlapped-I/O cost than they are for socket operations. 54   overlapped-I/O cost than they are for socket operations.
55   55  
56   @tparam Backend A backend tag value (e.g., `epoll`, `iocp`). 56   @tparam Backend A backend tag value (e.g., `epoll`, `iocp`).
57   57  
58   @par Thread Safety 58   @par Thread Safety
59   Same as @ref random_access_file. 59   Same as @ref random_access_file.
60   60  
61   @par Example 61   @par Example
62   @code 62   @code
63   #include <boost/corosio/native/native_random_access_file.hpp> 63   #include <boost/corosio/native/native_random_access_file.hpp>
64   64  
65   native_io_context<epoll> ctx; 65   native_io_context<epoll> ctx;
66   native_random_access_file<epoll> f(ctx); 66   native_random_access_file<epoll> f(ctx);
67   f.open("data.bin", file_base::read_only); 67   f.open("data.bin", file_base::read_only);
68   char buf[4096]; 68   char buf[4096];
69   auto [ec, n] = co_await f.read_some_at( 69   auto [ec, n] = co_await f.read_some_at(
70   0, capy::mutable_buffer(buf, sizeof(buf))); 70   0, capy::mutable_buffer(buf, sizeof(buf)));
71   @endcode 71   @endcode
72   72  
73   @see random_access_file, epoll_t, iocp_t 73   @see random_access_file, epoll_t, iocp_t
74   */ 74   */
75   template<auto Backend> 75   template<auto Backend>
76   class native_random_access_file : public random_access_file 76   class native_random_access_file : public random_access_file
77   { 77   {
78   using backend_type = decltype(Backend); 78   using backend_type = decltype(Backend);
79   using impl_type = typename backend_type::random_access_file_type; 79   using impl_type = typename backend_type::random_access_file_type;
80   using service_type = 80   using service_type =
81   typename backend_type::random_access_file_service_type; 81   typename backend_type::random_access_file_service_type;
82   82  
HITCBC 83   4 impl_type& get_impl() noexcept 83   4 impl_type& get_impl() noexcept
84   { 84   {
HITCBC 85   4 return *static_cast<impl_type*>(h_.get()); 85   4 return *static_cast<impl_type*>(h_.get());
86   } 86   }
87   87  
88   template<class MutableBufferSequence> 88   template<class MutableBufferSequence>
89   struct native_read_at_awaitable 89   struct native_read_at_awaitable
90   { 90   {
91   native_random_access_file& self_; 91   native_random_access_file& self_;
92   std::uint64_t offset_; 92   std::uint64_t offset_;
93   MutableBufferSequence buffers_; 93   MutableBufferSequence buffers_;
94   std::stop_token token_; 94   std::stop_token token_;
95   mutable std::error_code ec_; 95   mutable std::error_code ec_;
96   mutable std::size_t bytes_transferred_ = 0; 96   mutable std::size_t bytes_transferred_ = 0;
97   97  
HITCBC 98   2 native_read_at_awaitable( 98   2 native_read_at_awaitable(
99   native_random_access_file& self, 99   native_random_access_file& self,
100   std::uint64_t offset, 100   std::uint64_t offset,
101   MutableBufferSequence buffers) noexcept 101   MutableBufferSequence buffers) noexcept
HITCBC 102   2 : self_(self) 102   2 : self_(self)
HITCBC 103   2 , offset_(offset) 103   2 , offset_(offset)
HITCBC 104   2 , buffers_(std::move(buffers)) 104   2 , buffers_(std::move(buffers))
105   { 105   {
HITCBC 106   2 } 106   2 }
107   107  
HITCBC 108   2 bool await_ready() const noexcept 108   2 bool await_ready() const noexcept
109   { 109   {
HITCBC 110   2 return token_.stop_requested(); 110   2 return token_.stop_requested();
111   } 111   }
112   112  
HITCBC 113   2 capy::io_result<std::size_t> await_resume() const noexcept 113   2 capy::io_result<std::size_t> await_resume() const noexcept
114   { 114   {
HITCBC 115   2 if (token_.stop_requested()) 115   2 if (token_.stop_requested())
MISUBC 116   return {make_error_code(std::errc::operation_canceled), 0}; 116   return {make_error_code(std::errc::operation_canceled), 0};
HITCBC 117   2 return {ec_, bytes_transferred_}; 117   2 return {ec_, bytes_transferred_};
118   } 118   }
119   119  
HITCBC 120   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 120   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
121   -> std::coroutine_handle<> 121   -> std::coroutine_handle<>
122   { 122   {
HITCBC 123   2 token_ = env->stop_token; 123   2 token_ = env->stop_token;
HITCBC 124   6 return self_.get_impl().read_some_at( 124   6 return self_.get_impl().read_some_at(
HITCBC 125   2 offset_, h, env->executor, buffers_, 125   2 offset_, h, env->executor, buffers_,
HITCBC 126   6 token_, &ec_, &bytes_transferred_); 126   6 token_, &ec_, &bytes_transferred_);
127   } 127   }
128   }; 128   };
129   129  
130   template<class ConstBufferSequence> 130   template<class ConstBufferSequence>
131   struct native_write_at_awaitable 131   struct native_write_at_awaitable
132   { 132   {
133   native_random_access_file& self_; 133   native_random_access_file& self_;
134   std::uint64_t offset_; 134   std::uint64_t offset_;
135   ConstBufferSequence buffers_; 135   ConstBufferSequence buffers_;
136   std::stop_token token_; 136   std::stop_token token_;
137   mutable std::error_code ec_; 137   mutable std::error_code ec_;
138   mutable std::size_t bytes_transferred_ = 0; 138   mutable std::size_t bytes_transferred_ = 0;
139   139  
HITCBC 140   2 native_write_at_awaitable( 140   2 native_write_at_awaitable(
141   native_random_access_file& self, 141   native_random_access_file& self,
142   std::uint64_t offset, 142   std::uint64_t offset,
143   ConstBufferSequence buffers) noexcept 143   ConstBufferSequence buffers) noexcept
HITCBC 144   2 : self_(self) 144   2 : self_(self)
HITCBC 145   2 , offset_(offset) 145   2 , offset_(offset)
HITCBC 146   2 , buffers_(std::move(buffers)) 146   2 , buffers_(std::move(buffers))
147   { 147   {
HITCBC 148   2 } 148   2 }
149   149  
HITCBC 150   2 bool await_ready() const noexcept 150   2 bool await_ready() const noexcept
151   { 151   {
HITCBC 152   2 return token_.stop_requested(); 152   2 return token_.stop_requested();
153   } 153   }
154   154  
HITCBC 155   2 capy::io_result<std::size_t> await_resume() const noexcept 155   2 capy::io_result<std::size_t> await_resume() const noexcept
156   { 156   {
HITCBC 157   2 if (token_.stop_requested()) 157   2 if (token_.stop_requested())
MISUBC 158   return {make_error_code(std::errc::operation_canceled), 0}; 158   return {make_error_code(std::errc::operation_canceled), 0};
HITCBC 159   2 return {ec_, bytes_transferred_}; 159   2 return {ec_, bytes_transferred_};
160   } 160   }
161   161  
HITCBC 162   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 162   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
163   -> std::coroutine_handle<> 163   -> std::coroutine_handle<>
164   { 164   {
HITCBC 165   2 token_ = env->stop_token; 165   2 token_ = env->stop_token;
HITCBC 166   6 return self_.get_impl().write_some_at( 166   6 return self_.get_impl().write_some_at(
HITCBC 167   2 offset_, h, env->executor, buffers_, 167   2 offset_, h, env->executor, buffers_,
HITCBC 168   6 token_, &ec_, &bytes_transferred_); 168   6 token_, &ec_, &bytes_transferred_);
169   } 169   }
170   }; 170   };
171   171  
172   public: 172   public:
173   /** Construct a native random-access file from an execution context. 173   /** Construct a native random-access file from an execution context.
174   174  
175   @param ctx The execution context that will own this file. 175   @param ctx The execution context that will own this file.
176   */ 176   */
HITCBC 177   10 explicit native_random_access_file(capy::execution_context& ctx) 177   10 explicit native_random_access_file(capy::execution_context& ctx)
HITCBC 178   10 : random_access_file(create_handle<service_type>(ctx)) 178   10 : random_access_file(create_handle<service_type>(ctx))
179   { 179   {
HITCBC 180   10 } 180   10 }
181   181  
182   /** Construct a native random-access file from an executor. 182   /** Construct a native random-access file from an executor.
183   183  
184   @param ex The executor whose context will own this file. 184   @param ex The executor whose context will own this file.
185   */ 185   */
186   template<class Ex> 186   template<class Ex>
187   requires(!std::same_as< 187   requires(!std::same_as<
188   std::remove_cvref_t<Ex>, 188   std::remove_cvref_t<Ex>,
189   native_random_access_file>) && 189   native_random_access_file>) &&
190   capy::Executor<Ex> 190   capy::Executor<Ex>
191   explicit native_random_access_file(Ex const& ex) 191   explicit native_random_access_file(Ex const& ex)
192   : native_random_access_file(ex.context()) 192   : native_random_access_file(ex.context())
193   { 193   {
194   } 194   }
195   195  
196   /// Move construct. 196   /// Move construct.
197   native_random_access_file(native_random_access_file&&) noexcept = default; 197   native_random_access_file(native_random_access_file&&) noexcept = default;
198   198  
199   /// Move assign. 199   /// Move assign.
200   native_random_access_file& 200   native_random_access_file&
201   operator=(native_random_access_file&&) noexcept = default; 201   operator=(native_random_access_file&&) noexcept = default;
202   202  
203   native_random_access_file(native_random_access_file const&) = delete; 203   native_random_access_file(native_random_access_file const&) = delete;
204   native_random_access_file& 204   native_random_access_file&
205   operator=(native_random_access_file const&) = delete; 205   operator=(native_random_access_file const&) = delete;
206   206  
207   /** Asynchronously read at the given offset. 207   /** Asynchronously read at the given offset.
208   208  
209   Calls the backend implementation directly, bypassing virtual 209   Calls the backend implementation directly, bypassing virtual
210   dispatch. Otherwise identical to @ref random_access_file::read_some_at. 210   dispatch. Otherwise identical to @ref random_access_file::read_some_at.
211   */ 211   */
212   template<capy::MutableBufferSequence MB> 212   template<capy::MutableBufferSequence MB>
HITCBC 213   2 auto read_some_at(std::uint64_t offset, MB const& buffers) 213   2 auto read_some_at(std::uint64_t offset, MB const& buffers)
214   { 214   {
HITCBC 215   2 return native_read_at_awaitable<MB>(*this, offset, buffers); 215   2 return native_read_at_awaitable<MB>(*this, offset, buffers);
216   } 216   }
217   217  
218   /** Asynchronously write at the given offset. 218   /** Asynchronously write at the given offset.
219   219  
220   Calls the backend implementation directly, bypassing virtual 220   Calls the backend implementation directly, bypassing virtual
221   dispatch. Otherwise identical to @ref random_access_file::write_some_at. 221   dispatch. Otherwise identical to @ref random_access_file::write_some_at.
222   */ 222   */
223   template<capy::ConstBufferSequence CB> 223   template<capy::ConstBufferSequence CB>
HITCBC 224   2 auto write_some_at(std::uint64_t offset, CB const& buffers) 224   2 auto write_some_at(std::uint64_t offset, CB const& buffers)
225   { 225   {
HITCBC 226   2 return native_write_at_awaitable<CB>(*this, offset, buffers); 226   2 return native_write_at_awaitable<CB>(*this, offset, buffers);
227   } 227   }
228   }; 228   };
229   229  
230   } // namespace boost::corosio 230   } // namespace boost::corosio
231   231  
232   #endif // BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP 232   #endif // BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP