buffered_write_stream.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. //
  2. // impl/buffered_write_stream.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2022 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_BUFFERED_WRITE_STREAM_HPP
  11. #define ASIO_IMPL_BUFFERED_WRITE_STREAM_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/detail/handler_alloc_helpers.hpp"
  17. #include "asio/detail/handler_cont_helpers.hpp"
  18. #include "asio/detail/handler_invoke_helpers.hpp"
  19. #include "asio/detail/handler_type_requirements.hpp"
  20. #include "asio/detail/non_const_lvalue.hpp"
  21. #include "asio/detail/push_options.hpp"
  22. namespace asio {
  23. template <typename Stream>
  24. std::size_t buffered_write_stream<Stream>::flush()
  25. {
  26. std::size_t bytes_written = write(next_layer_,
  27. buffer(storage_.data(), storage_.size()));
  28. storage_.consume(bytes_written);
  29. return bytes_written;
  30. }
  31. template <typename Stream>
  32. std::size_t buffered_write_stream<Stream>::flush(asio::error_code& ec)
  33. {
  34. std::size_t bytes_written = write(next_layer_,
  35. buffer(storage_.data(), storage_.size()),
  36. transfer_all(), ec);
  37. storage_.consume(bytes_written);
  38. return bytes_written;
  39. }
  40. namespace detail
  41. {
  42. template <typename WriteHandler>
  43. class buffered_flush_handler
  44. {
  45. public:
  46. buffered_flush_handler(detail::buffered_stream_storage& storage,
  47. WriteHandler& handler)
  48. : storage_(storage),
  49. handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
  50. {
  51. }
  52. #if defined(ASIO_HAS_MOVE)
  53. buffered_flush_handler(const buffered_flush_handler& other)
  54. : storage_(other.storage_),
  55. handler_(other.handler_)
  56. {
  57. }
  58. buffered_flush_handler(buffered_flush_handler&& other)
  59. : storage_(other.storage_),
  60. handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
  61. {
  62. }
  63. #endif // defined(ASIO_HAS_MOVE)
  64. void operator()(const asio::error_code& ec,
  65. const std::size_t bytes_written)
  66. {
  67. storage_.consume(bytes_written);
  68. ASIO_MOVE_OR_LVALUE(WriteHandler)(handler_)(ec, bytes_written);
  69. }
  70. //private:
  71. detail::buffered_stream_storage& storage_;
  72. WriteHandler handler_;
  73. };
  74. template <typename WriteHandler>
  75. inline asio_handler_allocate_is_deprecated
  76. asio_handler_allocate(std::size_t size,
  77. buffered_flush_handler<WriteHandler>* this_handler)
  78. {
  79. #if defined(ASIO_NO_DEPRECATED)
  80. asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
  81. return asio_handler_allocate_is_no_longer_used();
  82. #else // defined(ASIO_NO_DEPRECATED)
  83. return asio_handler_alloc_helpers::allocate(
  84. size, this_handler->handler_);
  85. #endif // defined(ASIO_NO_DEPRECATED)
  86. }
  87. template <typename WriteHandler>
  88. inline asio_handler_deallocate_is_deprecated
  89. asio_handler_deallocate(void* pointer, std::size_t size,
  90. buffered_flush_handler<WriteHandler>* this_handler)
  91. {
  92. asio_handler_alloc_helpers::deallocate(
  93. pointer, size, this_handler->handler_);
  94. #if defined(ASIO_NO_DEPRECATED)
  95. return asio_handler_deallocate_is_no_longer_used();
  96. #endif // defined(ASIO_NO_DEPRECATED)
  97. }
  98. template <typename WriteHandler>
  99. inline bool asio_handler_is_continuation(
  100. buffered_flush_handler<WriteHandler>* this_handler)
  101. {
  102. return asio_handler_cont_helpers::is_continuation(
  103. this_handler->handler_);
  104. }
  105. template <typename Function, typename WriteHandler>
  106. inline asio_handler_invoke_is_deprecated
  107. asio_handler_invoke(Function& function,
  108. buffered_flush_handler<WriteHandler>* this_handler)
  109. {
  110. asio_handler_invoke_helpers::invoke(
  111. function, this_handler->handler_);
  112. #if defined(ASIO_NO_DEPRECATED)
  113. return asio_handler_invoke_is_no_longer_used();
  114. #endif // defined(ASIO_NO_DEPRECATED)
  115. }
  116. template <typename Function, typename WriteHandler>
  117. inline asio_handler_invoke_is_deprecated
  118. asio_handler_invoke(const Function& function,
  119. buffered_flush_handler<WriteHandler>* this_handler)
  120. {
  121. asio_handler_invoke_helpers::invoke(
  122. function, this_handler->handler_);
  123. #if defined(ASIO_NO_DEPRECATED)
  124. return asio_handler_invoke_is_no_longer_used();
  125. #endif // defined(ASIO_NO_DEPRECATED)
  126. }
  127. template <typename Stream>
  128. class initiate_async_buffered_flush
  129. {
  130. public:
  131. typedef typename remove_reference<
  132. Stream>::type::lowest_layer_type::executor_type executor_type;
  133. explicit initiate_async_buffered_flush(
  134. typename remove_reference<Stream>::type& next_layer)
  135. : next_layer_(next_layer)
  136. {
  137. }
  138. executor_type get_executor() const ASIO_NOEXCEPT
  139. {
  140. return next_layer_.lowest_layer().get_executor();
  141. }
  142. template <typename WriteHandler>
  143. void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
  144. buffered_stream_storage* storage) const
  145. {
  146. // If you get an error on the following line it means that your handler
  147. // does not meet the documented type requirements for a WriteHandler.
  148. ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  149. non_const_lvalue<WriteHandler> handler2(handler);
  150. async_write(next_layer_, buffer(storage->data(), storage->size()),
  151. buffered_flush_handler<typename decay<WriteHandler>::type>(
  152. *storage, handler2.value));
  153. }
  154. private:
  155. typename remove_reference<Stream>::type& next_layer_;
  156. };
  157. } // namespace detail
  158. #if !defined(GENERATING_DOCUMENTATION)
  159. template <template <typename, typename> class Associator,
  160. typename WriteHandler, typename DefaultCandidate>
  161. struct associator<Associator,
  162. detail::buffered_flush_handler<WriteHandler>,
  163. DefaultCandidate>
  164. : Associator<WriteHandler, DefaultCandidate>
  165. {
  166. static typename Associator<WriteHandler, DefaultCandidate>::type get(
  167. const detail::buffered_flush_handler<WriteHandler>& h,
  168. const DefaultCandidate& c = DefaultCandidate()) ASIO_NOEXCEPT
  169. {
  170. return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c);
  171. }
  172. };
  173. #endif // !defined(GENERATING_DOCUMENTATION)
  174. template <typename Stream>
  175. template <
  176. ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
  177. std::size_t)) WriteHandler>
  178. ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
  179. void (asio::error_code, std::size_t))
  180. buffered_write_stream<Stream>::async_flush(
  181. ASIO_MOVE_ARG(WriteHandler) handler)
  182. {
  183. return async_initiate<WriteHandler,
  184. void (asio::error_code, std::size_t)>(
  185. detail::initiate_async_buffered_flush<Stream>(next_layer_),
  186. handler, &storage_);
  187. }
  188. template <typename Stream>
  189. template <typename ConstBufferSequence>
  190. std::size_t buffered_write_stream<Stream>::write_some(
  191. const ConstBufferSequence& buffers)
  192. {
  193. using asio::buffer_size;
  194. if (buffer_size(buffers) == 0)
  195. return 0;
  196. if (storage_.size() == storage_.capacity())
  197. this->flush();
  198. return this->copy(buffers);
  199. }
  200. template <typename Stream>
  201. template <typename ConstBufferSequence>
  202. std::size_t buffered_write_stream<Stream>::write_some(
  203. const ConstBufferSequence& buffers, asio::error_code& ec)
  204. {
  205. ec = asio::error_code();
  206. using asio::buffer_size;
  207. if (buffer_size(buffers) == 0)
  208. return 0;
  209. if (storage_.size() == storage_.capacity() && !flush(ec))
  210. return 0;
  211. return this->copy(buffers);
  212. }
  213. namespace detail
  214. {
  215. template <typename ConstBufferSequence, typename WriteHandler>
  216. class buffered_write_some_handler
  217. {
  218. public:
  219. buffered_write_some_handler(detail::buffered_stream_storage& storage,
  220. const ConstBufferSequence& buffers, WriteHandler& handler)
  221. : storage_(storage),
  222. buffers_(buffers),
  223. handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
  224. {
  225. }
  226. #if defined(ASIO_HAS_MOVE)
  227. buffered_write_some_handler(const buffered_write_some_handler& other)
  228. : storage_(other.storage_),
  229. buffers_(other.buffers_),
  230. handler_(other.handler_)
  231. {
  232. }
  233. buffered_write_some_handler(buffered_write_some_handler&& other)
  234. : storage_(other.storage_),
  235. buffers_(other.buffers_),
  236. handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
  237. {
  238. }
  239. #endif // defined(ASIO_HAS_MOVE)
  240. void operator()(const asio::error_code& ec, std::size_t)
  241. {
  242. if (ec)
  243. {
  244. const std::size_t length = 0;
  245. ASIO_MOVE_OR_LVALUE(WriteHandler)(handler_)(ec, length);
  246. }
  247. else
  248. {
  249. using asio::buffer_size;
  250. std::size_t orig_size = storage_.size();
  251. std::size_t space_avail = storage_.capacity() - orig_size;
  252. std::size_t bytes_avail = buffer_size(buffers_);
  253. std::size_t length = bytes_avail < space_avail
  254. ? bytes_avail : space_avail;
  255. storage_.resize(orig_size + length);
  256. const std::size_t bytes_copied = asio::buffer_copy(
  257. storage_.data() + orig_size, buffers_, length);
  258. ASIO_MOVE_OR_LVALUE(WriteHandler)(handler_)(ec, bytes_copied);
  259. }
  260. }
  261. //private:
  262. detail::buffered_stream_storage& storage_;
  263. ConstBufferSequence buffers_;
  264. WriteHandler handler_;
  265. };
  266. template <typename ConstBufferSequence, typename WriteHandler>
  267. inline asio_handler_allocate_is_deprecated
  268. asio_handler_allocate(std::size_t size,
  269. buffered_write_some_handler<
  270. ConstBufferSequence, WriteHandler>* this_handler)
  271. {
  272. #if defined(ASIO_NO_DEPRECATED)
  273. asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
  274. return asio_handler_allocate_is_no_longer_used();
  275. #else // defined(ASIO_NO_DEPRECATED)
  276. return asio_handler_alloc_helpers::allocate(
  277. size, this_handler->handler_);
  278. #endif // defined(ASIO_NO_DEPRECATED)
  279. }
  280. template <typename ConstBufferSequence, typename WriteHandler>
  281. inline asio_handler_deallocate_is_deprecated
  282. asio_handler_deallocate(void* pointer, std::size_t size,
  283. buffered_write_some_handler<
  284. ConstBufferSequence, WriteHandler>* this_handler)
  285. {
  286. asio_handler_alloc_helpers::deallocate(
  287. pointer, size, this_handler->handler_);
  288. #if defined(ASIO_NO_DEPRECATED)
  289. return asio_handler_deallocate_is_no_longer_used();
  290. #endif // defined(ASIO_NO_DEPRECATED)
  291. }
  292. template <typename ConstBufferSequence, typename WriteHandler>
  293. inline bool asio_handler_is_continuation(
  294. buffered_write_some_handler<
  295. ConstBufferSequence, WriteHandler>* this_handler)
  296. {
  297. return asio_handler_cont_helpers::is_continuation(
  298. this_handler->handler_);
  299. }
  300. template <typename Function, typename ConstBufferSequence,
  301. typename WriteHandler>
  302. inline asio_handler_invoke_is_deprecated
  303. asio_handler_invoke(Function& function,
  304. buffered_write_some_handler<
  305. ConstBufferSequence, WriteHandler>* this_handler)
  306. {
  307. asio_handler_invoke_helpers::invoke(
  308. function, this_handler->handler_);
  309. #if defined(ASIO_NO_DEPRECATED)
  310. return asio_handler_invoke_is_no_longer_used();
  311. #endif // defined(ASIO_NO_DEPRECATED)
  312. }
  313. template <typename Function, typename ConstBufferSequence,
  314. typename WriteHandler>
  315. inline asio_handler_invoke_is_deprecated
  316. asio_handler_invoke(const Function& function,
  317. buffered_write_some_handler<
  318. ConstBufferSequence, WriteHandler>* this_handler)
  319. {
  320. asio_handler_invoke_helpers::invoke(
  321. function, this_handler->handler_);
  322. #if defined(ASIO_NO_DEPRECATED)
  323. return asio_handler_invoke_is_no_longer_used();
  324. #endif // defined(ASIO_NO_DEPRECATED)
  325. }
  326. template <typename Stream>
  327. class initiate_async_buffered_write_some
  328. {
  329. public:
  330. typedef typename remove_reference<
  331. Stream>::type::lowest_layer_type::executor_type executor_type;
  332. explicit initiate_async_buffered_write_some(
  333. typename remove_reference<Stream>::type& next_layer)
  334. : next_layer_(next_layer)
  335. {
  336. }
  337. executor_type get_executor() const ASIO_NOEXCEPT
  338. {
  339. return next_layer_.lowest_layer().get_executor();
  340. }
  341. template <typename WriteHandler, typename ConstBufferSequence>
  342. void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
  343. buffered_stream_storage* storage,
  344. const ConstBufferSequence& buffers) const
  345. {
  346. // If you get an error on the following line it means that your handler
  347. // does not meet the documented type requirements for a WriteHandler.
  348. ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  349. using asio::buffer_size;
  350. non_const_lvalue<WriteHandler> handler2(handler);
  351. if (buffer_size(buffers) == 0 || storage->size() < storage->capacity())
  352. {
  353. next_layer_.async_write_some(ASIO_CONST_BUFFER(0, 0),
  354. buffered_write_some_handler<ConstBufferSequence,
  355. typename decay<WriteHandler>::type>(
  356. *storage, buffers, handler2.value));
  357. }
  358. else
  359. {
  360. initiate_async_buffered_flush<Stream>(this->next_layer_)(
  361. buffered_write_some_handler<ConstBufferSequence,
  362. typename decay<WriteHandler>::type>(
  363. *storage, buffers, handler2.value),
  364. storage);
  365. }
  366. }
  367. private:
  368. typename remove_reference<Stream>::type& next_layer_;
  369. };
  370. } // namespace detail
  371. #if !defined(GENERATING_DOCUMENTATION)
  372. template <template <typename, typename> class Associator,
  373. typename ConstBufferSequence, typename WriteHandler,
  374. typename DefaultCandidate>
  375. struct associator<Associator,
  376. detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
  377. DefaultCandidate>
  378. : Associator<WriteHandler, DefaultCandidate>
  379. {
  380. static typename Associator<WriteHandler, DefaultCandidate>::type get(
  381. const detail::buffered_write_some_handler<
  382. ConstBufferSequence, WriteHandler>& h,
  383. const DefaultCandidate& c = DefaultCandidate()) ASIO_NOEXCEPT
  384. {
  385. return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c);
  386. }
  387. };
  388. #endif // !defined(GENERATING_DOCUMENTATION)
  389. template <typename Stream>
  390. template <typename ConstBufferSequence,
  391. ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
  392. std::size_t)) WriteHandler>
  393. ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
  394. void (asio::error_code, std::size_t))
  395. buffered_write_stream<Stream>::async_write_some(
  396. const ConstBufferSequence& buffers,
  397. ASIO_MOVE_ARG(WriteHandler) handler)
  398. {
  399. return async_initiate<WriteHandler,
  400. void (asio::error_code, std::size_t)>(
  401. detail::initiate_async_buffered_write_some<Stream>(next_layer_),
  402. handler, &storage_, buffers);
  403. }
  404. template <typename Stream>
  405. template <typename ConstBufferSequence>
  406. std::size_t buffered_write_stream<Stream>::copy(
  407. const ConstBufferSequence& buffers)
  408. {
  409. using asio::buffer_size;
  410. std::size_t orig_size = storage_.size();
  411. std::size_t space_avail = storage_.capacity() - orig_size;
  412. std::size_t bytes_avail = buffer_size(buffers);
  413. std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
  414. storage_.resize(orig_size + length);
  415. return asio::buffer_copy(
  416. storage_.data() + orig_size, buffers, length);
  417. }
  418. } // namespace asio
  419. #include "asio/detail/pop_options.hpp"
  420. #endif // ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP