100.00% Lines (38/38) 100.00% Functions (11/11)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Michael Vandeberg 2   // Copyright (c) 2026 Michael Vandeberg
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_RANDOM_ACCESS_FILE_HPP 10   #ifndef BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP
11   #define BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP 11   #define BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP
12   12  
13   #include <boost/corosio/detail/config.hpp> 13   #include <boost/corosio/detail/config.hpp>
14   #include <boost/corosio/detail/platform.hpp> 14   #include <boost/corosio/detail/platform.hpp>
15   #include <boost/corosio/detail/except.hpp> 15   #include <boost/corosio/detail/except.hpp>
16   #include <boost/corosio/detail/native_handle.hpp> 16   #include <boost/corosio/detail/native_handle.hpp>
17   #include <boost/corosio/detail/buffer_param.hpp> 17   #include <boost/corosio/detail/buffer_param.hpp>
  18 + #include <boost/corosio/detail/op_base.hpp>
18   #include <boost/corosio/file_base.hpp> 19   #include <boost/corosio/file_base.hpp>
19   #include <boost/corosio/io/io_object.hpp> 20   #include <boost/corosio/io/io_object.hpp>
20   #include <boost/capy/io_result.hpp> 21   #include <boost/capy/io_result.hpp>
21   #include <boost/capy/ex/executor_ref.hpp> 22   #include <boost/capy/ex/executor_ref.hpp>
22   #include <boost/capy/ex/execution_context.hpp> 23   #include <boost/capy/ex/execution_context.hpp>
23   #include <boost/capy/ex/io_env.hpp> 24   #include <boost/capy/ex/io_env.hpp>
24   #include <boost/capy/concept/executor.hpp> 25   #include <boost/capy/concept/executor.hpp>
25   #include <boost/capy/buffers.hpp> 26   #include <boost/capy/buffers.hpp>
26   27  
27   #include <concepts> 28   #include <concepts>
28   #include <coroutine> 29   #include <coroutine>
29   #include <cstddef> 30   #include <cstddef>
30   #include <cstdint> 31   #include <cstdint>
31   #include <type_traits> 32   #include <type_traits>
32   #include <filesystem> 33   #include <filesystem>
33   #include <stop_token> 34   #include <stop_token>
34   #include <system_error> 35   #include <system_error>
35   36  
36   namespace boost::corosio { 37   namespace boost::corosio {
37   38  
38   /** An asynchronous random-access file for coroutine I/O. 39   /** An asynchronous random-access file for coroutine I/O.
39   40  
40   Provides asynchronous read and write operations at explicit 41   Provides asynchronous read and write operations at explicit
41   byte offsets, without maintaining an implicit file position. 42   byte offsets, without maintaining an implicit file position.
42   43  
43   On POSIX platforms, file I/O is dispatched to a thread pool 44   On POSIX platforms, file I/O is dispatched to a thread pool
44   (blocking `preadv`/`pwritev`) with completion posted back to 45   (blocking `preadv`/`pwritev`) with completion posted back to
45   the scheduler. On Windows, true overlapped I/O is used via IOCP. 46   the scheduler. On Windows, true overlapped I/O is used via IOCP.
46   47  
47   @par Thread Safety 48   @par Thread Safety
48   Distinct objects: Safe.@n 49   Distinct objects: Safe.@n
49   Shared objects: Unsafe. Multiple concurrent reads and writes 50   Shared objects: Unsafe. Multiple concurrent reads and writes
50   are supported from coroutines sharing the same file object, 51   are supported from coroutines sharing the same file object,
51   but external synchronization is required for non-async 52   but external synchronization is required for non-async
52   operations (open, close, size, resize, etc.). 53   operations (open, close, size, resize, etc.).
53   54  
54   @par Example 55   @par Example
55   @par !example random_access_file 56   @par !example random_access_file
56   */ 57   */
57   class BOOST_COROSIO_DECL random_access_file : public io_object 58   class BOOST_COROSIO_DECL random_access_file : public io_object
58   { 59   {
59   public: 60   public:
60   /** Platform-specific random-access file implementation interface. 61   /** Platform-specific random-access file implementation interface.
61   62  
62   Backends derive from this to provide offset-based file I/O. 63   Backends derive from this to provide offset-based file I/O.
63   */ 64   */
64   struct implementation : io_object::implementation 65   struct implementation : io_object::implementation
65   { 66   {
66   /** Initiate a read at the given offset. 67   /** Initiate a read at the given offset.
67   68  
68   @param offset Byte offset into the file. 69   @param offset Byte offset into the file.
69   @param h Coroutine handle to resume on completion. 70   @param h Coroutine handle to resume on completion.
70   @param ex Executor for dispatching the completion. 71   @param ex Executor for dispatching the completion.
71   @param buf The buffer to read into. 72   @param buf The buffer to read into.
72   @param token Stop token for cancellation. 73   @param token Stop token for cancellation.
73   @param ec Output error code. 74   @param ec Output error code.
74   @param bytes_out Output bytes transferred. 75   @param bytes_out Output bytes transferred.
75   @return Coroutine handle to resume immediately. 76   @return Coroutine handle to resume immediately.
76   */ 77   */
77   virtual std::coroutine_handle<> read_some_at( 78   virtual std::coroutine_handle<> read_some_at(
78   std::uint64_t offset, 79   std::uint64_t offset,
79   std::coroutine_handle<> h, 80   std::coroutine_handle<> h,
80   capy::executor_ref ex, 81   capy::executor_ref ex,
81   buffer_param buf, 82   buffer_param buf,
82   std::stop_token token, 83   std::stop_token token,
83   std::error_code* ec, 84   std::error_code* ec,
84   std::size_t* bytes_out) = 0; 85   std::size_t* bytes_out) = 0;
85   86  
86   /** Initiate a write at the given offset. 87   /** Initiate a write at the given offset.
87   88  
88   @param offset Byte offset into the file. 89   @param offset Byte offset into the file.
89   @param h Coroutine handle to resume on completion. 90   @param h Coroutine handle to resume on completion.
90   @param ex Executor for dispatching the completion. 91   @param ex Executor for dispatching the completion.
91   @param buf The buffer to write from. 92   @param buf The buffer to write from.
92   @param token Stop token for cancellation. 93   @param token Stop token for cancellation.
93   @param ec Output error code. 94   @param ec Output error code.
94   @param bytes_out Output bytes transferred. 95   @param bytes_out Output bytes transferred.
95   @return Coroutine handle to resume immediately. 96   @return Coroutine handle to resume immediately.
96   */ 97   */
97   virtual std::coroutine_handle<> write_some_at( 98   virtual std::coroutine_handle<> write_some_at(
98   std::uint64_t offset, 99   std::uint64_t offset,
99   std::coroutine_handle<> h, 100   std::coroutine_handle<> h,
100   capy::executor_ref ex, 101   capy::executor_ref ex,
101   buffer_param buf, 102   buffer_param buf,
102   std::stop_token token, 103   std::stop_token token,
103   std::error_code* ec, 104   std::error_code* ec,
104   std::size_t* bytes_out) = 0; 105   std::size_t* bytes_out) = 0;
105   106  
106   /// Return the platform file descriptor or handle. 107   /// Return the platform file descriptor or handle.
107   virtual native_handle_type native_handle() const noexcept = 0; 108   virtual native_handle_type native_handle() const noexcept = 0;
108   109  
109   /// Cancel pending asynchronous operations. 110   /// Cancel pending asynchronous operations.
110   virtual void cancel() noexcept = 0; 111   virtual void cancel() noexcept = 0;
111   112  
112   /// Return the file size in bytes. 113   /// Return the file size in bytes.
113   virtual std::uint64_t size() const = 0; 114   virtual std::uint64_t size() const = 0;
114   115  
115   /// Resize the file to @p new_size bytes. 116   /// Resize the file to @p new_size bytes.
116   virtual std::error_code resize(std::uint64_t new_size) noexcept = 0; 117   virtual std::error_code resize(std::uint64_t new_size) noexcept = 0;
117   118  
118   /// Synchronize file data to stable storage. 119   /// Synchronize file data to stable storage.
119   virtual std::error_code sync_data() noexcept = 0; 120   virtual std::error_code sync_data() noexcept = 0;
120   121  
121   /// Synchronize file data and metadata to stable storage. 122   /// Synchronize file data and metadata to stable storage.
122   virtual std::error_code sync_all() noexcept = 0; 123   virtual std::error_code sync_all() noexcept = 0;
123   124  
124   /// Release ownership of the native handle. 125   /// Release ownership of the native handle.
125   virtual native_handle_type release() = 0; 126   virtual native_handle_type release() = 0;
126   127  
127   /// Adopt an existing native handle. 128   /// Adopt an existing native handle.
128   virtual std::error_code assign(native_handle_type handle) noexcept = 0; 129   virtual std::error_code assign(native_handle_type handle) noexcept = 0;
129   }; 130   };
130   131  
131   /** Awaitable for async read-at operations. */ 132   /** Awaitable for async read-at operations. */
132   template<class MutableBufferSequence> 133   template<class MutableBufferSequence>
133   struct read_some_at_awaitable 134   struct read_some_at_awaitable
  135 + : detail::bytes_op_base<read_some_at_awaitable<MutableBufferSequence>>
134   { 136   {
135   random_access_file& f_; 137   random_access_file& f_;
136   std::uint64_t offset_; 138   std::uint64_t offset_;
137 - std::stop_token token_;  
138 - mutable std::error_code ec_;  
139 - mutable std::size_t bytes_ = 0;  
140   MutableBufferSequence buffers_; 139   MutableBufferSequence buffers_;
141   140  
HITCBC 142   293 read_some_at_awaitable( 141   343 read_some_at_awaitable(
143   random_access_file& f, 142   random_access_file& f,
144   std::uint64_t offset, 143   std::uint64_t offset,
145   MutableBufferSequence 144   MutableBufferSequence
146   buffers) noexcept(std:: 145   buffers) noexcept(std::
147   is_nothrow_move_constructible_v< 146   is_nothrow_move_constructible_v<
148   MutableBufferSequence>) 147   MutableBufferSequence>)
HITCBC 149   293 : f_(f) 148   343 : f_(f)
HITCBC 150   293 , offset_(offset) 149   343 , offset_(offset)
HITCBC 151   293 , buffers_(std::move(buffers)) 150   343 , buffers_(std::move(buffers))
152   { 151   {
HITCBC 153   293 } 152   343 }
154   153  
ECB 155 - 293 bool await_ready() const noexcept 154 + std::coroutine_handle<>
HITGIC 156 - { 155 + 337 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
157 - // A pre-set ec_ means the initiator failed before  
158 - // dispatch (e.g. a closed object).  
DCB 159 - 293 return static_cast<bool>(ec_) || token_.stop_requested();  
160 - }  
161 -  
DCB 162 - 291 [[nodiscard]] capy::io_result<std::size_t> await_resume() const noexcept  
163 - {  
DCB 164 - 291 if (token_.stop_requested())  
DCB 165 - 4 return {make_error_code(std::errc::operation_canceled), 0};  
DCB 166 - 287 return {ec_, bytes_};  
167 - }  
168 -  
DCB 169 - 291 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)  
170 - -> std::coroutine_handle<>  
171 - token_ = env->stop_token;  
ECB 172   291 { 156   {
HITCBC 173   873 return f_.get().read_some_at( 157   674 return f_.get().read_some_at(
HITCBC 174 - 873 offset_, h, env->executor, buffers_, token_, &ec_, &bytes_); 158 + 337 offset_, h, ex, buffers_, this->token_, &this->ec_,
HITGNC   159 + 674 &this->bytes_);
175   } 160   }
176   }; 161   };
177   162  
178   /** Awaitable for async write-at operations. */ 163   /** Awaitable for async write-at operations. */
179   template<class ConstBufferSequence> 164   template<class ConstBufferSequence>
180   struct write_some_at_awaitable 165   struct write_some_at_awaitable
  166 + : detail::bytes_op_base<write_some_at_awaitable<ConstBufferSequence>>
181   { 167   {
182   random_access_file& f_; 168   random_access_file& f_;
183   std::uint64_t offset_; 169   std::uint64_t offset_;
184 - std::stop_token token_;  
185 - mutable std::error_code ec_;  
186 - mutable std::size_t bytes_ = 0;  
187   ConstBufferSequence buffers_; 170   ConstBufferSequence buffers_;
188   171  
HITCBC 189   43 write_some_at_awaitable( 172   93 write_some_at_awaitable(
190   random_access_file& f, 173   random_access_file& f,
191   std::uint64_t offset, 174   std::uint64_t offset,
192   ConstBufferSequence 175   ConstBufferSequence
193   buffers) noexcept(std:: 176   buffers) noexcept(std::
194   is_nothrow_move_constructible_v< 177   is_nothrow_move_constructible_v<
195   ConstBufferSequence>) 178   ConstBufferSequence>)
HITCBC 196   43 : f_(f) 179   93 : f_(f)
HITCBC 197   43 , offset_(offset) 180   93 , offset_(offset)
HITCBC 198   43 , buffers_(std::move(buffers)) 181   93 , buffers_(std::move(buffers))
199   { 182   {
HITCBC 200   43 } 183   93 }
201   184  
ECB 202 - 43 bool await_ready() const noexcept 185 + std::coroutine_handle<>
HITGIC 203 - { 186 + 89 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
204 - // A pre-set ec_ means the initiator failed before  
205 - // dispatch (e.g. a closed object).  
DCB 206 - 43 return static_cast<bool>(ec_) || token_.stop_requested();  
207 - }  
208 -  
DCB 209 - 43 [[nodiscard]] capy::io_result<std::size_t> await_resume() const noexcept  
210 - {  
DCB 211 - 43 if (token_.stop_requested())  
DCB 212 - 2 return {make_error_code(std::errc::operation_canceled), 0};  
DCB 213 - 41 return {ec_, bytes_};  
214 - }  
215 -  
DCB 216 - 41 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)  
217 - -> std::coroutine_handle<>  
218 - token_ = env->stop_token;  
ECB 219   41 { 187   {
HITCBC 220   123 return f_.get().write_some_at( 188   178 return f_.get().write_some_at(
HITCBC 221 - 123 offset_, h, env->executor, buffers_, token_, &ec_, &bytes_); 189 + 89 offset_, h, ex, buffers_, this->token_, &this->ec_,
HITGNC   190 + 178 &this->bytes_);
222   } 191   }
223   }; 192   };
224   193  
225   public: 194   public:
226   /** Destructor. 195   /** Destructor.
227   196  
228   Closes the file if open, cancelling any pending operations. 197   Closes the file if open, cancelling any pending operations.
229   */ 198   */
230   ~random_access_file() override; 199   ~random_access_file() override;
231   200  
232   /** Construct from an execution context. 201   /** Construct from an execution context.
233   202  
234   @param ctx The execution context that will own this file. 203   @param ctx The execution context that will own this file.
235   */ 204   */
236   explicit random_access_file(capy::execution_context& ctx); 205   explicit random_access_file(capy::execution_context& ctx);
237   206  
238   /** Construct from an executor. 207   /** Construct from an executor.
239   208  
240   @param ex The executor whose context will own this file. 209   @param ex The executor whose context will own this file.
241   */ 210   */
242   template<class Ex> 211   template<class Ex>
243   requires(!std::same_as<std::remove_cvref_t<Ex>, random_access_file>) && 212   requires(!std::same_as<std::remove_cvref_t<Ex>, random_access_file>) &&
244   capy::Executor<Ex> 213   capy::Executor<Ex>
HITCBC 245   2 explicit random_access_file(Ex const& ex) : random_access_file(ex.context()) 214   2 explicit random_access_file(Ex const& ex) : random_access_file(ex.context())
246   { 215   {
HITCBC 247   2 } 216   2 }
248   217  
249   /** Move constructor. */ 218   /** Move constructor. */
HITCBC 250   2 random_access_file(random_access_file&& other) noexcept 219   2 random_access_file(random_access_file&& other) noexcept
HITCBC 251   2 : io_object(std::move(other)) 220   2 : io_object(std::move(other))
252   { 221   {
HITCBC 253   2 } 222   2 }
254   223  
255   /** Move assignment operator. */ 224   /** Move assignment operator. */
256   random_access_file& operator=(random_access_file&& other) noexcept 225   random_access_file& operator=(random_access_file&& other) noexcept
257   { 226   {
258   if (this != &other) 227   if (this != &other)
259   { 228   {
260   close(); 229   close();
261   h_ = std::move(other.h_); 230   h_ = std::move(other.h_);
262   } 231   }
263   return *this; 232   return *this;
264   } 233   }
265   234  
266   random_access_file(random_access_file const&) = delete; 235   random_access_file(random_access_file const&) = delete;
267   random_access_file& operator=(random_access_file const&) = delete; 236   random_access_file& operator=(random_access_file const&) = delete;
268   237  
269   /** Open a file. 238   /** Open a file.
270   239  
271   Failures such as a missing file or insufficient permissions 240   Failures such as a missing file or insufficient permissions
272   are expected runtime conditions and are reported through the 241   are expected runtime conditions and are reported through the
273   returned error code. If the file is already open, it is 242   returned error code. If the file is already open, it is
274   closed first. 243   closed first.
275   244  
276   @param path The filesystem path to open. 245   @param path The filesystem path to open.
277   @param mode Bitmask of @ref file_base::flags specifying 246   @param mode Bitmask of @ref file_base::flags specifying
278   access mode and creation behavior. 247   access mode and creation behavior.
279   248  
280   @return The error code, empty on success. 249   @return The error code, empty on success.
281   */ 250   */
282   [[nodiscard]] std::error_code open( 251   [[nodiscard]] std::error_code open(
283   std::filesystem::path const& path, 252   std::filesystem::path const& path,
284   file_base::flags mode = file_base::read_only) noexcept; 253   file_base::flags mode = file_base::read_only) noexcept;
285   254  
286   /** Close the file. 255   /** Close the file.
287   256  
288   Releases file resources. Any pending operations complete 257   Releases file resources. Any pending operations complete
289   with `errc::operation_canceled`. 258   with `errc::operation_canceled`.
290   */ 259   */
291   void close() noexcept; 260   void close() noexcept;
292   261  
293   /** Check if the file is open. */ 262   /** Check if the file is open. */
HITCBC 294   682 bool is_open() const noexcept 263   1082 bool is_open() const noexcept
295   { 264   {
296   #if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS) 265   #if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS)
297   return h_ && get().native_handle() != ~native_handle_type(0); 266   return h_ && get().native_handle() != ~native_handle_type(0);
298   #else 267   #else
HITCBC 299   682 return h_ && get().native_handle() >= 0; 268   1082 return h_ && get().native_handle() >= 0;
300   #endif 269   #endif
301   } 270   }
302   271  
303   /** Read data at the given offset. 272   /** Read data at the given offset.
304   273  
305   @param offset Byte offset into the file. 274   @param offset Byte offset into the file.
306   @param buffers The buffer sequence to read into. 275   @param buffers The buffer sequence to read into.
307   276  
308   @return An awaitable yielding `(error_code, std::size_t)`. 277   @return An awaitable yielding `(error_code, std::size_t)`.
309   278  
310   A closed file reports `errc::bad_file_descriptor`. 279   A closed file reports `errc::bad_file_descriptor`.
311   */ 280   */
312   template<capy::MutableBufferSequence MB> 281   template<capy::MutableBufferSequence MB>
HITCBC 313   293 [[nodiscard]] auto read_some_at(std::uint64_t offset, MB const& buffers) 282   343 [[nodiscard]] auto read_some_at(std::uint64_t offset, MB const& buffers)
314   { 283   {
HITCBC 315   293 read_some_at_awaitable<MB> aw(*this, offset, buffers); 284   343 read_some_at_awaitable<MB> aw(*this, offset, buffers);
HITCBC 316   293 if (!is_open()) 285   343 if (!is_open())
HITCBC 317   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 286   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 318   293 return aw; 287   343 return aw;
319   } 288   }
320   289  
321   /** Write data at the given offset. 290   /** Write data at the given offset.
322   291  
323   @param offset Byte offset into the file. 292   @param offset Byte offset into the file.
324   @param buffers The buffer sequence to write from. 293   @param buffers The buffer sequence to write from.
325   294  
326   @return An awaitable yielding `(error_code, std::size_t)`. 295   @return An awaitable yielding `(error_code, std::size_t)`.
327   296  
328   A closed file reports `errc::bad_file_descriptor`. 297   A closed file reports `errc::bad_file_descriptor`.
329   */ 298   */
330   template<capy::ConstBufferSequence CB> 299   template<capy::ConstBufferSequence CB>
HITCBC 331   43 [[nodiscard]] auto write_some_at(std::uint64_t offset, CB const& buffers) 300   93 [[nodiscard]] auto write_some_at(std::uint64_t offset, CB const& buffers)
332   { 301   {
HITCBC 333   43 write_some_at_awaitable<CB> aw(*this, offset, buffers); 302   93 write_some_at_awaitable<CB> aw(*this, offset, buffers);
HITCBC 334   43 if (!is_open()) 303   93 if (!is_open())
HITCBC 335   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 304   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 336   43 return aw; 305   93 return aw;
337   } 306   }
338   307  
339   /** Cancel pending asynchronous operations. */ 308   /** Cancel pending asynchronous operations. */
340   void cancel() noexcept; 309   void cancel() noexcept;
341   310  
342   /** Get the native file descriptor or handle. */ 311   /** Get the native file descriptor or handle. */
343   native_handle_type native_handle() const noexcept; 312   native_handle_type native_handle() const noexcept;
344   313  
345   /** Return the file size in bytes. 314   /** Return the file size in bytes.
346   315  
347   @throws std::system_error If the file is not open, or if the 316   @throws std::system_error If the file is not open, or if the
348   underlying size query fails. 317   underlying size query fails.
349   */ 318   */
350   std::uint64_t size() const; 319   std::uint64_t size() const;
351   320  
352   /** Resize the file to @p new_size bytes. 321   /** Resize the file to @p new_size bytes.
353   322  
354   Failures such as insufficient disk space are reported 323   Failures such as insufficient disk space are reported
355   through the returned error code. A closed file reports 324   through the returned error code. A closed file reports
356   `errc::bad_file_descriptor`. 325   `errc::bad_file_descriptor`.
357   326  
358   @param new_size The new file size. 327   @param new_size The new file size.
359   328  
360   @return The error code, empty on success. 329   @return The error code, empty on success.
361   */ 330   */
362   [[nodiscard]] std::error_code resize(std::uint64_t new_size) noexcept; 331   [[nodiscard]] std::error_code resize(std::uint64_t new_size) noexcept;
363   332  
364   /** Synchronize file data to stable storage. 333   /** Synchronize file data to stable storage.
365   334  
366   Write-back failures such as device I/O errors surface here 335   Write-back failures such as device I/O errors surface here
367   and are reported through the returned error code. A closed 336   and are reported through the returned error code. A closed
368   file reports `errc::bad_file_descriptor`. 337   file reports `errc::bad_file_descriptor`.
369   338  
370   @return The error code, empty on success. 339   @return The error code, empty on success.
371   */ 340   */
372   [[nodiscard]] std::error_code sync_data() noexcept; 341   [[nodiscard]] std::error_code sync_data() noexcept;
373   342  
374   /** Synchronize file data and metadata to stable storage. 343   /** Synchronize file data and metadata to stable storage.
375   344  
376   Write-back failures such as device I/O errors surface here 345   Write-back failures such as device I/O errors surface here
377   and are reported through the returned error code. A closed 346   and are reported through the returned error code. A closed
378   file reports `errc::bad_file_descriptor`. 347   file reports `errc::bad_file_descriptor`.
379   348  
380   @return The error code, empty on success. 349   @return The error code, empty on success.
381   */ 350   */
382   [[nodiscard]] std::error_code sync_all() noexcept; 351   [[nodiscard]] std::error_code sync_all() noexcept;
383   352  
384   /** Release ownership of the native handle. 353   /** Release ownership of the native handle.
385   354  
386   The file object becomes not-open. The caller is 355   The file object becomes not-open. The caller is
387   responsible for closing the returned handle. 356   responsible for closing the returned handle.
388   357  
389   @return The native file descriptor or handle. 358   @return The native file descriptor or handle.
390   359  
391   @throws std::system_error `errc::bad_file_descriptor` if the 360   @throws std::system_error `errc::bad_file_descriptor` if the
392   file is not open. 361   file is not open.
393   */ 362   */
394   native_handle_type release(); 363   native_handle_type release();
395   364  
396   /** Adopt an existing native handle. 365   /** Adopt an existing native handle.
397   366  
398   Closes any currently open file before adopting. 367   Closes any currently open file before adopting.
399   The file object takes ownership of the handle. Handles 368   The file object takes ownership of the handle. Handles
400   created elsewhere may be unsuitable for asynchronous I/O; 369   created elsewhere may be unsuitable for asynchronous I/O;
401   such failures are reported through the returned error code. 370   such failures are reported through the returned error code.
402   371  
403   @param handle The native file descriptor or handle. 372   @param handle The native file descriptor or handle.
404   373  
405   @return The error code, empty on success. 374   @return The error code, empty on success.
406   */ 375   */
407   [[nodiscard]] std::error_code assign(native_handle_type handle) noexcept; 376   [[nodiscard]] std::error_code assign(native_handle_type handle) noexcept;
408   377  
409   protected: 378   protected:
410   /// Construct from a pre-built handle (for native_random_access_file). 379   /// Construct from a pre-built handle (for native_random_access_file).
HITCBC 411   16 explicit random_access_file(handle h) noexcept : io_object(std::move(h)) {} 380   16 explicit random_access_file(handle h) noexcept : io_object(std::move(h)) {}
412   381  
413   private: 382   private:
HITCBC 414   1171 inline implementation& get() const noexcept 383   1765 inline implementation& get() const noexcept
415   { 384   {
HITCBC 416   1171 return *static_cast<implementation*>(h_.get()); 385   1765 return *static_cast<implementation*>(h_.get());
417   } 386   }
418   }; 387   };
419   388  
420   } // namespace boost::corosio 389   } // namespace boost::corosio
421   390  
422   #endif // BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP 391   #endif // BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP