100.00% Lines (23/23) 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_STREAM_FILE_HPP 11   #ifndef BOOST_COROSIO_NATIVE_NATIVE_STREAM_FILE_HPP
12   #define BOOST_COROSIO_NATIVE_NATIVE_STREAM_FILE_HPP 12   #define BOOST_COROSIO_NATIVE_NATIVE_STREAM_FILE_HPP
13   13  
14   #include <boost/corosio/stream_file.hpp> 14   #include <boost/corosio/stream_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_stream_file_service.hpp> 21   #include <boost/corosio/native/detail/posix/posix_stream_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_stream_file.hpp> 25   #include <boost/corosio/native/detail/uring/uring_stream_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_file_service.hpp> 29   #include <boost/corosio/native/detail/iocp/win_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 sequentially, calling the backend directly. 35   /** Reads and writes a file sequentially, calling the backend directly.
36   36  
37   This class template inherits from @ref stream_file. It shadows 37   This class template inherits from @ref stream_file. It shadows
38   `read_some` / `write_some` with versions that call the backend 38   `read_some` / `write_some` with versions that call the backend
39   implementation directly. The compiler can then inline through the 39   implementation directly. The compiler can then inline through the
40   entire call chain. 40   entire call chain.
41   41  
42   Non-async operations (`open`, `close`, `size`, `resize`, `seek`, 42   Non-async operations (`open`, `close`, `size`, `resize`, `seek`,
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_stream_file` IS-A `stream_file` and can be passed to 46   A `native_stream_file` IS-A `stream_file` and can be passed to
47   any function expecting `stream_file&` or `io_stream&`, in which 47   any function expecting `stream_file&` or `io_stream&`, in which
48   case virtual dispatch is used transparently. 48   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 stream_file. 61   Same as @ref stream_file.
62   62  
63   @par Example 63   @par Example
64   @par !example native_stream_file 64   @par !example native_stream_file
65   65  
66   @see stream_file, epoll_t, iocp_t 66   @see stream_file, epoll_t, iocp_t
67   */ 67   */
68   template<auto Backend> 68   template<auto Backend>
69   class native_stream_file : public stream_file 69   class native_stream_file : public stream_file
70   { 70   {
71   using backend_type = decltype(Backend); 71   using backend_type = decltype(Backend);
72   using impl_type = typename backend_type::stream_file_type; 72   using impl_type = typename backend_type::stream_file_type;
73   using service_type = typename backend_type::stream_file_service_type; 73   using service_type = typename backend_type::stream_file_service_type;
74   74  
HITCBC 75   8 impl_type& get_impl() noexcept 75   8 impl_type& get_impl() noexcept
76   { 76   {
HITCBC 77   8 return *static_cast<impl_type*>(h_.get()); 77   8 return *static_cast<impl_type*>(h_.get());
78   } 78   }
79   79  
80   template<class MutableBufferSequence> 80   template<class MutableBufferSequence>
81   struct native_read_awaitable 81   struct native_read_awaitable
82   : detail::bytes_op_base<native_read_awaitable<MutableBufferSequence>> 82   : detail::bytes_op_base<native_read_awaitable<MutableBufferSequence>>
83   { 83   {
84   native_stream_file& self_; 84   native_stream_file& self_;
85   MutableBufferSequence buffers_; 85   MutableBufferSequence buffers_;
86   86  
HITCBC 87   6 native_read_awaitable( 87   6 native_read_awaitable(
88   native_stream_file& self, MutableBufferSequence buffers) noexcept 88   native_stream_file& self, MutableBufferSequence buffers) noexcept
HITCBC 89   6 : self_(self) 89   6 : self_(self)
HITCBC 90   6 , buffers_(std::move(buffers)) 90   6 , buffers_(std::move(buffers))
91   { 91   {
HITCBC 92   6 } 92   6 }
93   93  
94   std::coroutine_handle<> 94   std::coroutine_handle<>
HITCBC 95   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 95   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
96   { 96   {
HITCBC 97   12 return self_.get_impl().read_some( 97   12 return self_.get_impl().read_some(
HITCBC 98   12 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 98   12 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
99   } 99   }
100   }; 100   };
101   101  
102   template<class ConstBufferSequence> 102   template<class ConstBufferSequence>
103   struct native_write_awaitable 103   struct native_write_awaitable
104   : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>> 104   : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>>
105   { 105   {
106   native_stream_file& self_; 106   native_stream_file& self_;
107   ConstBufferSequence buffers_; 107   ConstBufferSequence buffers_;
108   108  
HITCBC 109   6 native_write_awaitable( 109   6 native_write_awaitable(
110   native_stream_file& self, ConstBufferSequence buffers) noexcept 110   native_stream_file& self, ConstBufferSequence buffers) noexcept
HITCBC 111   6 : self_(self) 111   6 : self_(self)
HITCBC 112   6 , buffers_(std::move(buffers)) 112   6 , buffers_(std::move(buffers))
113   { 113   {
HITCBC 114   6 } 114   6 }
115   115  
116   std::coroutine_handle<> 116   std::coroutine_handle<>
HITCBC 117   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 117   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
118   { 118   {
HITCBC 119   12 return self_.get_impl().write_some( 119   12 return self_.get_impl().write_some(
HITCBC 120   12 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 120   12 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
121   } 121   }
122   }; 122   };
123   123  
124   public: 124   public:
125   /** Construct a native stream file from an execution context. 125   /** Construct a native stream file from an execution context.
126   126  
127   @param ctx The execution context that owns this file. 127   @param ctx The execution context that owns this file.
128   */ 128   */
HITCBC 129   16 explicit native_stream_file(capy::execution_context& ctx) 129   16 explicit native_stream_file(capy::execution_context& ctx)
HITCBC 130   16 : io_object(handle(ctx, ctx.use_service<service_type>())) 130   16 : io_object(handle(ctx, ctx.use_service<service_type>()))
131   { 131   {
HITCBC 132   16 } 132   16 }
133   133  
134   /** Construct a native stream file from an executor. 134   /** Construct a native stream file from an executor.
135   135  
136   @param ex The executor whose context owns this file. 136   @param ex The executor whose context owns this file.
137   */ 137   */
138   template<class Ex> 138   template<class Ex>
139   requires(!std::same_as<std::remove_cvref_t<Ex>, native_stream_file>) && 139   requires(!std::same_as<std::remove_cvref_t<Ex>, native_stream_file>) &&
140   capy::Executor<Ex> 140   capy::Executor<Ex>
141   explicit native_stream_file(Ex const& ex) : native_stream_file(ex.context()) 141   explicit native_stream_file(Ex const& ex) : native_stream_file(ex.context())
142   { 142   {
143   } 143   }
144   144  
145   /// Move construct. 145   /// Move construct.
146   native_stream_file(native_stream_file&&) noexcept = default; 146   native_stream_file(native_stream_file&&) noexcept = default;
147   147  
148   /// Move assign. 148   /// Move assign.
149   native_stream_file& operator=(native_stream_file&&) noexcept = default; 149   native_stream_file& operator=(native_stream_file&&) noexcept = default;
150   150  
151   /// Copy construction is disabled; the handle is uniquely owned. 151   /// Copy construction is disabled; the handle is uniquely owned.
152   native_stream_file(native_stream_file const&) = delete; 152   native_stream_file(native_stream_file const&) = delete;
153   /// Copy assignment is disabled; the handle is uniquely owned. 153   /// Copy assignment is disabled; the handle is uniquely owned.
154   native_stream_file& operator=(native_stream_file const&) = delete; 154   native_stream_file& operator=(native_stream_file const&) = delete;
155   155  
156   /** Asynchronously read data from the file. 156   /** Asynchronously read data from the file.
157   157  
158   Calls the backend implementation directly, bypassing virtual 158   Calls the backend implementation directly, bypassing virtual
159   dispatch. Otherwise identical to @ref io_stream::read_some. 159   dispatch. Otherwise identical to @ref io_stream::read_some.
160   160  
161   @param buffers The buffers to read into. 161   @param buffers The buffers to read into.
162   162  
163   @return An awaitable yielding the error code and the byte count read. 163   @return An awaitable yielding the error code and the byte count read.
164   */ 164   */
165   template<capy::MutableBufferSequence MB> 165   template<capy::MutableBufferSequence MB>
HITCBC 166   6 [[nodiscard]] auto read_some(MB const& buffers) 166   6 [[nodiscard]] auto read_some(MB const& buffers)
167   { 167   {
HITCBC 168   6 return native_read_awaitable<MB>(*this, buffers); 168   6 return native_read_awaitable<MB>(*this, buffers);
169   } 169   }
170   170  
171   /** Asynchronously write data to the file. 171   /** Asynchronously write data to the file.
172   172  
173   Calls the backend implementation directly, bypassing virtual 173   Calls the backend implementation directly, bypassing virtual
174   dispatch. Otherwise identical to @ref io_stream::write_some. 174   dispatch. Otherwise identical to @ref io_stream::write_some.
175   175  
176   @param buffers The buffer data to write. 176   @param buffers The buffer data to write.
177   177  
178   @return An awaitable yielding the error code and the byte count written. 178   @return An awaitable yielding the error code and the byte count written.
179   */ 179   */
180   template<capy::ConstBufferSequence CB> 180   template<capy::ConstBufferSequence CB>
HITCBC 181   6 [[nodiscard]] auto write_some(CB const& buffers) 181   6 [[nodiscard]] auto write_some(CB const& buffers)
182   { 182   {
HITCBC 183   6 return native_write_awaitable<CB>(*this, buffers); 183   6 return native_write_awaitable<CB>(*this, buffers);
184   } 184   }
185   }; 185   };
186   186  
187   } // namespace boost::corosio 187   } // namespace boost::corosio
188   188  
189   #endif // BOOST_COROSIO_NATIVE_NATIVE_STREAM_FILE_HPP 189   #endif // BOOST_COROSIO_NATIVE_NATIVE_STREAM_FILE_HPP