Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //
0002 // windows/basic_random_access_handle.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_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP
0012 #define BOOST_ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_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 #include <boost/asio/windows/basic_overlapped_handle.hpp>
0020 
0021 #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \
0022   || defined(GENERATING_DOCUMENTATION)
0023 
0024 #include <boost/asio/detail/push_options.hpp>
0025 
0026 namespace boost {
0027 namespace asio {
0028 namespace windows {
0029 
0030 /// Provides random-access handle functionality.
0031 /**
0032  * The windows::basic_random_access_handle class provides asynchronous and
0033  * blocking random-access handle functionality.
0034  *
0035  * @par Thread Safety
0036  * @e Distinct @e objects: Safe.@n
0037  * @e Shared @e objects: Unsafe.
0038  */
0039 template <typename Executor = any_io_executor>
0040 class basic_random_access_handle
0041   : public basic_overlapped_handle<Executor>
0042 {
0043 private:
0044   class initiate_async_write_some_at;
0045   class initiate_async_read_some_at;
0046 
0047 public:
0048   /// The type of the executor associated with the object.
0049   typedef Executor executor_type;
0050 
0051   /// Rebinds the handle type to another executor.
0052   template <typename Executor1>
0053   struct rebind_executor
0054   {
0055     /// The handle type when rebound to the specified executor.
0056     typedef basic_random_access_handle<Executor1> other;
0057   };
0058 
0059   /// The native representation of a handle.
0060 #if defined(GENERATING_DOCUMENTATION)
0061   typedef implementation_defined native_handle_type;
0062 #else
0063   typedef boost::asio::detail::win_iocp_handle_service::native_handle_type
0064     native_handle_type;
0065 #endif
0066 
0067   /// Construct a random-access handle without opening it.
0068   /**
0069    * This constructor creates a random-access handle without opening it.
0070    *
0071    * @param ex The I/O executor that the random-access handle will use, by
0072    * default, to dispatch handlers for any asynchronous operations performed on
0073    * the random-access handle.
0074    */
0075   explicit basic_random_access_handle(const executor_type& ex)
0076     : basic_overlapped_handle<Executor>(ex)
0077   {
0078   }
0079 
0080   /// Construct a random-access handle without opening it.
0081   /**
0082    * This constructor creates a random-access handle without opening it. The
0083    * handle needs to be opened or assigned before data can be written to or read
0084    * from it.
0085    *
0086    * @param context An execution context which provides the I/O executor that
0087    * the random-access handle will use, by default, to dispatch handlers for any
0088    * asynchronous operations performed on the random-access handle.
0089    */
0090   template <typename ExecutionContext>
0091   explicit basic_random_access_handle(ExecutionContext& context,
0092       constraint_t<
0093         is_convertible<ExecutionContext&, execution_context&>::value,
0094         defaulted_constraint
0095       > = defaulted_constraint())
0096     : basic_overlapped_handle<Executor>(context)
0097   {
0098   }
0099 
0100   /// Construct a random-access handle on an existing native handle.
0101   /**
0102    * This constructor creates a random-access handle object to hold an existing
0103    * native handle.
0104    *
0105    * @param ex The I/O executor that the random-access handle will use, by
0106    * default, to dispatch handlers for any asynchronous operations performed on
0107    * the random-access handle.
0108    *
0109    * @param handle The new underlying handle implementation.
0110    *
0111    * @throws boost::system::system_error Thrown on failure.
0112    */
0113   basic_random_access_handle(const executor_type& ex,
0114       const native_handle_type& handle)
0115     : basic_overlapped_handle<Executor>(ex, handle)
0116   {
0117   }
0118 
0119   /// Construct a random-access handle on an existing native handle.
0120   /**
0121    * This constructor creates a random-access handle object to hold an existing
0122    * native handle.
0123    *
0124    * @param context An execution context which provides the I/O executor that
0125    * the random-access handle will use, by default, to dispatch handlers for any
0126    * asynchronous operations performed on the random-access handle.
0127    *
0128    * @param handle The new underlying handle implementation.
0129    *
0130    * @throws boost::system::system_error Thrown on failure.
0131    */
0132   template <typename ExecutionContext>
0133   basic_random_access_handle(ExecutionContext& context,
0134       const native_handle_type& handle,
0135       constraint_t<
0136         is_convertible<ExecutionContext&, execution_context&>::value
0137       > = 0)
0138     : basic_overlapped_handle<Executor>(context, handle)
0139   {
0140   }
0141 
0142   /// Move-construct a random-access handle from another.
0143   /**
0144    * This constructor moves a random-access handle from one object to another.
0145    *
0146    * @param other The other random-access handle object from which the
0147    * move will occur.
0148    *
0149    * @note Following the move, the moved-from object is in the same state as if
0150    * constructed using the @c basic_random_access_handle(const executor_type&)
0151    * constructor.
0152    */
0153   basic_random_access_handle(basic_random_access_handle&& other)
0154     : basic_overlapped_handle<Executor>(std::move(other))
0155   {
0156   }
0157 
0158   /// Move-assign a random-access handle from another.
0159   /**
0160    * This assignment operator moves a random-access handle from one object to
0161    * another.
0162    *
0163    * @param other The other random-access handle object from which the
0164    * move will occur.
0165    *
0166    * @note Following the move, the moved-from object is in the same state as if
0167    * constructed using the @c basic_random_access_handle(const executor_type&)
0168    * constructor.
0169    */
0170   basic_random_access_handle& operator=(basic_random_access_handle&& other)
0171   {
0172     basic_overlapped_handle<Executor>::operator=(std::move(other));
0173     return *this;
0174   }
0175 
0176   /// Move-construct a random-access handle from a handle of another executor
0177   /// type.
0178   /**
0179    * This constructor moves a random-access handle from one object to another.
0180    *
0181    * @param other The other random-access handle object from which the
0182    * move will occur.
0183    *
0184    * @note Following the move, the moved-from object is in the same state as if
0185    * constructed using the @c basic_random_access_handle(const executor_type&)
0186    * constructor.
0187    */
0188   template<typename Executor1>
0189   basic_random_access_handle(basic_random_access_handle<Executor1>&& other,
0190       constraint_t<
0191         is_convertible<Executor1, Executor>::value,
0192         defaulted_constraint
0193       > = defaulted_constraint())
0194     : basic_overlapped_handle<Executor>(std::move(other))
0195   {
0196   }
0197 
0198   /// Move-assign a random-access handle from a handle of another executor
0199   /// type.
0200   /**
0201    * This assignment operator moves a random-access handle from one object to
0202    * another.
0203    *
0204    * @param other The other random-access handle object from which the
0205    * move will occur.
0206    *
0207    * @note Following the move, the moved-from object is in the same state as if
0208    * constructed using the @c basic_random_access_handle(const executor_type&)
0209    * constructor.
0210    */
0211   template<typename Executor1>
0212   constraint_t<
0213     is_convertible<Executor1, Executor>::value,
0214     basic_random_access_handle&
0215   > operator=(basic_random_access_handle<Executor1>&& other)
0216   {
0217     basic_overlapped_handle<Executor>::operator=(std::move(other));
0218     return *this;
0219   }
0220 
0221   /// Write some data to the handle at the specified offset.
0222   /**
0223    * This function is used to write data to the random-access handle. The
0224    * function call will block until one or more bytes of the data has been
0225    * written successfully, or until an error occurs.
0226    *
0227    * @param offset The offset at which the data will be written.
0228    *
0229    * @param buffers One or more data buffers to be written to the handle.
0230    *
0231    * @returns The number of bytes written.
0232    *
0233    * @throws boost::system::system_error Thrown on failure. An error code of
0234    * boost::asio::error::eof indicates that the connection was closed by the
0235    * peer.
0236    *
0237    * @note The write_some_at operation may not write all of the data. Consider
0238    * using the @ref write_at function if you need to ensure that all data is
0239    * written before the blocking operation completes.
0240    *
0241    * @par Example
0242    * To write a single data buffer use the @ref buffer function as follows:
0243    * @code
0244    * handle.write_some_at(42, boost::asio::buffer(data, size));
0245    * @endcode
0246    * See the @ref buffer documentation for information on writing multiple
0247    * buffers in one go, and how to use it with arrays, boost::array or
0248    * std::vector.
0249    */
0250   template <typename ConstBufferSequence>
0251   std::size_t write_some_at(uint64_t offset,
0252       const ConstBufferSequence& buffers)
0253   {
0254     boost::system::error_code ec;
0255     std::size_t s = this->impl_.get_service().write_some_at(
0256         this->impl_.get_implementation(), offset, buffers, ec);
0257     boost::asio::detail::throw_error(ec, "write_some_at");
0258     return s;
0259   }
0260 
0261   /// Write some data to the handle at the specified offset.
0262   /**
0263    * This function is used to write data to the random-access handle. The
0264    * function call will block until one or more bytes of the data has been
0265    * written successfully, or until an error occurs.
0266    *
0267    * @param offset The offset at which the data will be written.
0268    *
0269    * @param buffers One or more data buffers to be written to the handle.
0270    *
0271    * @param ec Set to indicate what error occurred, if any.
0272    *
0273    * @returns The number of bytes written. Returns 0 if an error occurred.
0274    *
0275    * @note The write_some operation may not transmit all of the data to the
0276    * peer. Consider using the @ref write_at function if you need to ensure that
0277    * all data is written before the blocking operation completes.
0278    */
0279   template <typename ConstBufferSequence>
0280   std::size_t write_some_at(uint64_t offset,
0281       const ConstBufferSequence& buffers, boost::system::error_code& ec)
0282   {
0283     return this->impl_.get_service().write_some_at(
0284         this->impl_.get_implementation(), offset, buffers, ec);
0285   }
0286 
0287   /// Start an asynchronous write at the specified offset.
0288   /**
0289    * This function is used to asynchronously write data to the random-access
0290    * handle. It is an initiating function for an @ref asynchronous_operation,
0291    * and always returns immediately.
0292    *
0293    * @param offset The offset at which the data will be written.
0294    *
0295    * @param buffers One or more data buffers to be written to the handle.
0296    * Although the buffers object may be copied as necessary, ownership of the
0297    * underlying memory blocks is retained by the caller, which must guarantee
0298    * that they remain valid until the completion handler is called.
0299    *
0300    * @param token The @ref completion_token that will be used to produce a
0301    * completion handler, which will be called when the write completes.
0302    * Potential completion tokens include @ref use_future, @ref use_awaitable,
0303    * @ref yield_context, or a function object with the correct completion
0304    * signature. The function signature of the completion handler must be:
0305    * @code void handler(
0306    *   const boost::system::error_code& error, // Result of operation.
0307    *   std::size_t bytes_transferred // Number of bytes written.
0308    * ); @endcode
0309    * Regardless of whether the asynchronous operation completes immediately or
0310    * not, the completion handler will not be invoked from within this function.
0311    * On immediate completion, invocation of the handler will be performed in a
0312    * manner equivalent to using boost::asio::post().
0313    *
0314    * @par Completion Signature
0315    * @code void(boost::system::error_code, std::size_t) @endcode
0316    *
0317    * @note The write operation may not transmit all of the data to the peer.
0318    * Consider using the @ref async_write_at function if you need to ensure that
0319    * all data is written before the asynchronous operation completes.
0320    *
0321    * @par Example
0322    * To write a single data buffer use the @ref buffer function as follows:
0323    * @code
0324    * handle.async_write_some_at(42, boost::asio::buffer(data, size), handler);
0325    * @endcode
0326    * See the @ref buffer documentation for information on writing multiple
0327    * buffers in one go, and how to use it with arrays, boost::array or
0328    * std::vector.
0329    *
0330    * @par Per-Operation Cancellation
0331    * This asynchronous operation supports cancellation for the following
0332    * boost::asio::cancellation_type values:
0333    *
0334    * @li @c cancellation_type::terminal
0335    *
0336    * @li @c cancellation_type::partial
0337    *
0338    * @li @c cancellation_type::total
0339    */
0340   template <typename ConstBufferSequence,
0341       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
0342         std::size_t)) WriteToken = default_completion_token_t<executor_type>>
0343   auto async_write_some_at(uint64_t offset, const ConstBufferSequence& buffers,
0344       WriteToken&& token = default_completion_token_t<executor_type>())
0345     -> decltype(
0346       async_initiate<WriteToken,
0347         void (boost::system::error_code, std::size_t)>(
0348           declval<initiate_async_write_some_at>(), token, offset, buffers))
0349   {
0350     return async_initiate<WriteToken,
0351       void (boost::system::error_code, std::size_t)>(
0352         initiate_async_write_some_at(this), token, offset, buffers);
0353   }
0354 
0355   /// Read some data from the handle at the specified offset.
0356   /**
0357    * This function is used to read data from the random-access handle. The
0358    * function call will block until one or more bytes of data has been read
0359    * successfully, or until an error occurs.
0360    *
0361    * @param offset The offset at which the data will be read.
0362    *
0363    * @param buffers One or more buffers into which the data will be read.
0364    *
0365    * @returns The number of bytes read.
0366    *
0367    * @throws boost::system::system_error Thrown on failure. An error code of
0368    * boost::asio::error::eof indicates that the connection was closed by the
0369    * peer.
0370    *
0371    * @note The read_some operation may not read all of the requested number of
0372    * bytes. Consider using the @ref read_at function if you need to ensure that
0373    * the requested amount of data is read before the blocking operation
0374    * completes.
0375    *
0376    * @par Example
0377    * To read into a single data buffer use the @ref buffer function as follows:
0378    * @code
0379    * handle.read_some_at(42, boost::asio::buffer(data, size));
0380    * @endcode
0381    * See the @ref buffer documentation for information on reading into multiple
0382    * buffers in one go, and how to use it with arrays, boost::array or
0383    * std::vector.
0384    */
0385   template <typename MutableBufferSequence>
0386   std::size_t read_some_at(uint64_t offset,
0387       const MutableBufferSequence& buffers)
0388   {
0389     boost::system::error_code ec;
0390     std::size_t s = this->impl_.get_service().read_some_at(
0391         this->impl_.get_implementation(), offset, buffers, ec);
0392     boost::asio::detail::throw_error(ec, "read_some_at");
0393     return s;
0394   }
0395 
0396   /// Read some data from the handle at the specified offset.
0397   /**
0398    * This function is used to read data from the random-access handle. The
0399    * function call will block until one or more bytes of data has been read
0400    * successfully, or until an error occurs.
0401    *
0402    * @param offset The offset at which the data will be read.
0403    *
0404    * @param buffers One or more buffers into which the data will be read.
0405    *
0406    * @param ec Set to indicate what error occurred, if any.
0407    *
0408    * @returns The number of bytes read. Returns 0 if an error occurred.
0409    *
0410    * @note The read_some operation may not read all of the requested number of
0411    * bytes. Consider using the @ref read_at function if you need to ensure that
0412    * the requested amount of data is read before the blocking operation
0413    * completes.
0414    */
0415   template <typename MutableBufferSequence>
0416   std::size_t read_some_at(uint64_t offset,
0417       const MutableBufferSequence& buffers, boost::system::error_code& ec)
0418   {
0419     return this->impl_.get_service().read_some_at(
0420         this->impl_.get_implementation(), offset, buffers, ec);
0421   }
0422 
0423   /// Start an asynchronous read at the specified offset.
0424   /**
0425    * This function is used to asynchronously read data from the random-access
0426    * handle. It is an initiating function for an @ref asynchronous_operation,
0427    * and always returns immediately.
0428    *
0429    * @param offset The offset at which the data will be read.
0430    *
0431    * @param buffers One or more buffers into which the data will be read.
0432    * Although the buffers object may be copied as necessary, ownership of the
0433    * underlying memory blocks is retained by the caller, which must guarantee
0434    * that they remain valid until the completion handler is called.
0435    *
0436    * @param token The @ref completion_token that will be used to produce a
0437    * completion handler, which will be called when the read completes.
0438    * Potential completion tokens include @ref use_future, @ref use_awaitable,
0439    * @ref yield_context, or a function object with the correct completion
0440    * signature. The function signature of the completion handler must be:
0441    * @code void handler(
0442    *   const boost::system::error_code& error, // Result of operation.
0443    *   std::size_t bytes_transferred // Number of bytes read.
0444    * ); @endcode
0445    * Regardless of whether the asynchronous operation completes immediately or
0446    * not, the completion handler will not be invoked from within this function.
0447    * On immediate completion, invocation of the handler will be performed in a
0448    * manner equivalent to using boost::asio::post().
0449    *
0450    * @par Completion Signature
0451    * @code void(boost::system::error_code, std::size_t) @endcode
0452    *
0453    * @note The read operation may not read all of the requested number of bytes.
0454    * Consider using the @ref async_read_at function if you need to ensure that
0455    * the requested amount of data is read before the asynchronous operation
0456    * completes.
0457    *
0458    * @par Example
0459    * To read into a single data buffer use the @ref buffer function as follows:
0460    * @code
0461    * handle.async_read_some_at(42, boost::asio::buffer(data, size), handler);
0462    * @endcode
0463    * See the @ref buffer documentation for information on reading into multiple
0464    * buffers in one go, and how to use it with arrays, boost::array or
0465    * std::vector.
0466    *
0467    * @par Per-Operation Cancellation
0468    * This asynchronous operation supports cancellation for the following
0469    * boost::asio::cancellation_type values:
0470    *
0471    * @li @c cancellation_type::terminal
0472    *
0473    * @li @c cancellation_type::partial
0474    *
0475    * @li @c cancellation_type::total
0476    */
0477   template <typename MutableBufferSequence,
0478       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
0479         std::size_t)) ReadToken = default_completion_token_t<executor_type>>
0480   auto async_read_some_at(uint64_t offset, const MutableBufferSequence& buffers,
0481       ReadToken&& token = default_completion_token_t<executor_type>())
0482     -> decltype(
0483       async_initiate<ReadToken,
0484         void (boost::system::error_code, std::size_t)>(
0485           declval<initiate_async_read_some_at>(), token, offset, buffers))
0486   {
0487     return async_initiate<ReadToken,
0488       void (boost::system::error_code, std::size_t)>(
0489         initiate_async_read_some_at(this), token, offset, buffers);
0490   }
0491 
0492 private:
0493   class initiate_async_write_some_at
0494   {
0495   public:
0496     typedef Executor executor_type;
0497 
0498     explicit initiate_async_write_some_at(basic_random_access_handle* self)
0499       : self_(self)
0500     {
0501     }
0502 
0503     const executor_type& get_executor() const noexcept
0504     {
0505       return self_->get_executor();
0506     }
0507 
0508     template <typename WriteHandler, typename ConstBufferSequence>
0509     void operator()(WriteHandler&& handler,
0510         uint64_t offset, const ConstBufferSequence& buffers) const
0511     {
0512       // If you get an error on the following line it means that your handler
0513       // does not meet the documented type requirements for a WriteHandler.
0514       BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
0515 
0516       detail::non_const_lvalue<WriteHandler> handler2(handler);
0517       self_->impl_.get_service().async_write_some_at(
0518           self_->impl_.get_implementation(), offset, buffers,
0519           handler2.value, self_->impl_.get_executor());
0520     }
0521 
0522   private:
0523     basic_random_access_handle* self_;
0524   };
0525 
0526   class initiate_async_read_some_at
0527   {
0528   public:
0529     typedef Executor executor_type;
0530 
0531     explicit initiate_async_read_some_at(basic_random_access_handle* self)
0532       : self_(self)
0533     {
0534     }
0535 
0536     const executor_type& get_executor() const noexcept
0537     {
0538       return self_->get_executor();
0539     }
0540 
0541     template <typename ReadHandler, typename MutableBufferSequence>
0542     void operator()(ReadHandler&& handler,
0543         uint64_t offset, const MutableBufferSequence& buffers) const
0544     {
0545       // If you get an error on the following line it means that your handler
0546       // does not meet the documented type requirements for a ReadHandler.
0547       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
0548 
0549       detail::non_const_lvalue<ReadHandler> handler2(handler);
0550       self_->impl_.get_service().async_read_some_at(
0551           self_->impl_.get_implementation(), offset, buffers,
0552           handler2.value, self_->impl_.get_executor());
0553     }
0554 
0555   private:
0556     basic_random_access_handle* self_;
0557   };
0558 };
0559 
0560 } // namespace windows
0561 } // namespace asio
0562 } // namespace boost
0563 
0564 #include <boost/asio/detail/pop_options.hpp>
0565 
0566 #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
0567        //   || defined(GENERATING_DOCUMENTATION)
0568 
0569 #endif // BOOST_ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP