read_at.hpp 28 KB

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