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