read_at.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. //
  2. // impl/read_at.hpp
  3. // ~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 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/associator.hpp"
  17. #include "asio/buffer.hpp"
  18. #include "asio/detail/array_fwd.hpp"
  19. #include "asio/detail/base_from_cancellation_state.hpp"
  20. #include "asio/detail/base_from_completion_cond.hpp"
  21. #include "asio/detail/bind_handler.hpp"
  22. #include "asio/detail/consuming_buffers.hpp"
  23. #include "asio/detail/dependent_type.hpp"
  24. #include "asio/detail/handler_cont_helpers.hpp"
  25. #include "asio/detail/handler_tracking.hpp"
  26. #include "asio/detail/handler_type_requirements.hpp"
  27. #include "asio/detail/non_const_lvalue.hpp"
  28. #include "asio/detail/throw_error.hpp"
  29. #include "asio/error.hpp"
  30. #include "asio/detail/push_options.hpp"
  31. namespace asio {
  32. namespace detail
  33. {
  34. template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
  35. typename MutableBufferIterator, typename CompletionCondition>
  36. std::size_t read_at_buffer_sequence(SyncRandomAccessReadDevice& d,
  37. uint64_t offset, const MutableBufferSequence& buffers,
  38. const MutableBufferIterator&, CompletionCondition completion_condition,
  39. asio::error_code& ec)
  40. {
  41. ec = asio::error_code();
  42. asio::detail::consuming_buffers<mutable_buffer,
  43. MutableBufferSequence, MutableBufferIterator> tmp(buffers);
  44. while (!tmp.empty())
  45. {
  46. if (std::size_t max_size = detail::adapt_completion_condition_result(
  47. completion_condition(ec, tmp.total_consumed())))
  48. {
  49. tmp.consume(d.read_some_at(offset + tmp.total_consumed(),
  50. tmp.prepare(max_size), ec));
  51. }
  52. else
  53. break;
  54. }
  55. return tmp.total_consumed();
  56. }
  57. } // namespace detail
  58. template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
  59. typename CompletionCondition>
  60. std::size_t read_at(SyncRandomAccessReadDevice& d,
  61. uint64_t offset, const MutableBufferSequence& buffers,
  62. CompletionCondition completion_condition, asio::error_code& ec)
  63. {
  64. return detail::read_at_buffer_sequence(d, offset, buffers,
  65. asio::buffer_sequence_begin(buffers),
  66. static_cast<CompletionCondition&&>(completion_condition), ec);
  67. }
  68. template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
  69. inline std::size_t read_at(SyncRandomAccessReadDevice& d,
  70. uint64_t offset, const MutableBufferSequence& buffers)
  71. {
  72. asio::error_code ec;
  73. std::size_t bytes_transferred = read_at(
  74. d, offset, buffers, transfer_all(), ec);
  75. asio::detail::throw_error(ec, "read_at");
  76. return bytes_transferred;
  77. }
  78. template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
  79. inline std::size_t read_at(SyncRandomAccessReadDevice& d,
  80. uint64_t offset, const MutableBufferSequence& buffers,
  81. asio::error_code& ec)
  82. {
  83. return read_at(d, offset, buffers, transfer_all(), ec);
  84. }
  85. template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
  86. typename CompletionCondition>
  87. inline std::size_t read_at(SyncRandomAccessReadDevice& d,
  88. uint64_t offset, const MutableBufferSequence& buffers,
  89. CompletionCondition completion_condition)
  90. {
  91. asio::error_code ec;
  92. std::size_t bytes_transferred = read_at(d, offset, buffers,
  93. static_cast<CompletionCondition&&>(completion_condition), ec);
  94. asio::detail::throw_error(ec, "read_at");
  95. return bytes_transferred;
  96. }
  97. #if !defined(ASIO_NO_EXTENSIONS)
  98. #if !defined(ASIO_NO_IOSTREAM)
  99. template <typename SyncRandomAccessReadDevice, typename Allocator,
  100. typename CompletionCondition>
  101. std::size_t read_at(SyncRandomAccessReadDevice& d,
  102. uint64_t offset, asio::basic_streambuf<Allocator>& b,
  103. CompletionCondition completion_condition, asio::error_code& ec)
  104. {
  105. ec = asio::error_code();
  106. std::size_t total_transferred = 0;
  107. std::size_t max_size = detail::adapt_completion_condition_result(
  108. completion_condition(ec, total_transferred));
  109. std::size_t bytes_available = read_size_helper(b, max_size);
  110. while (bytes_available > 0)
  111. {
  112. std::size_t bytes_transferred = d.read_some_at(
  113. offset + total_transferred, b.prepare(bytes_available), ec);
  114. b.commit(bytes_transferred);
  115. total_transferred += bytes_transferred;
  116. max_size = detail::adapt_completion_condition_result(
  117. completion_condition(ec, total_transferred));
  118. bytes_available = read_size_helper(b, max_size);
  119. }
  120. return total_transferred;
  121. }
  122. template <typename SyncRandomAccessReadDevice, typename Allocator>
  123. inline std::size_t read_at(SyncRandomAccessReadDevice& d,
  124. uint64_t offset, asio::basic_streambuf<Allocator>& b)
  125. {
  126. asio::error_code ec;
  127. std::size_t bytes_transferred = read_at(
  128. d, offset, b, transfer_all(), ec);
  129. asio::detail::throw_error(ec, "read_at");
  130. return bytes_transferred;
  131. }
  132. template <typename SyncRandomAccessReadDevice, typename Allocator>
  133. inline std::size_t read_at(SyncRandomAccessReadDevice& d,
  134. uint64_t offset, asio::basic_streambuf<Allocator>& b,
  135. asio::error_code& ec)
  136. {
  137. return read_at(d, offset, b, transfer_all(), ec);
  138. }
  139. template <typename SyncRandomAccessReadDevice, typename Allocator,
  140. typename CompletionCondition>
  141. inline std::size_t read_at(SyncRandomAccessReadDevice& d,
  142. uint64_t offset, asio::basic_streambuf<Allocator>& b,
  143. CompletionCondition completion_condition)
  144. {
  145. asio::error_code ec;
  146. std::size_t bytes_transferred = read_at(d, offset, b,
  147. static_cast<CompletionCondition&&>(completion_condition), ec);
  148. asio::detail::throw_error(ec, "read_at");
  149. return bytes_transferred;
  150. }
  151. #endif // !defined(ASIO_NO_IOSTREAM)
  152. #endif // !defined(ASIO_NO_EXTENSIONS)
  153. namespace detail
  154. {
  155. template <typename AsyncRandomAccessReadDevice,
  156. typename MutableBufferSequence, typename MutableBufferIterator,
  157. typename CompletionCondition, typename ReadHandler>
  158. class read_at_op
  159. : public base_from_cancellation_state<ReadHandler>,
  160. 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. : base_from_cancellation_state<ReadHandler>(
  167. handler, enable_partial_cancellation()),
  168. base_from_completion_cond<CompletionCondition>(completion_condition),
  169. device_(device),
  170. offset_(offset),
  171. buffers_(buffers),
  172. start_(0),
  173. handler_(static_cast<ReadHandler&&>(handler))
  174. {
  175. }
  176. read_at_op(const read_at_op& other)
  177. : base_from_cancellation_state<ReadHandler>(other),
  178. base_from_completion_cond<CompletionCondition>(other),
  179. device_(other.device_),
  180. offset_(other.offset_),
  181. buffers_(other.buffers_),
  182. start_(other.start_),
  183. handler_(other.handler_)
  184. {
  185. }
  186. read_at_op(read_at_op&& other)
  187. : base_from_cancellation_state<ReadHandler>(
  188. static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
  189. base_from_completion_cond<CompletionCondition>(
  190. static_cast<base_from_completion_cond<CompletionCondition>&&>(other)),
  191. device_(other.device_),
  192. offset_(other.offset_),
  193. buffers_(static_cast<buffers_type&&>(other.buffers_)),
  194. start_(other.start_),
  195. handler_(static_cast<ReadHandler&&>(other.handler_))
  196. {
  197. }
  198. void operator()(asio::error_code ec,
  199. std::size_t bytes_transferred, int start = 0)
  200. {
  201. std::size_t max_size;
  202. switch (start_ = start)
  203. {
  204. case 1:
  205. max_size = this->check_for_completion(ec, buffers_.total_consumed());
  206. for (;;)
  207. {
  208. {
  209. ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at"));
  210. device_.async_read_some_at(
  211. offset_ + buffers_.total_consumed(), buffers_.prepare(max_size),
  212. static_cast<read_at_op&&>(*this));
  213. }
  214. return; default:
  215. buffers_.consume(bytes_transferred);
  216. if ((!ec && bytes_transferred == 0) || buffers_.empty())
  217. break;
  218. max_size = this->check_for_completion(ec, buffers_.total_consumed());
  219. if (max_size == 0)
  220. break;
  221. if (this->cancelled() != cancellation_type::none)
  222. {
  223. ec = asio::error::operation_aborted;
  224. break;
  225. }
  226. }
  227. static_cast<ReadHandler&&>(handler_)(
  228. static_cast<const asio::error_code&>(ec),
  229. static_cast<const std::size_t&>(buffers_.total_consumed()));
  230. }
  231. }
  232. //private:
  233. typedef asio::detail::consuming_buffers<mutable_buffer,
  234. MutableBufferSequence, MutableBufferIterator> buffers_type;
  235. AsyncRandomAccessReadDevice& device_;
  236. uint64_t offset_;
  237. buffers_type buffers_;
  238. int start_;
  239. ReadHandler handler_;
  240. };
  241. template <typename AsyncRandomAccessReadDevice,
  242. typename MutableBufferSequence, typename MutableBufferIterator,
  243. typename CompletionCondition, typename ReadHandler>
  244. inline bool asio_handler_is_continuation(
  245. read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
  246. MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
  247. {
  248. return this_handler->start_ == 0 ? true
  249. : asio_handler_cont_helpers::is_continuation(
  250. this_handler->handler_);
  251. }
  252. template <typename AsyncRandomAccessReadDevice,
  253. typename MutableBufferSequence, typename MutableBufferIterator,
  254. typename CompletionCondition, typename ReadHandler>
  255. inline void start_read_at_op(AsyncRandomAccessReadDevice& d,
  256. uint64_t offset, const MutableBufferSequence& buffers,
  257. const MutableBufferIterator&, CompletionCondition& completion_condition,
  258. ReadHandler& handler)
  259. {
  260. detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
  261. MutableBufferIterator, CompletionCondition, ReadHandler>(
  262. d, offset, buffers, completion_condition, handler)(
  263. asio::error_code(), 0, 1);
  264. }
  265. template <typename AsyncRandomAccessReadDevice>
  266. class initiate_async_read_at
  267. {
  268. public:
  269. typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;
  270. explicit initiate_async_read_at(AsyncRandomAccessReadDevice& device)
  271. : device_(device)
  272. {
  273. }
  274. executor_type get_executor() const noexcept
  275. {
  276. return device_.get_executor();
  277. }
  278. template <typename ReadHandler, typename MutableBufferSequence,
  279. typename CompletionCondition>
  280. void operator()(ReadHandler&& handler,
  281. uint64_t offset, const MutableBufferSequence& buffers,
  282. CompletionCondition&& completion_cond) const
  283. {
  284. // If you get an error on the following line it means that your handler
  285. // does not meet the documented type requirements for a ReadHandler.
  286. ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
  287. non_const_lvalue<ReadHandler> handler2(handler);
  288. non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
  289. start_read_at_op(device_, offset, buffers,
  290. asio::buffer_sequence_begin(buffers),
  291. completion_cond2.value, handler2.value);
  292. }
  293. private:
  294. AsyncRandomAccessReadDevice& device_;
  295. };
  296. } // namespace detail
  297. #if !defined(GENERATING_DOCUMENTATION)
  298. template <template <typename, typename> class Associator,
  299. typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
  300. typename MutableBufferIterator, typename CompletionCondition,
  301. typename ReadHandler, typename DefaultCandidate>
  302. struct associator<Associator,
  303. detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
  304. MutableBufferIterator, CompletionCondition, ReadHandler>,
  305. DefaultCandidate>
  306. : Associator<ReadHandler, DefaultCandidate>
  307. {
  308. static typename Associator<ReadHandler, DefaultCandidate>::type get(
  309. const detail::read_at_op<AsyncRandomAccessReadDevice,
  310. MutableBufferSequence, MutableBufferIterator,
  311. CompletionCondition, ReadHandler>& h) noexcept
  312. {
  313. return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
  314. }
  315. static auto get(
  316. const detail::read_at_op<AsyncRandomAccessReadDevice,
  317. MutableBufferSequence, MutableBufferIterator,
  318. CompletionCondition, ReadHandler>& h,
  319. const DefaultCandidate& c) noexcept
  320. -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
  321. {
  322. return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
  323. }
  324. };
  325. #endif // !defined(GENERATING_DOCUMENTATION)
  326. template <typename AsyncRandomAccessReadDevice,
  327. typename MutableBufferSequence, typename CompletionCondition,
  328. ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
  329. std::size_t)) ReadToken>
  330. inline auto async_read_at(AsyncRandomAccessReadDevice& d,
  331. uint64_t offset, const MutableBufferSequence& buffers,
  332. CompletionCondition completion_condition, ReadToken&& token)
  333. -> decltype(
  334. async_initiate<ReadToken,
  335. void (asio::error_code, std::size_t)>(
  336. declval<detail::initiate_async_read_at<AsyncRandomAccessReadDevice>>(),
  337. token, offset, buffers,
  338. static_cast<CompletionCondition&&>(completion_condition)))
  339. {
  340. return async_initiate<ReadToken,
  341. void (asio::error_code, std::size_t)>(
  342. detail::initiate_async_read_at<AsyncRandomAccessReadDevice>(d),
  343. token, offset, buffers,
  344. static_cast<CompletionCondition&&>(completion_condition));
  345. }
  346. template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
  347. ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
  348. std::size_t)) ReadToken>
  349. inline auto async_read_at(AsyncRandomAccessReadDevice& d,
  350. uint64_t offset, const MutableBufferSequence& buffers, ReadToken&& token)
  351. -> decltype(
  352. async_initiate<ReadToken,
  353. void (asio::error_code, std::size_t)>(
  354. declval<detail::initiate_async_read_at<AsyncRandomAccessReadDevice>>(),
  355. token, offset, buffers, transfer_all()))
  356. {
  357. return async_initiate<ReadToken,
  358. void (asio::error_code, std::size_t)>(
  359. detail::initiate_async_read_at<AsyncRandomAccessReadDevice>(d),
  360. token, offset, buffers, transfer_all());
  361. }
  362. #if !defined(ASIO_NO_EXTENSIONS)
  363. #if !defined(ASIO_NO_IOSTREAM)
  364. namespace detail
  365. {
  366. template <typename AsyncRandomAccessReadDevice, typename Allocator,
  367. typename CompletionCondition, typename ReadHandler>
  368. class read_at_streambuf_op
  369. : public base_from_cancellation_state<ReadHandler>,
  370. base_from_completion_cond<CompletionCondition>
  371. {
  372. public:
  373. read_at_streambuf_op(AsyncRandomAccessReadDevice& device,
  374. uint64_t offset, basic_streambuf<Allocator>& streambuf,
  375. CompletionCondition& completion_condition, ReadHandler& handler)
  376. : base_from_cancellation_state<ReadHandler>(
  377. handler, enable_partial_cancellation()),
  378. base_from_completion_cond<CompletionCondition>(completion_condition),
  379. device_(device),
  380. offset_(offset),
  381. streambuf_(streambuf),
  382. start_(0),
  383. total_transferred_(0),
  384. handler_(static_cast<ReadHandler&&>(handler))
  385. {
  386. }
  387. read_at_streambuf_op(const read_at_streambuf_op& other)
  388. : base_from_cancellation_state<ReadHandler>(other),
  389. base_from_completion_cond<CompletionCondition>(other),
  390. device_(other.device_),
  391. offset_(other.offset_),
  392. streambuf_(other.streambuf_),
  393. start_(other.start_),
  394. total_transferred_(other.total_transferred_),
  395. handler_(other.handler_)
  396. {
  397. }
  398. read_at_streambuf_op(read_at_streambuf_op&& other)
  399. : base_from_cancellation_state<ReadHandler>(
  400. static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
  401. base_from_completion_cond<CompletionCondition>(
  402. static_cast<base_from_completion_cond<CompletionCondition>&&>(other)),
  403. device_(other.device_),
  404. offset_(other.offset_),
  405. streambuf_(other.streambuf_),
  406. start_(other.start_),
  407. total_transferred_(other.total_transferred_),
  408. handler_(static_cast<ReadHandler&&>(other.handler_))
  409. {
  410. }
  411. void operator()(asio::error_code ec,
  412. std::size_t bytes_transferred, int start = 0)
  413. {
  414. std::size_t max_size, bytes_available;
  415. switch (start_ = start)
  416. {
  417. case 1:
  418. max_size = this->check_for_completion(ec, total_transferred_);
  419. bytes_available = read_size_helper(streambuf_, max_size);
  420. for (;;)
  421. {
  422. {
  423. ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at"));
  424. device_.async_read_some_at(offset_ + total_transferred_,
  425. streambuf_.prepare(bytes_available),
  426. static_cast<read_at_streambuf_op&&>(*this));
  427. }
  428. return; default:
  429. total_transferred_ += bytes_transferred;
  430. streambuf_.commit(bytes_transferred);
  431. max_size = this->check_for_completion(ec, total_transferred_);
  432. bytes_available = read_size_helper(streambuf_, max_size);
  433. if ((!ec && bytes_transferred == 0) || bytes_available == 0)
  434. break;
  435. if (this->cancelled() != cancellation_type::none)
  436. {
  437. ec = asio::error::operation_aborted;
  438. break;
  439. }
  440. }
  441. static_cast<ReadHandler&&>(handler_)(
  442. static_cast<const asio::error_code&>(ec),
  443. static_cast<const std::size_t&>(total_transferred_));
  444. }
  445. }
  446. //private:
  447. AsyncRandomAccessReadDevice& device_;
  448. uint64_t offset_;
  449. asio::basic_streambuf<Allocator>& streambuf_;
  450. int start_;
  451. std::size_t total_transferred_;
  452. ReadHandler handler_;
  453. };
  454. template <typename AsyncRandomAccessReadDevice, typename Allocator,
  455. typename CompletionCondition, typename ReadHandler>
  456. inline bool asio_handler_is_continuation(
  457. read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
  458. CompletionCondition, ReadHandler>* this_handler)
  459. {
  460. return this_handler->start_ == 0 ? true
  461. : asio_handler_cont_helpers::is_continuation(
  462. this_handler->handler_);
  463. }
  464. template <typename AsyncRandomAccessReadDevice>
  465. class initiate_async_read_at_streambuf
  466. {
  467. public:
  468. typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;
  469. explicit initiate_async_read_at_streambuf(
  470. AsyncRandomAccessReadDevice& device)
  471. : device_(device)
  472. {
  473. }
  474. executor_type get_executor() const noexcept
  475. {
  476. return device_.get_executor();
  477. }
  478. template <typename ReadHandler,
  479. typename Allocator, typename CompletionCondition>
  480. void operator()(ReadHandler&& handler,
  481. uint64_t offset, basic_streambuf<Allocator>* b,
  482. CompletionCondition&& completion_cond) const
  483. {
  484. // If you get an error on the following line it means that your handler
  485. // does not meet the documented type requirements for a ReadHandler.
  486. ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
  487. non_const_lvalue<ReadHandler> handler2(handler);
  488. non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
  489. read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
  490. CompletionCondition, decay_t<ReadHandler>>(
  491. device_, offset, *b, completion_cond2.value, handler2.value)(
  492. asio::error_code(), 0, 1);
  493. }
  494. private:
  495. AsyncRandomAccessReadDevice& device_;
  496. };
  497. } // namespace detail
  498. #if !defined(GENERATING_DOCUMENTATION)
  499. template <template <typename, typename> class Associator,
  500. typename AsyncRandomAccessReadDevice, typename Executor,
  501. typename CompletionCondition, typename ReadHandler,
  502. typename DefaultCandidate>
  503. struct associator<Associator,
  504. detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
  505. Executor, CompletionCondition, ReadHandler>,
  506. DefaultCandidate>
  507. : Associator<ReadHandler, DefaultCandidate>
  508. {
  509. static typename Associator<ReadHandler, DefaultCandidate>::type get(
  510. const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
  511. Executor, CompletionCondition, ReadHandler>& h) noexcept
  512. {
  513. return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
  514. }
  515. static auto get(
  516. const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
  517. Executor, CompletionCondition, ReadHandler>& h,
  518. const DefaultCandidate& c) noexcept
  519. -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
  520. {
  521. return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
  522. }
  523. };
  524. #endif // !defined(GENERATING_DOCUMENTATION)
  525. template <typename AsyncRandomAccessReadDevice,
  526. typename Allocator, typename CompletionCondition,
  527. ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
  528. std::size_t)) ReadToken>
  529. inline auto async_read_at(AsyncRandomAccessReadDevice& d,
  530. uint64_t offset, asio::basic_streambuf<Allocator>& b,
  531. CompletionCondition completion_condition, ReadToken&& token)
  532. -> decltype(
  533. async_initiate<ReadToken,
  534. void (asio::error_code, std::size_t)>(
  535. declval<detail::initiate_async_read_at_streambuf<
  536. AsyncRandomAccessReadDevice>>(),
  537. token, offset, &b,
  538. static_cast<CompletionCondition&&>(completion_condition)))
  539. {
  540. return async_initiate<ReadToken,
  541. void (asio::error_code, std::size_t)>(
  542. detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d),
  543. token, offset, &b,
  544. static_cast<CompletionCondition&&>(completion_condition));
  545. }
  546. template <typename AsyncRandomAccessReadDevice, typename Allocator,
  547. ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
  548. std::size_t)) ReadToken>
  549. inline auto async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset,
  550. asio::basic_streambuf<Allocator>& b, ReadToken&& token)
  551. -> decltype(
  552. async_initiate<ReadToken,
  553. void (asio::error_code, std::size_t)>(
  554. declval<detail::initiate_async_read_at_streambuf<
  555. AsyncRandomAccessReadDevice>>(),
  556. token, offset, &b, transfer_all()))
  557. {
  558. return async_initiate<ReadToken,
  559. void (asio::error_code, std::size_t)>(
  560. detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d),
  561. token, offset, &b, transfer_all());
  562. }
  563. #endif // !defined(ASIO_NO_IOSTREAM)
  564. #endif // !defined(ASIO_NO_EXTENSIONS)
  565. } // namespace asio
  566. #include "asio/detail/pop_options.hpp"
  567. #endif // ASIO_IMPL_READ_AT_HPP