read_at.hpp 29 KB

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