read_at.hpp 20 KB

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