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