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