write_at.hpp 19 KB

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