Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:05

0001 //
0002 // basic_random_access_file.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
0012 #define BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #if defined(BOOST_ASIO_HAS_FILE) \
0021   || defined(GENERATING_DOCUMENTATION)
0022 
0023 #include <cstddef>
0024 #include <boost/asio/async_result.hpp>
0025 #include <boost/asio/basic_file.hpp>
0026 #include <boost/asio/detail/handler_type_requirements.hpp>
0027 #include <boost/asio/detail/non_const_lvalue.hpp>
0028 #include <boost/asio/detail/throw_error.hpp>
0029 #include <boost/asio/error.hpp>
0030 
0031 #include <boost/asio/detail/push_options.hpp>
0032 
0033 namespace boost {
0034 namespace asio {
0035 
0036 #if !defined(BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL)
0037 #define BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL
0038 
0039 // Forward declaration with defaulted arguments.
0040 template <typename Executor = any_io_executor>
0041 class basic_random_access_file;
0042 
0043 #endif // !defined(BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL)
0044 
0045 /// Provides random-access file functionality.
0046 /**
0047  * The basic_random_access_file class template provides asynchronous and
0048  * blocking random-access file functionality.
0049  *
0050  * @par Thread Safety
0051  * @e Distinct @e objects: Safe.@n
0052  * @e Shared @e objects: Unsafe.
0053  *
0054  * Synchronous @c read_some_at and @c write_some_at operations are thread safe
0055  * with respect to each other, if the underlying operating system calls are
0056  * also thread safe. This means that it is permitted to perform concurrent
0057  * calls to these synchronous operations on a single file object. Other
0058  * synchronous operations, such as @c open or @c close, are not thread safe.
0059  */
0060 template <typename Executor>
0061 class basic_random_access_file
0062   : public basic_file<Executor>
0063 {
0064 private:
0065   class initiate_async_write_some_at;
0066   class initiate_async_read_some_at;
0067 
0068 public:
0069   /// The type of the executor associated with the object.
0070   typedef Executor executor_type;
0071 
0072   /// Rebinds the file type to another executor.
0073   template <typename Executor1>
0074   struct rebind_executor
0075   {
0076     /// The file type when rebound to the specified executor.
0077     typedef basic_random_access_file<Executor1> other;
0078   };
0079 
0080   /// The native representation of a file.
0081 #if defined(GENERATING_DOCUMENTATION)
0082   typedef implementation_defined native_handle_type;
0083 #else
0084   typedef typename basic_file<Executor>::native_handle_type native_handle_type;
0085 #endif
0086 
0087   /// Construct a basic_random_access_file without opening it.
0088   /**
0089    * This constructor initialises a file without opening it. The file needs to
0090    * be opened before data can be read from or or written to it.
0091    *
0092    * @param ex The I/O executor that the file will use, by default, to
0093    * dispatch handlers for any asynchronous operations performed on the file.
0094    */
0095   explicit basic_random_access_file(const executor_type& ex)
0096     : basic_file<Executor>(ex)
0097   {
0098   }
0099 
0100   /// Construct a basic_random_access_file without opening it.
0101   /**
0102    * This constructor initialises a file without opening it. The file needs to
0103    * be opened before data can be read from or or written to it.
0104    *
0105    * @param context An execution context which provides the I/O executor that
0106    * the file will use, by default, to dispatch handlers for any asynchronous
0107    * operations performed on the file.
0108    */
0109   template <typename ExecutionContext>
0110   explicit basic_random_access_file(ExecutionContext& context,
0111       constraint_t<
0112         is_convertible<ExecutionContext&, execution_context&>::value,
0113         defaulted_constraint
0114       > = defaulted_constraint())
0115     : basic_file<Executor>(context)
0116   {
0117   }
0118 
0119   /// Construct and open a basic_random_access_file.
0120   /**
0121    * This constructor initialises and opens a file.
0122    *
0123    * @param ex The I/O executor that the file will use, by default, to
0124    * dispatch handlers for any asynchronous operations performed on the file.
0125    *
0126    * @param path The path name identifying the file to be opened.
0127    *
0128    * @param open_flags A set of flags that determine how the file should be
0129    * opened.
0130    *
0131    * @throws boost::system::system_error Thrown on failure.
0132    */
0133   basic_random_access_file(const executor_type& ex,
0134       const char* path, file_base::flags open_flags)
0135     : basic_file<Executor>(ex, path, open_flags)
0136   {
0137   }
0138 
0139   /// Construct and open a basic_random_access_file.
0140   /**
0141    * This constructor initialises and opens a file.
0142    *
0143    * @param context An execution context which provides the I/O executor that
0144    * the file will use, by default, to dispatch handlers for any asynchronous
0145    * operations performed on the file.
0146    *
0147    * @param path The path name identifying the file to be opened.
0148    *
0149    * @param open_flags A set of flags that determine how the file should be
0150    * opened.
0151    *
0152    * @throws boost::system::system_error Thrown on failure.
0153    */
0154   template <typename ExecutionContext>
0155   basic_random_access_file(ExecutionContext& context,
0156       const char* path, file_base::flags open_flags,
0157       constraint_t<
0158         is_convertible<ExecutionContext&, execution_context&>::value,
0159         defaulted_constraint
0160       > = defaulted_constraint())
0161     : basic_file<Executor>(context, path, open_flags)
0162   {
0163   }
0164 
0165   /// Construct and open a basic_random_access_file.
0166   /**
0167    * This constructor initialises and opens a file.
0168    *
0169    * @param ex The I/O executor that the file will use, by default, to
0170    * dispatch handlers for any asynchronous operations performed on the file.
0171    *
0172    * @param path The path name identifying the file to be opened.
0173    *
0174    * @param open_flags A set of flags that determine how the file should be
0175    * opened.
0176    *
0177    * @throws boost::system::system_error Thrown on failure.
0178    */
0179   basic_random_access_file(const executor_type& ex,
0180       const std::string& path, file_base::flags open_flags)
0181     : basic_file<Executor>(ex, path, open_flags)
0182   {
0183   }
0184 
0185   /// Construct and open a basic_random_access_file.
0186   /**
0187    * This constructor initialises and opens a file.
0188    *
0189    * @param context An execution context which provides the I/O executor that
0190    * the file will use, by default, to dispatch handlers for any asynchronous
0191    * operations performed on the file.
0192    *
0193    * @param path The path name identifying the file to be opened.
0194    *
0195    * @param open_flags A set of flags that determine how the file should be
0196    * opened.
0197    *
0198    * @throws boost::system::system_error Thrown on failure.
0199    */
0200   template <typename ExecutionContext>
0201   basic_random_access_file(ExecutionContext& context,
0202       const std::string& path, file_base::flags open_flags,
0203       constraint_t<
0204         is_convertible<ExecutionContext&, execution_context&>::value,
0205         defaulted_constraint
0206       > = defaulted_constraint())
0207     : basic_file<Executor>(context, path, open_flags)
0208   {
0209   }
0210 
0211   /// Construct a basic_random_access_file on an existing native file.
0212   /**
0213    * This constructor initialises a random-access file object to hold an
0214    * existing native file.
0215    *
0216    * @param ex The I/O executor that the file will use, by default, to
0217    * dispatch handlers for any asynchronous operations performed on the file.
0218    *
0219    * @param native_file The new underlying file implementation.
0220    *
0221    * @throws boost::system::system_error Thrown on failure.
0222    */
0223   basic_random_access_file(const executor_type& ex,
0224       const native_handle_type& native_file)
0225     : basic_file<Executor>(ex, native_file)
0226   {
0227   }
0228 
0229   /// Construct a basic_random_access_file on an existing native file.
0230   /**
0231    * This constructor initialises a random-access file object to hold an
0232    * existing native file.
0233    *
0234    * @param context An execution context which provides the I/O executor that
0235    * the file will use, by default, to dispatch handlers for any asynchronous
0236    * operations performed on the file.
0237    *
0238    * @param native_file The new underlying file implementation.
0239    *
0240    * @throws boost::system::system_error Thrown on failure.
0241    */
0242   template <typename ExecutionContext>
0243   basic_random_access_file(ExecutionContext& context,
0244       const native_handle_type& native_file,
0245       constraint_t<
0246         is_convertible<ExecutionContext&, execution_context&>::value,
0247         defaulted_constraint
0248       > = defaulted_constraint())
0249     : basic_file<Executor>(context, native_file)
0250   {
0251   }
0252 
0253   /// Move-construct a basic_random_access_file from another.
0254   /**
0255    * This constructor moves a random-access file from one object to another.
0256    *
0257    * @param other The other basic_random_access_file object from which the move
0258    * will occur.
0259    *
0260    * @note Following the move, the moved-from object is in the same state as if
0261    * constructed using the @c basic_random_access_file(const executor_type&)
0262    * constructor.
0263    */
0264   basic_random_access_file(basic_random_access_file&& other) noexcept
0265     : basic_file<Executor>(std::move(other))
0266   {
0267   }
0268 
0269   /// Move-assign a basic_random_access_file from another.
0270   /**
0271    * This assignment operator moves a random-access file from one object to
0272    * another.
0273    *
0274    * @param other The other basic_random_access_file object from which the move
0275    * will occur.
0276    *
0277    * @note Following the move, the moved-from object is in the same state as if
0278    * constructed using the @c basic_random_access_file(const executor_type&)
0279    * constructor.
0280    */
0281   basic_random_access_file& operator=(basic_random_access_file&& other)
0282   {
0283     basic_file<Executor>::operator=(std::move(other));
0284     return *this;
0285   }
0286 
0287   /// Move-construct a basic_random_access_file from a file of another executor
0288   /// type.
0289   /**
0290    * This constructor moves a random-access file from one object to another.
0291    *
0292    * @param other The other basic_random_access_file object from which the move
0293    * will occur.
0294    *
0295    * @note Following the move, the moved-from object is in the same state as if
0296    * constructed using the @c basic_random_access_file(const executor_type&)
0297    * constructor.
0298    */
0299   template <typename Executor1>
0300   basic_random_access_file(basic_random_access_file<Executor1>&& other,
0301       constraint_t<
0302         is_convertible<Executor1, Executor>::value,
0303         defaulted_constraint
0304       > = defaulted_constraint())
0305     : basic_file<Executor>(std::move(other))
0306   {
0307   }
0308 
0309   /// Move-assign a basic_random_access_file from a file of another executor
0310   /// type.
0311   /**
0312    * This assignment operator moves a random-access file from one object to
0313    * another.
0314    *
0315    * @param other The other basic_random_access_file object from which the move
0316    * will occur.
0317    *
0318    * @note Following the move, the moved-from object is in the same state as if
0319    * constructed using the @c basic_random_access_file(const executor_type&)
0320    * constructor.
0321    */
0322   template <typename Executor1>
0323   constraint_t<
0324     is_convertible<Executor1, Executor>::value,
0325     basic_random_access_file&
0326   > operator=(basic_random_access_file<Executor1>&& other)
0327   {
0328     basic_file<Executor>::operator=(std::move(other));
0329     return *this;
0330   }
0331 
0332   /// Destroys the file.
0333   /**
0334    * This function destroys the file, cancelling any outstanding asynchronous
0335    * operations associated with the file as if by calling @c cancel.
0336    */
0337   ~basic_random_access_file()
0338   {
0339   }
0340 
0341   /// Write some data to the handle at the specified offset.
0342   /**
0343    * This function is used to write data to the random-access handle. The
0344    * function call will block until one or more bytes of the data has been
0345    * written successfully, or until an error occurs.
0346    *
0347    * @param offset The offset at which the data will be written.
0348    *
0349    * @param buffers One or more data buffers to be written to the handle.
0350    *
0351    * @returns The number of bytes written.
0352    *
0353    * @throws boost::system::system_error Thrown on failure. An error code of
0354    * boost::asio::error::eof indicates that the end of the file was reached.
0355    *
0356    * @note The write_some_at operation may not write all of the data. Consider
0357    * using the @ref write_at function if you need to ensure that all data is
0358    * written before the blocking operation completes.
0359    *
0360    * @par Example
0361    * To write a single data buffer use the @ref buffer function as follows:
0362    * @code
0363    * handle.write_some_at(42, boost::asio::buffer(data, size));
0364    * @endcode
0365    * See the @ref buffer documentation for information on writing multiple
0366    * buffers in one go, and how to use it with arrays, boost::array or
0367    * std::vector.
0368    */
0369   template <typename ConstBufferSequence>
0370   std::size_t write_some_at(uint64_t offset,
0371       const ConstBufferSequence& buffers)
0372   {
0373     boost::system::error_code ec;
0374     std::size_t s = this->impl_.get_service().write_some_at(
0375         this->impl_.get_implementation(), offset, buffers, ec);
0376     boost::asio::detail::throw_error(ec, "write_some_at");
0377     return s;
0378   }
0379 
0380   /// Write some data to the handle at the specified offset.
0381   /**
0382    * This function is used to write data to the random-access handle. The
0383    * function call will block until one or more bytes of the data has been
0384    * written successfully, or until an error occurs.
0385    *
0386    * @param offset The offset at which the data will be written.
0387    *
0388    * @param buffers One or more data buffers to be written to the handle.
0389    *
0390    * @param ec Set to indicate what error occurred, if any.
0391    *
0392    * @returns The number of bytes written. Returns 0 if an error occurred.
0393    *
0394    * @note The write_some operation may not write all of the data to the
0395    * file. Consider using the @ref write_at function if you need to ensure that
0396    * all data is written before the blocking operation completes.
0397    */
0398   template <typename ConstBufferSequence>
0399   std::size_t write_some_at(uint64_t offset,
0400       const ConstBufferSequence& buffers, boost::system::error_code& ec)
0401   {
0402     return this->impl_.get_service().write_some_at(
0403         this->impl_.get_implementation(), offset, buffers, ec);
0404   }
0405 
0406   /// Start an asynchronous write at the specified offset.
0407   /**
0408    * This function is used to asynchronously write data to the random-access
0409    * handle. It is an initiating function for an @ref asynchronous_operation,
0410    * and always returns immediately.
0411    *
0412    * @param offset The offset at which the data will be written.
0413    *
0414    * @param buffers One or more data buffers to be written to the handle.
0415    * Although the buffers object may be copied as necessary, ownership of the
0416    * underlying memory blocks is retained by the caller, which must guarantee
0417    * that they remain valid until the completion handler is called.
0418    *
0419    * @param token The @ref completion_token that will be used to produce a
0420    * completion handler, which will be called when the write completes.
0421    * Potential completion tokens include @ref use_future, @ref use_awaitable,
0422    * @ref yield_context, or a function object with the correct completion
0423    * signature. The function signature of the completion handler must be:
0424    * @code void handler(
0425    *   const boost::system::error_code& error, // Result of operation.
0426    *   std::size_t bytes_transferred // Number of bytes written.
0427    * ); @endcode
0428    * Regardless of whether the asynchronous operation completes immediately or
0429    * not, the completion handler will not be invoked from within this function.
0430    * On immediate completion, invocation of the handler will be performed in a
0431    * manner equivalent to using boost::asio::post().
0432    *
0433    * @par Completion Signature
0434    * @code void(boost::system::error_code, std::size_t) @endcode
0435    *
0436    * @note The write operation may not write all of the data to the file.
0437    * Consider using the @ref async_write_at function if you need to ensure that
0438    * all data is written before the asynchronous operation completes.
0439    *
0440    * @par Example
0441    * To write a single data buffer use the @ref buffer function as follows:
0442    * @code
0443    * handle.async_write_some_at(42, boost::asio::buffer(data, size), handler);
0444    * @endcode
0445    * See the @ref buffer documentation for information on writing multiple
0446    * buffers in one go, and how to use it with arrays, boost::array or
0447    * std::vector.
0448    *
0449    * @par Per-Operation Cancellation
0450    * This asynchronous operation supports cancellation for the following
0451    * boost::asio::cancellation_type values:
0452    *
0453    * @li @c cancellation_type::terminal
0454    *
0455    * @li @c cancellation_type::partial
0456    *
0457    * @li @c cancellation_type::total
0458    */
0459   template <typename ConstBufferSequence,
0460       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
0461         std::size_t)) WriteToken = default_completion_token_t<executor_type>>
0462   auto async_write_some_at(uint64_t offset, const ConstBufferSequence& buffers,
0463       WriteToken&& token = default_completion_token_t<executor_type>())
0464     -> decltype(
0465       async_initiate<WriteToken,
0466         void (boost::system::error_code, std::size_t)>(
0467           declval<initiate_async_write_some_at>(), token, offset, buffers))
0468   {
0469     return async_initiate<WriteToken,
0470       void (boost::system::error_code, std::size_t)>(
0471         initiate_async_write_some_at(this), token, offset, buffers);
0472   }
0473 
0474   /// Read some data from the handle at the specified offset.
0475   /**
0476    * This function is used to read data from the random-access handle. The
0477    * function call will block until one or more bytes of data has been read
0478    * successfully, or until an error occurs.
0479    *
0480    * @param offset The offset at which the data will be read.
0481    *
0482    * @param buffers One or more buffers into which the data will be read.
0483    *
0484    * @returns The number of bytes read.
0485    *
0486    * @throws boost::system::system_error Thrown on failure. An error code of
0487    * boost::asio::error::eof indicates that the end of the file was reached.
0488    *
0489    * @note The read_some operation may not read all of the requested number of
0490    * bytes. Consider using the @ref read_at function if you need to ensure that
0491    * the requested amount of data is read before the blocking operation
0492    * completes.
0493    *
0494    * @par Example
0495    * To read into a single data buffer use the @ref buffer function as follows:
0496    * @code
0497    * handle.read_some_at(42, boost::asio::buffer(data, size));
0498    * @endcode
0499    * See the @ref buffer documentation for information on reading into multiple
0500    * buffers in one go, and how to use it with arrays, boost::array or
0501    * std::vector.
0502    */
0503   template <typename MutableBufferSequence>
0504   std::size_t read_some_at(uint64_t offset,
0505       const MutableBufferSequence& buffers)
0506   {
0507     boost::system::error_code ec;
0508     std::size_t s = this->impl_.get_service().read_some_at(
0509         this->impl_.get_implementation(), offset, buffers, ec);
0510     boost::asio::detail::throw_error(ec, "read_some_at");
0511     return s;
0512   }
0513 
0514   /// Read some data from the handle at the specified offset.
0515   /**
0516    * This function is used to read data from the random-access handle. The
0517    * function call will block until one or more bytes of data has been read
0518    * successfully, or until an error occurs.
0519    *
0520    * @param offset The offset at which the data will be read.
0521    *
0522    * @param buffers One or more buffers into which the data will be read.
0523    *
0524    * @param ec Set to indicate what error occurred, if any.
0525    *
0526    * @returns The number of bytes read. Returns 0 if an error occurred.
0527    *
0528    * @note The read_some operation may not read all of the requested number of
0529    * bytes. Consider using the @ref read_at function if you need to ensure that
0530    * the requested amount of data is read before the blocking operation
0531    * completes.
0532    */
0533   template <typename MutableBufferSequence>
0534   std::size_t read_some_at(uint64_t offset,
0535       const MutableBufferSequence& buffers, boost::system::error_code& ec)
0536   {
0537     return this->impl_.get_service().read_some_at(
0538         this->impl_.get_implementation(), offset, buffers, ec);
0539   }
0540 
0541   /// Start an asynchronous read at the specified offset.
0542   /**
0543    * This function is used to asynchronously read data from the random-access
0544    * handle. It is an initiating function for an @ref asynchronous_operation,
0545    * and always returns immediately.
0546    *
0547    * @param offset The offset at which the data will be read.
0548    *
0549    * @param buffers One or more buffers into which the data will be read.
0550    * Although the buffers object may be copied as necessary, ownership of the
0551    * underlying memory blocks is retained by the caller, which must guarantee
0552    * that they remain valid until the completion handler is called.
0553    *
0554    * @param token The @ref completion_token that will be used to produce a
0555    * completion handler, which will be called when the read completes.
0556    * Potential completion tokens include @ref use_future, @ref use_awaitable,
0557    * @ref yield_context, or a function object with the correct completion
0558    * signature. The function signature of the completion handler must be:
0559    * @code void handler(
0560    *   const boost::system::error_code& error, // Result of operation.
0561    *   std::size_t bytes_transferred // Number of bytes read.
0562    * ); @endcode
0563    * Regardless of whether the asynchronous operation completes immediately or
0564    * not, the completion handler will not be invoked from within this function.
0565    * On immediate completion, invocation of the handler will be performed in a
0566    * manner equivalent to using boost::asio::post().
0567    *
0568    * @par Completion Signature
0569    * @code void(boost::system::error_code, std::size_t) @endcode
0570    *
0571    * @note The read operation may not read all of the requested number of bytes.
0572    * Consider using the @ref async_read_at function if you need to ensure that
0573    * the requested amount of data is read before the asynchronous operation
0574    * completes.
0575    *
0576    * @par Example
0577    * To read into a single data buffer use the @ref buffer function as follows:
0578    * @code
0579    * handle.async_read_some_at(42, boost::asio::buffer(data, size), handler);
0580    * @endcode
0581    * See the @ref buffer documentation for information on reading into multiple
0582    * buffers in one go, and how to use it with arrays, boost::array or
0583    * std::vector.
0584    *
0585    * @par Per-Operation Cancellation
0586    * This asynchronous operation supports cancellation for the following
0587    * boost::asio::cancellation_type values:
0588    *
0589    * @li @c cancellation_type::terminal
0590    *
0591    * @li @c cancellation_type::partial
0592    *
0593    * @li @c cancellation_type::total
0594    */
0595   template <typename MutableBufferSequence,
0596       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
0597         std::size_t)) ReadToken = default_completion_token_t<executor_type>>
0598   auto async_read_some_at(uint64_t offset, const MutableBufferSequence& buffers,
0599       ReadToken&& token = default_completion_token_t<executor_type>())
0600     -> decltype(
0601       async_initiate<ReadToken,
0602         void (boost::system::error_code, std::size_t)>(
0603           declval<initiate_async_read_some_at>(), token, offset, buffers))
0604   {
0605     return async_initiate<ReadToken,
0606       void (boost::system::error_code, std::size_t)>(
0607         initiate_async_read_some_at(this), token, offset, buffers);
0608   }
0609 
0610 private:
0611   // Disallow copying and assignment.
0612   basic_random_access_file(const basic_random_access_file&) = delete;
0613   basic_random_access_file& operator=(
0614       const basic_random_access_file&) = delete;
0615 
0616   class initiate_async_write_some_at
0617   {
0618   public:
0619     typedef Executor executor_type;
0620 
0621     explicit initiate_async_write_some_at(basic_random_access_file* self)
0622       : self_(self)
0623     {
0624     }
0625 
0626     const executor_type& get_executor() const noexcept
0627     {
0628       return self_->get_executor();
0629     }
0630 
0631     template <typename WriteHandler, typename ConstBufferSequence>
0632     void operator()(WriteHandler&& handler,
0633         uint64_t offset, const ConstBufferSequence& buffers) const
0634     {
0635       // If you get an error on the following line it means that your handler
0636       // does not meet the documented type requirements for a WriteHandler.
0637       BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
0638 
0639       detail::non_const_lvalue<WriteHandler> handler2(handler);
0640       self_->impl_.get_service().async_write_some_at(
0641           self_->impl_.get_implementation(), offset, buffers,
0642           handler2.value, self_->impl_.get_executor());
0643     }
0644 
0645   private:
0646     basic_random_access_file* self_;
0647   };
0648 
0649   class initiate_async_read_some_at
0650   {
0651   public:
0652     typedef Executor executor_type;
0653 
0654     explicit initiate_async_read_some_at(basic_random_access_file* self)
0655       : self_(self)
0656     {
0657     }
0658 
0659     const executor_type& get_executor() const noexcept
0660     {
0661       return self_->get_executor();
0662     }
0663 
0664     template <typename ReadHandler, typename MutableBufferSequence>
0665     void operator()(ReadHandler&& handler,
0666         uint64_t offset, const MutableBufferSequence& buffers) const
0667     {
0668       // If you get an error on the following line it means that your handler
0669       // does not meet the documented type requirements for a ReadHandler.
0670       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
0671 
0672       detail::non_const_lvalue<ReadHandler> handler2(handler);
0673       self_->impl_.get_service().async_read_some_at(
0674           self_->impl_.get_implementation(), offset, buffers,
0675           handler2.value, self_->impl_.get_executor());
0676     }
0677 
0678   private:
0679     basic_random_access_file* self_;
0680   };
0681 };
0682 
0683 } // namespace asio
0684 } // namespace boost
0685 
0686 #include <boost/asio/detail/pop_options.hpp>
0687 
0688 #endif // defined(BOOST_ASIO_HAS_FILE)
0689        //   || defined(GENERATING_DOCUMENTATION)
0690 
0691 #endif // BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_HPP