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