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 + /** A sequential file with devirtualized async I/O operations.
36   36  
37 - This class template inherits from @ref stream_file. It shadows 37 + This class template inherits from @ref stream_file and 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, allowing the compiler to inline through
40 - entire call chain. 40 + the 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
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 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 will own 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(create_handle<service_type>(ctx)) 130   16 : io_object(create_handle<service_type>(ctx))
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 will own 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 + 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.  
154   native_stream_file& operator=(native_stream_file const&) = delete; 152   native_stream_file& operator=(native_stream_file const&) = delete;
155   153  
156   /** Asynchronously read data from the file. 154   /** Asynchronously read data from the file.
157   155  
158   Calls the backend implementation directly, bypassing virtual 156   Calls the backend implementation directly, bypassing virtual
159 -  
160 - @param buffers The buffers to read into.  
161 -  
162 - @return An awaitable yielding the error code and the byte count read.  
163   dispatch. Otherwise identical to @ref io_stream::read_some. 157   dispatch. Otherwise identical to @ref io_stream::read_some.
164   */ 158   */
165   template<capy::MutableBufferSequence MB> 159   template<capy::MutableBufferSequence MB>
HITCBC 166   6 [[nodiscard]] auto read_some(MB const& buffers) 160   6 [[nodiscard]] auto read_some(MB const& buffers)
167   { 161   {
HITCBC 168   6 return native_read_awaitable<MB>(*this, buffers); 162   6 return native_read_awaitable<MB>(*this, buffers);
169   } 163   }
170   164  
171   /** Asynchronously write data to the file. 165   /** Asynchronously write data to the file.
172   166  
173   Calls the backend implementation directly, bypassing virtual 167   Calls the backend implementation directly, bypassing virtual
174 -  
175 - @param buffers The buffer data to write.  
176 -  
177 - @return An awaitable yielding the error code and the byte count written.  
178   dispatch. Otherwise identical to @ref io_stream::write_some. 168   dispatch. Otherwise identical to @ref io_stream::write_some.
179   */ 169   */
180   template<capy::ConstBufferSequence CB> 170   template<capy::ConstBufferSequence CB>
HITCBC 181   6 [[nodiscard]] auto write_some(CB const& buffers) 171   6 [[nodiscard]] auto write_some(CB const& buffers)
182   { 172   {
HITCBC 183   6 return native_write_awaitable<CB>(*this, buffers); 173   6 return native_write_awaitable<CB>(*this, buffers);
184   } 174   }
185   }; 175   };
186   176  
187   } // namespace boost::corosio 177   } // namespace boost::corosio
188   178  
189   #endif // BOOST_COROSIO_NATIVE_NATIVE_STREAM_FILE_HPP 179   #endif // BOOST_COROSIO_NATIVE_NATIVE_STREAM_FILE_HPP