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