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   /** A random-access file with devirtualized async I/O operations. 35   /** A random-access file with devirtualized async I/O operations.
36   36  
37   This class template inherits from @ref random_access_file and 37   This class template inherits from @ref random_access_file and
38   shadows `read_some_at` / `write_some_at` with versions that 38   shadows `read_some_at` / `write_some_at` with versions that
39   call the backend implementation directly, allowing the compiler 39   call the backend implementation directly, allowing the compiler
40   to inline 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 50   @note On POSIX platforms, file I/O is dispatched to a thread
51   pool regardless of the chosen reactor backend, so all three 51   pool regardless of the chosen reactor backend, so all three
52   reactor tags (`epoll`, `select`, `kqueue`) 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 will own 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 will own 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   164  
165   native_random_access_file(native_random_access_file const&) = delete; 165   native_random_access_file(native_random_access_file const&) = delete;
166   native_random_access_file& 166   native_random_access_file&
167   operator=(native_random_access_file const&) = delete; 167   operator=(native_random_access_file const&) = delete;
168   168  
169   /** Asynchronously read at the given offset. 169   /** Asynchronously read at the given offset.
170   170  
171   Calls the backend implementation directly, bypassing virtual 171   Calls the backend implementation directly, bypassing virtual
172   dispatch. Otherwise identical to @ref random_access_file::read_some_at. 172   dispatch. Otherwise identical to @ref random_access_file::read_some_at.
173   */ 173   */
174   template<capy::MutableBufferSequence MB> 174   template<capy::MutableBufferSequence MB>
HITCBC 175   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)
176   { 176   {
HITCBC 177   8 return native_read_at_awaitable<MB>(*this, offset, buffers); 177   8 return native_read_at_awaitable<MB>(*this, offset, buffers);
178   } 178   }
179   179  
180   /** Asynchronously write at the given offset. 180   /** Asynchronously write at the given offset.
181   181  
182   Calls the backend implementation directly, bypassing virtual 182   Calls the backend implementation directly, bypassing virtual
183   dispatch. Otherwise identical to @ref random_access_file::write_some_at. 183   dispatch. Otherwise identical to @ref random_access_file::write_some_at.
184   */ 184   */
185   template<capy::ConstBufferSequence CB> 185   template<capy::ConstBufferSequence CB>
HITCBC 186   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)
187   { 187   {
HITCBC 188   6 return native_write_at_awaitable<CB>(*this, offset, buffers); 188   6 return native_write_at_awaitable<CB>(*this, offset, buffers);
189   } 189   }
190   }; 190   };
191   191  
192   } // namespace boost::corosio 192   } // namespace boost::corosio
193   193  
194   #endif // BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP 194   #endif // BOOST_COROSIO_NATIVE_NATIVE_RANDOM_ACCESS_FILE_HPP