1//
2// basic_random_access_file.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
12#define BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
20#if defined(BOOST_ASIO_HAS_FILE) \
21 || defined(GENERATING_DOCUMENTATION)
22
23#include <cstddef>
24#include <boost/asio/async_result.hpp>
25#include <boost/asio/basic_file.hpp>
26#include <boost/asio/detail/handler_type_requirements.hpp>
27#include <boost/asio/detail/non_const_lvalue.hpp>
28#include <boost/asio/detail/throw_error.hpp>
29#include <boost/asio/error.hpp>
30
31#include <boost/asio/detail/push_options.hpp>
32
33namespace boost {
34namespace asio {
35
36#if !defined(BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL)
37#define BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL
38
39// Forward declaration with defaulted arguments.
40template <typename Executor = any_io_executor>
41class basic_random_access_file;
42
43#endif // !defined(BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL)
44
45/// Provides random-access file functionality.
46/**
47 * The basic_random_access_file class template provides asynchronous and
48 * blocking random-access file functionality.
49 *
50 * @par Thread Safety
51 * @e Distinct @e objects: Safe.@n
52 * @e Shared @e objects: Unsafe.
53 *
54 * Synchronous @c read_some_at and @c write_some_at operations are thread safe
55 * with respect to each other, if the underlying operating system calls are
56 * also thread safe. This means that it is permitted to perform concurrent
57 * calls to these synchronous operations on a single file object. Other
58 * synchronous operations, such as @c open or @c close, are not thread safe.
59 */
60template <typename Executor>
61class basic_random_access_file
62 : public basic_file<Executor>
63{
64private:
65 class initiate_async_write_some_at;
66 class initiate_async_read_some_at;
67
68public:
69 /// The type of the executor associated with the object.
70 typedef Executor executor_type;
71
72 /// Rebinds the file type to another executor.
73 template <typename Executor1>
74 struct rebind_executor
75 {
76 /// The file type when rebound to the specified executor.
77 typedef basic_random_access_file<Executor1> other;
78 };
79
80 /// The native representation of a file.
81#if defined(GENERATING_DOCUMENTATION)
82 typedef implementation_defined native_handle_type;
83#else
84 typedef typename basic_file<Executor>::native_handle_type native_handle_type;
85#endif
86
87 /// Construct a basic_random_access_file without opening it.
88 /**
89 * This constructor initialises a file without opening it. The file needs to
90 * be opened before data can be read from or or written to it.
91 *
92 * @param ex The I/O executor that the file will use, by default, to
93 * dispatch handlers for any asynchronous operations performed on the file.
94 */
95 explicit basic_random_access_file(const executor_type& ex)
96 : basic_file<Executor>(ex)
97 {
98 }
99
100 /// Construct a basic_random_access_file without opening it.
101 /**
102 * This constructor initialises a file without opening it. The file needs to
103 * be opened before data can be read from or or written to it.
104 *
105 * @param context An execution context which provides the I/O executor that
106 * the file will use, by default, to dispatch handlers for any asynchronous
107 * operations performed on the file.
108 */
109 template <typename ExecutionContext>
110 explicit basic_random_access_file(ExecutionContext& context,
111 constraint_t<
112 is_convertible<ExecutionContext&, execution_context&>::value,
113 defaulted_constraint
114 > = defaulted_constraint())
115 : basic_file<Executor>(context)
116 {
117 }
118
119 /// Construct and open a basic_random_access_file.
120 /**
121 * This constructor initialises and opens a file.
122 *
123 * @param ex The I/O executor that the file will use, by default, to
124 * dispatch handlers for any asynchronous operations performed on the file.
125 *
126 * @param path The path name identifying the file to be opened.
127 *
128 * @param open_flags A set of flags that determine how the file should be
129 * opened.
130 *
131 * @throws boost::system::system_error Thrown on failure.
132 */
133 basic_random_access_file(const executor_type& ex,
134 const char* path, file_base::flags open_flags)
135 : basic_file<Executor>(ex, path, open_flags)
136 {
137 }
138
139 /// Construct and open a basic_random_access_file.
140 /**
141 * This constructor initialises and opens a file.
142 *
143 * @param context An execution context which provides the I/O executor that
144 * the file will use, by default, to dispatch handlers for any asynchronous
145 * operations performed on the file.
146 *
147 * @param path The path name identifying the file to be opened.
148 *
149 * @param open_flags A set of flags that determine how the file should be
150 * opened.
151 *
152 * @throws boost::system::system_error Thrown on failure.
153 */
154 template <typename ExecutionContext>
155 basic_random_access_file(ExecutionContext& context,
156 const char* path, file_base::flags open_flags,
157 constraint_t<
158 is_convertible<ExecutionContext&, execution_context&>::value,
159 defaulted_constraint
160 > = defaulted_constraint())
161 : basic_file<Executor>(context, path, open_flags)
162 {
163 }
164
165 /// Construct and open a basic_random_access_file.
166 /**
167 * This constructor initialises and opens a file.
168 *
169 * @param ex The I/O executor that the file will use, by default, to
170 * dispatch handlers for any asynchronous operations performed on the file.
171 *
172 * @param path The path name identifying the file to be opened.
173 *
174 * @param open_flags A set of flags that determine how the file should be
175 * opened.
176 *
177 * @throws boost::system::system_error Thrown on failure.
178 */
179 basic_random_access_file(const executor_type& ex,
180 const std::string& path, file_base::flags open_flags)
181 : basic_file<Executor>(ex, path, open_flags)
182 {
183 }
184
185 /// Construct and open a basic_random_access_file.
186 /**
187 * This constructor initialises and opens a file.
188 *
189 * @param context An execution context which provides the I/O executor that
190 * the file will use, by default, to dispatch handlers for any asynchronous
191 * operations performed on the file.
192 *
193 * @param path The path name identifying the file to be opened.
194 *
195 * @param open_flags A set of flags that determine how the file should be
196 * opened.
197 *
198 * @throws boost::system::system_error Thrown on failure.
199 */
200 template <typename ExecutionContext>
201 basic_random_access_file(ExecutionContext& context,
202 const std::string& path, file_base::flags open_flags,
203 constraint_t<
204 is_convertible<ExecutionContext&, execution_context&>::value,
205 defaulted_constraint
206 > = defaulted_constraint())
207 : basic_file<Executor>(context, path, open_flags)
208 {
209 }
210
211 /// Construct a basic_random_access_file on an existing native file.
212 /**
213 * This constructor initialises a random-access file object to hold an
214 * existing native file.
215 *
216 * @param ex The I/O executor that the file will use, by default, to
217 * dispatch handlers for any asynchronous operations performed on the file.
218 *
219 * @param native_file The new underlying file implementation.
220 *
221 * @throws boost::system::system_error Thrown on failure.
222 */
223 basic_random_access_file(const executor_type& ex,
224 const native_handle_type& native_file)
225 : basic_file<Executor>(ex, native_file)
226 {
227 }
228
229 /// Construct a basic_random_access_file on an existing native file.
230 /**
231 * This constructor initialises a random-access file object to hold an
232 * existing native file.
233 *
234 * @param context An execution context which provides the I/O executor that
235 * the file will use, by default, to dispatch handlers for any asynchronous
236 * operations performed on the file.
237 *
238 * @param native_file The new underlying file implementation.
239 *
240 * @throws boost::system::system_error Thrown on failure.
241 */
242 template <typename ExecutionContext>
243 basic_random_access_file(ExecutionContext& context,
244 const native_handle_type& native_file,
245 constraint_t<
246 is_convertible<ExecutionContext&, execution_context&>::value,
247 defaulted_constraint
248 > = defaulted_constraint())
249 : basic_file<Executor>(context, native_file)
250 {
251 }
252
253 /// Move-construct a basic_random_access_file from another.
254 /**
255 * This constructor moves a random-access file from one object to another.
256 *
257 * @param other The other basic_random_access_file object from which the move
258 * will occur.
259 *
260 * @note Following the move, the moved-from object is in the same state as if
261 * constructed using the @c basic_random_access_file(const executor_type&)
262 * constructor.
263 */
264 basic_random_access_file(basic_random_access_file&& other) noexcept
265 : basic_file<Executor>(std::move(other))
266 {
267 }
268
269 /// Move-assign a basic_random_access_file from another.
270 /**
271 * This assignment operator moves a random-access file from one object to
272 * another.
273 *
274 * @param other The other basic_random_access_file object from which the move
275 * will occur.
276 *
277 * @note Following the move, the moved-from object is in the same state as if
278 * constructed using the @c basic_random_access_file(const executor_type&)
279 * constructor.
280 */
281 basic_random_access_file& operator=(basic_random_access_file&& other)
282 {
283 basic_file<Executor>::operator=(std::move(other));
284 return *this;
285 }
286
287 /// Move-construct a basic_random_access_file from a file of another executor
288 /// type.
289 /**
290 * This constructor moves a random-access file from one object to another.
291 *
292 * @param other The other basic_random_access_file object from which the move
293 * will occur.
294 *
295 * @note Following the move, the moved-from object is in the same state as if
296 * constructed using the @c basic_random_access_file(const executor_type&)
297 * constructor.
298 */
299 template <typename Executor1>
300 basic_random_access_file(basic_random_access_file<Executor1>&& other,
301 constraint_t<
302 is_convertible<Executor1, Executor>::value,
303 defaulted_constraint
304 > = defaulted_constraint())
305 : basic_file<Executor>(std::move(other))
306 {
307 }
308
309 /// Move-assign a basic_random_access_file from a file of another executor
310 /// type.
311 /**
312 * This assignment operator moves a random-access file from one object to
313 * another.
314 *
315 * @param other The other basic_random_access_file object from which the move
316 * will occur.
317 *
318 * @note Following the move, the moved-from object is in the same state as if
319 * constructed using the @c basic_random_access_file(const executor_type&)
320 * constructor.
321 */
322 template <typename Executor1>
323 constraint_t<
324 is_convertible<Executor1, Executor>::value,
325 basic_random_access_file&
326 > operator=(basic_random_access_file<Executor1>&& other)
327 {
328 basic_file<Executor>::operator=(std::move(other));
329 return *this;
330 }
331
332 /// Destroys the file.
333 /**
334 * This function destroys the file, cancelling any outstanding asynchronous
335 * operations associated with the file as if by calling @c cancel.
336 */
337 ~basic_random_access_file()
338 {
339 }
340
341 /// Write some data to the handle at the specified offset.
342 /**
343 * This function is used to write data to the random-access handle. The
344 * function call will block until one or more bytes of the data has been
345 * written successfully, or until an error occurs.
346 *
347 * @param offset The offset at which the data will be written.
348 *
349 * @param buffers One or more data buffers to be written to the handle.
350 *
351 * @returns The number of bytes written.
352 *
353 * @throws boost::system::system_error Thrown on failure. An error code of
354 * boost::asio::error::eof indicates that the end of the file was reached.
355 *
356 * @note The write_some_at operation may not write all of the data. Consider
357 * using the @ref write_at function if you need to ensure that all data is
358 * written before the blocking operation completes.
359 *
360 * @par Example
361 * To write a single data buffer use the @ref buffer function as follows:
362 * @code
363 * handle.write_some_at(42, boost::asio::buffer(data, size));
364 * @endcode
365 * See the @ref buffer documentation for information on writing multiple
366 * buffers in one go, and how to use it with arrays, boost::array or
367 * std::vector.
368 */
369 template <typename ConstBufferSequence>
370 std::size_t write_some_at(uint64_t offset,
371 const ConstBufferSequence& buffers)
372 {
373 boost::system::error_code ec;
374 std::size_t s = this->impl_.get_service().write_some_at(
375 this->impl_.get_implementation(), offset, buffers, ec);
376 boost::asio::detail::throw_error(ec, "write_some_at");
377 return s;
378 }
379
380 /// Write some data to the handle at the specified offset.
381 /**
382 * This function is used to write data to the random-access handle. The
383 * function call will block until one or more bytes of the data has been
384 * written successfully, or until an error occurs.
385 *
386 * @param offset The offset at which the data will be written.
387 *
388 * @param buffers One or more data buffers to be written to the handle.
389 *
390 * @param ec Set to indicate what error occurred, if any.
391 *
392 * @returns The number of bytes written. Returns 0 if an error occurred.
393 *
394 * @note The write_some operation may not write all of the data to the
395 * file. Consider using the @ref write_at function if you need to ensure that
396 * all data is written before the blocking operation completes.
397 */
398 template <typename ConstBufferSequence>
399 std::size_t write_some_at(uint64_t offset,
400 const ConstBufferSequence& buffers, boost::system::error_code& ec)
401 {
402 return this->impl_.get_service().write_some_at(
403 this->impl_.get_implementation(), offset, buffers, ec);
404 }
405
406 /// Start an asynchronous write at the specified offset.
407 /**
408 * This function is used to asynchronously write data to the random-access
409 * handle. It is an initiating function for an @ref asynchronous_operation,
410 * and always returns immediately.
411 *
412 * @param offset The offset at which the data will be written.
413 *
414 * @param buffers One or more data buffers to be written to the handle.
415 * Although the buffers object may be copied as necessary, ownership of the
416 * underlying memory blocks is retained by the caller, which must guarantee
417 * that they remain valid until the completion handler is called.
418 *
419 * @param token The @ref completion_token that will be used to produce a
420 * completion handler, which will be called when the write completes.
421 * Potential completion tokens include @ref use_future, @ref use_awaitable,
422 * @ref yield_context, or a function object with the correct completion
423 * signature. The function signature of the completion handler must be:
424 * @code void handler(
425 * const boost::system::error_code& error, // Result of operation.
426 * std::size_t bytes_transferred // Number of bytes written.
427 * ); @endcode
428 * Regardless of whether the asynchronous operation completes immediately or
429 * not, the completion handler will not be invoked from within this function.
430 * On immediate completion, invocation of the handler will be performed in a
431 * manner equivalent to using boost::asio::post().
432 *
433 * @par Completion Signature
434 * @code void(boost::system::error_code, std::size_t) @endcode
435 *
436 * @note The write operation may not write all of the data to the file.
437 * Consider using the @ref async_write_at function if you need to ensure that
438 * all data is written before the asynchronous operation completes.
439 *
440 * @par Example
441 * To write a single data buffer use the @ref buffer function as follows:
442 * @code
443 * handle.async_write_some_at(42, boost::asio::buffer(data, size), handler);
444 * @endcode
445 * See the @ref buffer documentation for information on writing multiple
446 * buffers in one go, and how to use it with arrays, boost::array or
447 * std::vector.
448 *
449 * @par Per-Operation Cancellation
450 * This asynchronous operation supports cancellation for the following
451 * boost::asio::cancellation_type values:
452 *
453 * @li @c cancellation_type::terminal
454 *
455 * @li @c cancellation_type::partial
456 *
457 * @li @c cancellation_type::total
458 */
459 template <typename ConstBufferSequence,
460 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
461 std::size_t)) WriteToken = default_completion_token_t<executor_type>>
462 auto async_write_some_at(uint64_t offset, const ConstBufferSequence& buffers,
463 WriteToken&& token = default_completion_token_t<executor_type>())
464 -> decltype(
465 async_initiate<WriteToken,
466 void (boost::system::error_code, std::size_t)>(
467 declval<initiate_async_write_some_at>(), token, offset, buffers))
468 {
469 return async_initiate<WriteToken,
470 void (boost::system::error_code, std::size_t)>(
471 initiate_async_write_some_at(this), token, offset, buffers);
472 }
473
474 /// Read some data from the handle at the specified offset.
475 /**
476 * This function is used to read data from the random-access handle. The
477 * function call will block until one or more bytes of data has been read
478 * successfully, or until an error occurs.
479 *
480 * @param offset The offset at which the data will be read.
481 *
482 * @param buffers One or more buffers into which the data will be read.
483 *
484 * @returns The number of bytes read.
485 *
486 * @throws boost::system::system_error Thrown on failure. An error code of
487 * boost::asio::error::eof indicates that the end of the file was reached.
488 *
489 * @note The read_some operation may not read all of the requested number of
490 * bytes. Consider using the @ref read_at function if you need to ensure that
491 * the requested amount of data is read before the blocking operation
492 * completes.
493 *
494 * @par Example
495 * To read into a single data buffer use the @ref buffer function as follows:
496 * @code
497 * handle.read_some_at(42, boost::asio::buffer(data, size));
498 * @endcode
499 * See the @ref buffer documentation for information on reading into multiple
500 * buffers in one go, and how to use it with arrays, boost::array or
501 * std::vector.
502 */
503 template <typename MutableBufferSequence>
504 std::size_t read_some_at(uint64_t offset,
505 const MutableBufferSequence& buffers)
506 {
507 boost::system::error_code ec;
508 std::size_t s = this->impl_.get_service().read_some_at(
509 this->impl_.get_implementation(), offset, buffers, ec);
510 boost::asio::detail::throw_error(ec, "read_some_at");
511 return s;
512 }
513
514 /// Read some data from the handle at the specified offset.
515 /**
516 * This function is used to read data from the random-access handle. The
517 * function call will block until one or more bytes of data has been read
518 * successfully, or until an error occurs.
519 *
520 * @param offset The offset at which the data will be read.
521 *
522 * @param buffers One or more buffers into which the data will be read.
523 *
524 * @param ec Set to indicate what error occurred, if any.
525 *
526 * @returns The number of bytes read. Returns 0 if an error occurred.
527 *
528 * @note The read_some operation may not read all of the requested number of
529 * bytes. Consider using the @ref read_at function if you need to ensure that
530 * the requested amount of data is read before the blocking operation
531 * completes.
532 */
533 template <typename MutableBufferSequence>
534 std::size_t read_some_at(uint64_t offset,
535 const MutableBufferSequence& buffers, boost::system::error_code& ec)
536 {
537 return this->impl_.get_service().read_some_at(
538 this->impl_.get_implementation(), offset, buffers, ec);
539 }
540
541 /// Start an asynchronous read at the specified offset.
542 /**
543 * This function is used to asynchronously read data from the random-access
544 * handle. It is an initiating function for an @ref asynchronous_operation,
545 * and always returns immediately.
546 *
547 * @param offset The offset at which the data will be read.
548 *
549 * @param buffers One or more buffers into which the data will be read.
550 * Although the buffers object may be copied as necessary, ownership of the
551 * underlying memory blocks is retained by the caller, which must guarantee
552 * that they remain valid until the completion handler is called.
553 *
554 * @param token The @ref completion_token that will be used to produce a
555 * completion handler, which will be called when the read completes.
556 * Potential completion tokens include @ref use_future, @ref use_awaitable,
557 * @ref yield_context, or a function object with the correct completion
558 * signature. The function signature of the completion handler must be:
559 * @code void handler(
560 * const boost::system::error_code& error, // Result of operation.
561 * std::size_t bytes_transferred // Number of bytes read.
562 * ); @endcode
563 * Regardless of whether the asynchronous operation completes immediately or
564 * not, the completion handler will not be invoked from within this function.
565 * On immediate completion, invocation of the handler will be performed in a
566 * manner equivalent to using boost::asio::post().
567 *
568 * @par Completion Signature
569 * @code void(boost::system::error_code, std::size_t) @endcode
570 *
571 * @note The read operation may not read all of the requested number of bytes.
572 * Consider using the @ref async_read_at function if you need to ensure that
573 * the requested amount of data is read before the asynchronous operation
574 * completes.
575 *
576 * @par Example
577 * To read into a single data buffer use the @ref buffer function as follows:
578 * @code
579 * handle.async_read_some_at(42, boost::asio::buffer(data, size), handler);
580 * @endcode
581 * See the @ref buffer documentation for information on reading into multiple
582 * buffers in one go, and how to use it with arrays, boost::array or
583 * std::vector.
584 *
585 * @par Per-Operation Cancellation
586 * This asynchronous operation supports cancellation for the following
587 * boost::asio::cancellation_type values:
588 *
589 * @li @c cancellation_type::terminal
590 *
591 * @li @c cancellation_type::partial
592 *
593 * @li @c cancellation_type::total
594 */
595 template <typename MutableBufferSequence,
596 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
597 std::size_t)) ReadToken = default_completion_token_t<executor_type>>
598 auto async_read_some_at(uint64_t offset, const MutableBufferSequence& buffers,
599 ReadToken&& token = default_completion_token_t<executor_type>())
600 -> decltype(
601 async_initiate<ReadToken,
602 void (boost::system::error_code, std::size_t)>(
603 declval<initiate_async_read_some_at>(), token, offset, buffers))
604 {
605 return async_initiate<ReadToken,
606 void (boost::system::error_code, std::size_t)>(
607 initiate_async_read_some_at(this), token, offset, buffers);
608 }
609
610private:
611 // Disallow copying and assignment.
612 basic_random_access_file(const basic_random_access_file&) = delete;
613 basic_random_access_file& operator=(
614 const basic_random_access_file&) = delete;
615
616 class initiate_async_write_some_at
617 {
618 public:
619 typedef Executor executor_type;
620
621 explicit initiate_async_write_some_at(basic_random_access_file* self)
622 : self_(self)
623 {
624 }
625
626 const executor_type& get_executor() const noexcept
627 {
628 return self_->get_executor();
629 }
630
631 template <typename WriteHandler, typename ConstBufferSequence>
632 void operator()(WriteHandler&& handler,
633 uint64_t offset, const ConstBufferSequence& buffers) const
634 {
635 // If you get an error on the following line it means that your handler
636 // does not meet the documented type requirements for a WriteHandler.
637 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
638
639 detail::non_const_lvalue<WriteHandler> handler2(handler);
640 self_->impl_.get_service().async_write_some_at(
641 self_->impl_.get_implementation(), offset, buffers,
642 handler2.value, self_->impl_.get_executor());
643 }
644
645 private:
646 basic_random_access_file* self_;
647 };
648
649 class initiate_async_read_some_at
650 {
651 public:
652 typedef Executor executor_type;
653
654 explicit initiate_async_read_some_at(basic_random_access_file* self)
655 : self_(self)
656 {
657 }
658
659 const executor_type& get_executor() const noexcept
660 {
661 return self_->get_executor();
662 }
663
664 template <typename ReadHandler, typename MutableBufferSequence>
665 void operator()(ReadHandler&& handler,
666 uint64_t offset, const MutableBufferSequence& buffers) const
667 {
668 // If you get an error on the following line it means that your handler
669 // does not meet the documented type requirements for a ReadHandler.
670 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
671
672 detail::non_const_lvalue<ReadHandler> handler2(handler);
673 self_->impl_.get_service().async_read_some_at(
674 self_->impl_.get_implementation(), offset, buffers,
675 handler2.value, self_->impl_.get_executor());
676 }
677
678 private:
679 basic_random_access_file* self_;
680 };
681};
682
683} // namespace asio
684} // namespace boost
685
686#include <boost/asio/detail/pop_options.hpp>
687
688#endif // defined(BOOST_ASIO_HAS_FILE)
689 // || defined(GENERATING_DOCUMENTATION)
690
691#endif // BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
692

source code of boost/libs/asio/include/boost/asio/basic_random_access_file.hpp