Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / asio / impl / read_at.hpp
1 //
2 // impl/read_at.hpp
3 // ~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 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_IMPL_READ_AT_HPP
12 #define BOOST_ASIO_IMPL_READ_AT_HPP
13
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18 #include <algorithm>
19 #include <boost/asio/associated_allocator.hpp>
20 #include <boost/asio/associated_executor.hpp>
21 #include <boost/asio/buffer.hpp>
22 #include <boost/asio/completion_condition.hpp>
23 #include <boost/asio/detail/array_fwd.hpp>
24 #include <boost/asio/detail/base_from_completion_cond.hpp>
25 #include <boost/asio/detail/bind_handler.hpp>
26 #include <boost/asio/detail/consuming_buffers.hpp>
27 #include <boost/asio/detail/dependent_type.hpp>
28 #include <boost/asio/detail/handler_alloc_helpers.hpp>
29 #include <boost/asio/detail/handler_cont_helpers.hpp>
30 #include <boost/asio/detail/handler_invoke_helpers.hpp>
31 #include <boost/asio/detail/handler_type_requirements.hpp>
32 #include <boost/asio/detail/non_const_lvalue.hpp>
33 #include <boost/asio/detail/throw_error.hpp>
34 #include <boost/asio/error.hpp>
35
36 #include <boost/asio/detail/push_options.hpp>
37
38 namespace boost {
39 namespace asio {
40
41 namespace detail
42 {
43   template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
44       typename MutableBufferIterator, typename CompletionCondition>
45   std::size_t read_at_buffer_sequence(SyncRandomAccessReadDevice& d,
46       uint64_t offset, const MutableBufferSequence& buffers,
47       const MutableBufferIterator&, CompletionCondition completion_condition,
48       boost::system::error_code& ec)
49   {
50     ec = boost::system::error_code();
51     boost::asio::detail::consuming_buffers<mutable_buffer,
52         MutableBufferSequence, MutableBufferIterator> tmp(buffers);
53     while (!tmp.empty())
54     {
55       if (std::size_t max_size = detail::adapt_completion_condition_result(
56             completion_condition(ec, tmp.total_consumed())))
57       {
58         tmp.consume(d.read_some_at(offset + tmp.total_consumed(),
59               tmp.prepare(max_size), ec));
60       }
61       else
62         break;
63     }
64     return tmp.total_consumed();;
65   }
66 } // namespace detail
67
68 template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
69     typename CompletionCondition>
70 std::size_t read_at(SyncRandomAccessReadDevice& d,
71     uint64_t offset, const MutableBufferSequence& buffers,
72     CompletionCondition completion_condition, boost::system::error_code& ec)
73 {
74   return detail::read_at_buffer_sequence(d, offset, buffers,
75       boost::asio::buffer_sequence_begin(buffers),
76       BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
77 }
78
79 template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
80 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
81     uint64_t offset, const MutableBufferSequence& buffers)
82 {
83   boost::system::error_code ec;
84   std::size_t bytes_transferred = read_at(
85       d, offset, buffers, transfer_all(), ec);
86   boost::asio::detail::throw_error(ec, "read_at");
87   return bytes_transferred;
88 }
89
90 template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
91 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
92     uint64_t offset, const MutableBufferSequence& buffers,
93     boost::system::error_code& ec)
94 {
95   return read_at(d, offset, buffers, transfer_all(), ec);
96 }
97
98 template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
99     typename CompletionCondition>
100 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
101     uint64_t offset, const MutableBufferSequence& buffers,
102     CompletionCondition completion_condition)
103 {
104   boost::system::error_code ec;
105   std::size_t bytes_transferred = read_at(d, offset, buffers,
106       BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
107   boost::asio::detail::throw_error(ec, "read_at");
108   return bytes_transferred;
109 }
110
111 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
112 #if !defined(BOOST_ASIO_NO_IOSTREAM)
113
114 template <typename SyncRandomAccessReadDevice, typename Allocator,
115     typename CompletionCondition>
116 std::size_t read_at(SyncRandomAccessReadDevice& d,
117     uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
118     CompletionCondition completion_condition, boost::system::error_code& ec)
119 {
120   ec = boost::system::error_code();
121   std::size_t total_transferred = 0;
122   std::size_t max_size = detail::adapt_completion_condition_result(
123         completion_condition(ec, total_transferred));
124   std::size_t bytes_available = read_size_helper(b, max_size);
125   while (bytes_available > 0)
126   {
127     std::size_t bytes_transferred = d.read_some_at(
128         offset + total_transferred, b.prepare(bytes_available), ec);
129     b.commit(bytes_transferred);
130     total_transferred += bytes_transferred;
131     max_size = detail::adapt_completion_condition_result(
132           completion_condition(ec, total_transferred));
133     bytes_available = read_size_helper(b, max_size);
134   }
135   return total_transferred;
136 }
137
138 template <typename SyncRandomAccessReadDevice, typename Allocator>
139 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
140     uint64_t offset, boost::asio::basic_streambuf<Allocator>& b)
141 {
142   boost::system::error_code ec;
143   std::size_t bytes_transferred = read_at(
144       d, offset, b, transfer_all(), ec);
145   boost::asio::detail::throw_error(ec, "read_at");
146   return bytes_transferred;
147 }
148
149 template <typename SyncRandomAccessReadDevice, typename Allocator>
150 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
151     uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
152     boost::system::error_code& ec)
153 {
154   return read_at(d, offset, b, transfer_all(), ec);
155 }
156
157 template <typename SyncRandomAccessReadDevice, typename Allocator,
158     typename CompletionCondition>
159 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
160     uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
161     CompletionCondition completion_condition)
162 {
163   boost::system::error_code ec;
164   std::size_t bytes_transferred = read_at(d, offset, b,
165       BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
166   boost::asio::detail::throw_error(ec, "read_at");
167   return bytes_transferred;
168 }
169
170 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
171 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
172
173 namespace detail
174 {
175   template <typename AsyncRandomAccessReadDevice,
176       typename MutableBufferSequence, typename MutableBufferIterator,
177       typename CompletionCondition, typename ReadHandler>
178   class read_at_op
179     : detail::base_from_completion_cond<CompletionCondition>
180   {
181   public:
182     read_at_op(AsyncRandomAccessReadDevice& device,
183         uint64_t offset, const MutableBufferSequence& buffers,
184         CompletionCondition& completion_condition, ReadHandler& handler)
185       : detail::base_from_completion_cond<
186           CompletionCondition>(completion_condition),
187         device_(device),
188         offset_(offset),
189         buffers_(buffers),
190         start_(0),
191         handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
192     {
193     }
194
195 #if defined(BOOST_ASIO_HAS_MOVE)
196     read_at_op(const read_at_op& other)
197       : detail::base_from_completion_cond<CompletionCondition>(other),
198         device_(other.device_),
199         offset_(other.offset_),
200         buffers_(other.buffers_),
201         start_(other.start_),
202         handler_(other.handler_)
203     {
204     }
205
206     read_at_op(read_at_op&& other)
207       : detail::base_from_completion_cond<CompletionCondition>(
208           BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond<
209             CompletionCondition>)(other)),
210         device_(other.device_),
211         offset_(other.offset_),
212         buffers_(BOOST_ASIO_MOVE_CAST(buffers_type)(other.buffers_)),
213         start_(other.start_),
214         handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
215     {
216     }
217 #endif // defined(BOOST_ASIO_HAS_MOVE)
218
219     void operator()(const boost::system::error_code& ec,
220         std::size_t bytes_transferred, int start = 0)
221     {
222       std::size_t max_size;
223       switch (start_ = start)
224       {
225         case 1:
226         max_size = this->check_for_completion(ec, buffers_.total_consumed());
227         do
228         {
229           device_.async_read_some_at(
230               offset_ + buffers_.total_consumed(), buffers_.prepare(max_size),
231               BOOST_ASIO_MOVE_CAST(read_at_op)(*this));
232           return; default:
233           buffers_.consume(bytes_transferred);
234           if ((!ec && bytes_transferred == 0) || buffers_.empty())
235             break;
236           max_size = this->check_for_completion(ec, buffers_.total_consumed());
237         } while (max_size > 0);
238
239         handler_(ec, buffers_.total_consumed());
240       }
241     }
242
243   //private:
244     typedef boost::asio::detail::consuming_buffers<mutable_buffer,
245         MutableBufferSequence, MutableBufferIterator> buffers_type;
246
247     AsyncRandomAccessReadDevice& device_;
248     uint64_t offset_;
249     buffers_type buffers_;
250     int start_;
251     ReadHandler handler_;
252   };
253
254   template <typename AsyncRandomAccessReadDevice,
255       typename MutableBufferSequence, typename MutableBufferIterator,
256       typename CompletionCondition, typename ReadHandler>
257   inline void* asio_handler_allocate(std::size_t size,
258       read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
259         MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
260   {
261     return boost_asio_handler_alloc_helpers::allocate(
262         size, this_handler->handler_);
263   }
264
265   template <typename AsyncRandomAccessReadDevice,
266       typename MutableBufferSequence, typename MutableBufferIterator,
267       typename CompletionCondition, typename ReadHandler>
268   inline void asio_handler_deallocate(void* pointer, std::size_t size,
269       read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
270         MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
271   {
272     boost_asio_handler_alloc_helpers::deallocate(
273         pointer, size, this_handler->handler_);
274   }
275
276   template <typename AsyncRandomAccessReadDevice,
277       typename MutableBufferSequence, typename MutableBufferIterator,
278       typename CompletionCondition, typename ReadHandler>
279   inline bool asio_handler_is_continuation(
280       read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
281         MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
282   {
283     return this_handler->start_ == 0 ? true
284       : boost_asio_handler_cont_helpers::is_continuation(
285           this_handler->handler_);
286   }
287
288   template <typename Function, typename AsyncRandomAccessReadDevice,
289       typename MutableBufferSequence, typename MutableBufferIterator,
290       typename CompletionCondition, typename ReadHandler>
291   inline void asio_handler_invoke(Function& function,
292       read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
293         MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
294   {
295     boost_asio_handler_invoke_helpers::invoke(
296         function, this_handler->handler_);
297   }
298
299   template <typename Function, typename AsyncRandomAccessReadDevice,
300       typename MutableBufferSequence, typename MutableBufferIterator,
301       typename CompletionCondition, typename ReadHandler>
302   inline void asio_handler_invoke(const Function& function,
303       read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
304         MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
305   {
306     boost_asio_handler_invoke_helpers::invoke(
307         function, this_handler->handler_);
308   }
309
310   template <typename AsyncRandomAccessReadDevice,
311       typename MutableBufferSequence, typename MutableBufferIterator,
312       typename CompletionCondition, typename ReadHandler>
313   inline void start_read_at_buffer_sequence_op(AsyncRandomAccessReadDevice& d,
314       uint64_t offset, const MutableBufferSequence& buffers,
315       const MutableBufferIterator&, CompletionCondition& completion_condition,
316       ReadHandler& handler)
317   {
318     detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
319       MutableBufferIterator, CompletionCondition, ReadHandler>(
320         d, offset, buffers, completion_condition, handler)(
321           boost::system::error_code(), 0, 1);
322   }
323
324   template <typename AsyncRandomAccessReadDevice>
325   class initiate_async_read_at_buffer_sequence
326   {
327   public:
328     typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;
329
330     explicit initiate_async_read_at_buffer_sequence(
331         AsyncRandomAccessReadDevice& device)
332       : device_(device)
333     {
334     }
335
336     executor_type get_executor() const BOOST_ASIO_NOEXCEPT
337     {
338       return device_.get_executor();
339     }
340
341     template <typename ReadHandler, typename MutableBufferSequence,
342         typename CompletionCondition>
343     void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
344         uint64_t offset, const MutableBufferSequence& buffers,
345         BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
346     {
347       // If you get an error on the following line it means that your handler
348       // does not meet the documented type requirements for a ReadHandler.
349       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
350
351       non_const_lvalue<ReadHandler> handler2(handler);
352       non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
353       start_read_at_buffer_sequence_op(device_, offset, buffers,
354           boost::asio::buffer_sequence_begin(buffers),
355           completion_cond2.value, handler2.value);
356     }
357
358   private:
359     AsyncRandomAccessReadDevice& device_;
360   };
361 } // namespace detail
362
363 #if !defined(GENERATING_DOCUMENTATION)
364
365 template <typename AsyncRandomAccessReadDevice,
366     typename MutableBufferSequence, typename MutableBufferIterator,
367     typename CompletionCondition, typename ReadHandler, typename Allocator>
368 struct associated_allocator<
369     detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
370     MutableBufferIterator, CompletionCondition, ReadHandler>,
371     Allocator>
372 {
373   typedef typename associated_allocator<ReadHandler, Allocator>::type type;
374
375   static type get(
376       const detail::read_at_op<AsyncRandomAccessReadDevice,
377       MutableBufferSequence, MutableBufferIterator,
378       CompletionCondition, ReadHandler>& h,
379       const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
380   {
381     return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a);
382   }
383 };
384
385 template <typename AsyncRandomAccessReadDevice,
386     typename MutableBufferSequence, typename MutableBufferIterator,
387     typename CompletionCondition, typename ReadHandler, typename Executor>
388 struct associated_executor<
389     detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
390     MutableBufferIterator, CompletionCondition, ReadHandler>,
391     Executor>
392 {
393   typedef typename associated_executor<ReadHandler, Executor>::type type;
394
395   static type get(
396       const detail::read_at_op<AsyncRandomAccessReadDevice,
397       MutableBufferSequence, MutableBufferIterator,
398       CompletionCondition, ReadHandler>& h,
399       const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
400   {
401     return associated_executor<ReadHandler, Executor>::get(h.handler_, ex);
402   }
403 };
404
405 #endif // !defined(GENERATING_DOCUMENTATION)
406
407 template <typename AsyncRandomAccessReadDevice,
408     typename MutableBufferSequence, typename CompletionCondition,
409     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
410       std::size_t)) ReadHandler>
411 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
412     void (boost::system::error_code, std::size_t))
413 async_read_at(AsyncRandomAccessReadDevice& d,
414     uint64_t offset, const MutableBufferSequence& buffers,
415     CompletionCondition completion_condition,
416     BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
417 {
418   return async_initiate<ReadHandler,
419     void (boost::system::error_code, std::size_t)>(
420       detail::initiate_async_read_at_buffer_sequence<
421         AsyncRandomAccessReadDevice>(d),
422       handler, offset, buffers,
423       BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
424 }
425
426 template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
427     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
428       std::size_t)) ReadHandler>
429 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
430     void (boost::system::error_code, std::size_t))
431 async_read_at(AsyncRandomAccessReadDevice& d,
432     uint64_t offset, const MutableBufferSequence& buffers,
433     BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
434 {
435   return async_initiate<ReadHandler,
436     void (boost::system::error_code, std::size_t)>(
437       detail::initiate_async_read_at_buffer_sequence<
438         AsyncRandomAccessReadDevice>(d),
439       handler, offset, buffers, transfer_all());
440 }
441
442 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
443 #if !defined(BOOST_ASIO_NO_IOSTREAM)
444
445 namespace detail
446 {
447   template <typename AsyncRandomAccessReadDevice, typename Allocator,
448       typename CompletionCondition, typename ReadHandler>
449   class read_at_streambuf_op
450     : detail::base_from_completion_cond<CompletionCondition>
451   {
452   public:
453     read_at_streambuf_op(AsyncRandomAccessReadDevice& device,
454         uint64_t offset, basic_streambuf<Allocator>& streambuf,
455         CompletionCondition& completion_condition, ReadHandler& handler)
456       : detail::base_from_completion_cond<
457           CompletionCondition>(completion_condition),
458         device_(device),
459         offset_(offset),
460         streambuf_(streambuf),
461         start_(0),
462         total_transferred_(0),
463         handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler))
464     {
465     }
466
467 #if defined(BOOST_ASIO_HAS_MOVE)
468     read_at_streambuf_op(const read_at_streambuf_op& other)
469       : detail::base_from_completion_cond<CompletionCondition>(other),
470         device_(other.device_),
471         offset_(other.offset_),
472         streambuf_(other.streambuf_),
473         start_(other.start_),
474         total_transferred_(other.total_transferred_),
475         handler_(other.handler_)
476     {
477     }
478
479     read_at_streambuf_op(read_at_streambuf_op&& other)
480       : detail::base_from_completion_cond<CompletionCondition>(
481           BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond<
482             CompletionCondition>)(other)),
483         device_(other.device_),
484         offset_(other.offset_),
485         streambuf_(other.streambuf_),
486         start_(other.start_),
487         total_transferred_(other.total_transferred_),
488         handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_))
489     {
490     }
491 #endif // defined(BOOST_ASIO_HAS_MOVE)
492
493     void operator()(const boost::system::error_code& ec,
494         std::size_t bytes_transferred, int start = 0)
495     {
496       std::size_t max_size, bytes_available;
497       switch (start_ = start)
498       {
499         case 1:
500         max_size = this->check_for_completion(ec, total_transferred_);
501         bytes_available = read_size_helper(streambuf_, max_size);
502         for (;;)
503         {
504           device_.async_read_some_at(offset_ + total_transferred_,
505               streambuf_.prepare(bytes_available),
506               BOOST_ASIO_MOVE_CAST(read_at_streambuf_op)(*this));
507           return; default:
508           total_transferred_ += bytes_transferred;
509           streambuf_.commit(bytes_transferred);
510           max_size = this->check_for_completion(ec, total_transferred_);
511           bytes_available = read_size_helper(streambuf_, max_size);
512           if ((!ec && bytes_transferred == 0) || bytes_available == 0)
513             break;
514         }
515
516         handler_(ec, static_cast<const std::size_t&>(total_transferred_));
517       }
518     }
519
520   //private:
521     AsyncRandomAccessReadDevice& device_;
522     uint64_t offset_;
523     boost::asio::basic_streambuf<Allocator>& streambuf_;
524     int start_;
525     std::size_t total_transferred_;
526     ReadHandler handler_;
527   };
528
529   template <typename AsyncRandomAccessReadDevice, typename Allocator,
530       typename CompletionCondition, typename ReadHandler>
531   inline void* asio_handler_allocate(std::size_t size,
532       read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
533         CompletionCondition, ReadHandler>* this_handler)
534   {
535     return boost_asio_handler_alloc_helpers::allocate(
536         size, this_handler->handler_);
537   }
538
539   template <typename AsyncRandomAccessReadDevice, typename Allocator,
540       typename CompletionCondition, typename ReadHandler>
541   inline void asio_handler_deallocate(void* pointer, std::size_t size,
542       read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
543         CompletionCondition, ReadHandler>* this_handler)
544   {
545     boost_asio_handler_alloc_helpers::deallocate(
546         pointer, size, this_handler->handler_);
547   }
548
549   template <typename AsyncRandomAccessReadDevice, typename Allocator,
550       typename CompletionCondition, typename ReadHandler>
551   inline bool asio_handler_is_continuation(
552       read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
553         CompletionCondition, ReadHandler>* this_handler)
554   {
555     return this_handler->start_ == 0 ? true
556       : boost_asio_handler_cont_helpers::is_continuation(
557           this_handler->handler_);
558   }
559
560   template <typename Function, typename AsyncRandomAccessReadDevice,
561       typename Allocator, typename CompletionCondition, typename ReadHandler>
562   inline void asio_handler_invoke(Function& function,
563       read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
564         CompletionCondition, ReadHandler>* this_handler)
565   {
566     boost_asio_handler_invoke_helpers::invoke(
567         function, this_handler->handler_);
568   }
569
570   template <typename Function, typename AsyncRandomAccessReadDevice,
571       typename Allocator, typename CompletionCondition, typename ReadHandler>
572   inline void asio_handler_invoke(const Function& function,
573       read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
574         CompletionCondition, ReadHandler>* this_handler)
575   {
576     boost_asio_handler_invoke_helpers::invoke(
577         function, this_handler->handler_);
578   }
579
580   template <typename AsyncRandomAccessReadDevice>
581   class initiate_async_read_at_streambuf
582   {
583   public:
584     typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;
585
586     explicit initiate_async_read_at_streambuf(
587         AsyncRandomAccessReadDevice& device)
588       : device_(device)
589     {
590     }
591
592     executor_type get_executor() const BOOST_ASIO_NOEXCEPT
593     {
594       return device_.get_executor();
595     }
596
597     template <typename ReadHandler,
598         typename Allocator, typename CompletionCondition>
599     void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
600         uint64_t offset, basic_streambuf<Allocator>* b,
601         BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
602     {
603       // If you get an error on the following line it means that your handler
604       // does not meet the documented type requirements for a ReadHandler.
605       BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
606
607       non_const_lvalue<ReadHandler> handler2(handler);
608       non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
609       read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
610         CompletionCondition, typename decay<ReadHandler>::type>(
611           device_, offset, *b, completion_cond2.value, handler2.value)(
612             boost::system::error_code(), 0, 1);
613     }
614
615   private:
616     AsyncRandomAccessReadDevice& device_;
617   };
618 } // namespace detail
619
620 #if !defined(GENERATING_DOCUMENTATION)
621
622 template <typename AsyncRandomAccessReadDevice, typename Allocator,
623     typename CompletionCondition, typename ReadHandler, typename Allocator1>
624 struct associated_allocator<
625     detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
626       Allocator, CompletionCondition, ReadHandler>,
627     Allocator1>
628 {
629   typedef typename associated_allocator<ReadHandler, Allocator1>::type type;
630
631   static type get(
632       const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
633         Allocator, CompletionCondition, ReadHandler>& h,
634       const Allocator1& a = Allocator1()) BOOST_ASIO_NOEXCEPT
635   {
636     return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a);
637   }
638 };
639
640 template <typename AsyncRandomAccessReadDevice, typename Executor,
641     typename CompletionCondition, typename ReadHandler, typename Executor1>
642 struct associated_executor<
643     detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
644       Executor, CompletionCondition, ReadHandler>,
645     Executor1>
646 {
647   typedef typename associated_executor<ReadHandler, Executor1>::type type;
648
649   static type get(
650       const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
651         Executor, CompletionCondition, ReadHandler>& h,
652       const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT
653   {
654     return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex);
655   }
656 };
657
658 #endif // !defined(GENERATING_DOCUMENTATION)
659
660 template <typename AsyncRandomAccessReadDevice,
661     typename Allocator, typename CompletionCondition,
662     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
663       std::size_t)) ReadHandler>
664 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
665     void (boost::system::error_code, std::size_t))
666 async_read_at(AsyncRandomAccessReadDevice& d,
667     uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
668     CompletionCondition completion_condition,
669     BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
670 {
671   return async_initiate<ReadHandler,
672     void (boost::system::error_code, std::size_t)>(
673       detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d),
674       handler, offset, &b,
675       BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
676 }
677
678 template <typename AsyncRandomAccessReadDevice, typename Allocator,
679     BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
680       std::size_t)) ReadHandler>
681 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
682     void (boost::system::error_code, std::size_t))
683 async_read_at(AsyncRandomAccessReadDevice& d,
684     uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
685     BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
686 {
687   return async_initiate<ReadHandler,
688     void (boost::system::error_code, std::size_t)>(
689       detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d),
690       handler, offset, &b, transfer_all());
691 }
692
693 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
694 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
695
696 } // namespace asio
697 } // namespace boost
698
699 #include <boost/asio/detail/pop_options.hpp>
700
701 #endif // BOOST_ASIO_IMPL_READ_AT_HPP