100.00% Lines (29/29) 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   /** Reads and writes a file at arbitrary offsets, calling the backend directly.
36   36  
37   This class template inherits from @ref random_access_file. It 37   This class template inherits from @ref random_access_file. It
38   shadows `read_some_at` / `write_some_at` with versions that call the 38   shadows `read_some_at` / `write_some_at` with versions that call the
39   backend implementation directly. The compiler can then inline 39   backend implementation directly. The compiler can then inline
40   through the entire call chain. 40   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 pool
51   regardless of the chosen reactor backend. All three reactor tags 51   regardless of the chosen reactor backend. All three reactor tags
52   (`epoll`, `select`, `kqueue`) therefore resolve to the same 52   (`epoll`, `select`, `kqueue`) therefore 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   mutable capy::continuation cont_; 87   mutable capy::continuation cont_;
88   88  
HITCBC 89   8 native_read_at_awaitable( 89   8 native_read_at_awaitable(
90   native_random_access_file& self, 90   native_random_access_file& self,
91   std::uint64_t offset, 91   std::uint64_t offset,
92   MutableBufferSequence buffers) noexcept 92   MutableBufferSequence buffers) noexcept
HITCBC 93   8 : self_(self) 93   8 : self_(self)
HITCBC 94   8 , offset_(offset) 94   8 , offset_(offset)
HITCBC 95   8 , buffers_(std::move(buffers)) 95   8 , buffers_(std::move(buffers))
96   { 96   {
HITCBC 97   8 } 97   8 }
98   98  
99   std::coroutine_handle<> 99   std::coroutine_handle<>
HITCBC 100   6 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 100   6 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
101   { 101   {
HITCBC 102   6 cont_.h = h; 102   6 cont_.h = h;
HITCBC 103   12 return self_.get_impl().read_some_at( 103   12 return self_.get_impl().read_some_at(
HITCBC 104   6 offset_, cont_, ex, buffers_, this->token_, &this->ec_, 104   6 offset_, cont_, ex, buffers_, this->token_, &this->ec_,
HITCBC 105   12 &this->bytes_); 105   12 &this->bytes_);
106   } 106   }
107   }; 107   };
108   108  
109   template<class ConstBufferSequence> 109   template<class ConstBufferSequence>
110   struct native_write_at_awaitable 110   struct native_write_at_awaitable
111   : detail::bytes_op_base<native_write_at_awaitable<ConstBufferSequence>> 111   : detail::bytes_op_base<native_write_at_awaitable<ConstBufferSequence>>
112   { 112   {
113   native_random_access_file& self_; 113   native_random_access_file& self_;
114   std::uint64_t offset_; 114   std::uint64_t offset_;
115   ConstBufferSequence buffers_; 115   ConstBufferSequence buffers_;
116   mutable capy::continuation cont_; 116   mutable capy::continuation cont_;
117   117  
HITCBC 118   6 native_write_at_awaitable( 118   6 native_write_at_awaitable(
119   native_random_access_file& self, 119   native_random_access_file& self,
120   std::uint64_t offset, 120   std::uint64_t offset,
121   ConstBufferSequence buffers) noexcept 121   ConstBufferSequence buffers) noexcept
HITCBC 122   6 : self_(self) 122   6 : self_(self)
HITCBC 123   6 , offset_(offset) 123   6 , offset_(offset)
HITCBC 124   6 , buffers_(std::move(buffers)) 124   6 , buffers_(std::move(buffers))
125   { 125   {
HITCBC 126   6 } 126   6 }
127   127  
128   std::coroutine_handle<> 128   std::coroutine_handle<>
HITCBC 129   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 129   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
130   { 130   {
HITCBC 131   4 cont_.h = h; 131   4 cont_.h = h;
HITCBC 132   8 return self_.get_impl().write_some_at( 132   8 return self_.get_impl().write_some_at(
HITCBC 133   4 offset_, cont_, ex, buffers_, this->token_, &this->ec_, 133   4 offset_, cont_, ex, buffers_, this->token_, &this->ec_,
HITCBC 134   8 &this->bytes_); 134   8 &this->bytes_);
135   } 135   }
136   }; 136   };
137   137  
138   public: 138   public:
139   /** Construct a native random-access file from an execution context. 139   /** Construct a native random-access file from an execution context.
140   140  
141   @param ctx The execution context that owns this file. 141   @param ctx The execution context that owns this file.
142   */ 142   */
HITCBC 143   16 explicit native_random_access_file(capy::execution_context& ctx) 143   16 explicit native_random_access_file(capy::execution_context& ctx)
HITCBC 144   16 : random_access_file(handle(ctx, ctx.use_service<service_type>())) 144   16 : random_access_file(handle(ctx, ctx.use_service<service_type>()))
145   { 145   {
HITCBC 146   16 } 146   16 }
147   147  
148   /** Construct a native random-access file from an executor. 148   /** Construct a native random-access file from an executor.
149   149  
150   @param ex The executor whose context owns this file. 150   @param ex The executor whose context owns this file.
151   */ 151   */
152   template<class Ex> 152   template<class Ex>
153   requires(!std::same_as< 153   requires(!std::same_as<
154   std::remove_cvref_t<Ex>, 154   std::remove_cvref_t<Ex>,
155   native_random_access_file>) && 155   native_random_access_file>) &&
156   capy::Executor<Ex> 156   capy::Executor<Ex>
157   explicit native_random_access_file(Ex const& ex) 157   explicit native_random_access_file(Ex const& ex)
158   : native_random_access_file(ex.context()) 158   : native_random_access_file(ex.context())
159   { 159   {
160   } 160   }
161   161  
162   /// Move construct. 162   /// Move construct.
163   native_random_access_file(native_random_access_file&&) noexcept = default; 163   native_random_access_file(native_random_access_file&&) noexcept = default;
164   164  
165   /// Move assign. 165   /// Move assign.
166   native_random_access_file& 166   native_random_access_file&
167   operator=(native_random_access_file&&) noexcept = default; 167   operator=(native_random_access_file&&) noexcept = default;
168   168  
169   /// Copy construction is disabled; the handle is uniquely owned. 169   /// Copy construction is disabled; the handle is uniquely owned.
170   native_random_access_file(native_random_access_file const&) = delete; 170   native_random_access_file(native_random_access_file const&) = delete;
171   /// Copy assignment is disabled; the handle is uniquely owned. 171   /// Copy assignment is disabled; the handle is uniquely owned.
172   native_random_access_file& 172   native_random_access_file&
173   operator=(native_random_access_file const&) = delete; 173   operator=(native_random_access_file const&) = delete;
174   174  
175   /** Asynchronously read at the given offset. 175   /** Asynchronously read at the given offset.
176   176  
177   Calls the backend implementation directly, bypassing virtual 177   Calls the backend implementation directly, bypassing virtual
178   dispatch. Otherwise identical to @ref random_access_file::read_some_at. 178   dispatch. Otherwise identical to @ref random_access_file::read_some_at.
179   179  
180   @param offset The byte offset to read at. 180   @param offset The byte offset to read at.
181   @param buffers The buffers to read into. 181   @param buffers The buffers to read into.
182   182  
183   @return An awaitable yielding the error code and the byte count read. 183   @return An awaitable yielding the error code and the byte count read.
184   */ 184   */
185   template<capy::MutableBufferSequence MB> 185   template<capy::MutableBufferSequence MB>
HITCBC 186   8 [[nodiscard]] auto read_some_at(std::uint64_t offset, MB const& buffers) 186   8 [[nodiscard]] auto read_some_at(std::uint64_t offset, MB const& buffers)
187   { 187   {
HITCBC 188   8 return native_read_at_awaitable<MB>(*this, offset, buffers); 188   8 return native_read_at_awaitable<MB>(*this, offset, buffers);
189   } 189   }
190   190  
191   /** Asynchronously write at the given offset. 191   /** Asynchronously write at the given offset.
192   192  
193   Calls the backend implementation directly, bypassing virtual 193   Calls the backend implementation directly, bypassing virtual
194   dispatch. Otherwise identical to @ref random_access_file::write_some_at. 194   dispatch. Otherwise identical to @ref random_access_file::write_some_at.
195   195  
196   @param offset The byte offset to write at. 196   @param offset The byte offset to write at.
197   @param buffers The buffer data to write. 197   @param buffers The buffer data to write.
198   198  
199   @return An awaitable yielding the error code and the byte count written. 199   @return An awaitable yielding the error code and the byte count written.
200   */ 200   */
201   template<capy::ConstBufferSequence CB> 201   template<capy::ConstBufferSequence CB>
HITCBC 202   6 [[nodiscard]] auto write_some_at(std::uint64_t offset, CB const& buffers) 202   6 [[nodiscard]] auto write_some_at(std::uint64_t offset, CB const& buffers)
203   { 203   {
HITCBC 204   6 return native_write_at_awaitable<CB>(*this, offset, buffers); 204   6 return native_write_at_awaitable<CB>(*this, offset, buffers);
205   } 205   }
206   }; 206   };
207   207  
208   } // namespace boost::corosio 208   } // namespace boost::corosio
209   209  
210   #endif // BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP 210   #endif // BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP