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

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