buffered_write_stream.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. //
  2. // impl/buffered_write_stream.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_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_cont_helpers.hpp"
  17. #include "asio/detail/handler_type_requirements.hpp"
  18. #include "asio/detail/non_const_lvalue.hpp"
  19. #include "asio/detail/push_options.hpp"
  20. namespace asio {
  21. template <typename Stream>
  22. std::size_t buffered_write_stream<Stream>::flush()
  23. {
  24. std::size_t bytes_written = write(next_layer_,
  25. buffer(storage_.data(), storage_.size()));
  26. storage_.consume(bytes_written);
  27. return bytes_written;
  28. }
  29. template <typename Stream>
  30. std::size_t buffered_write_stream<Stream>::flush(asio::error_code& ec)
  31. {
  32. std::size_t bytes_written = write(next_layer_,
  33. buffer(storage_.data(), storage_.size()),
  34. transfer_all(), ec);
  35. storage_.consume(bytes_written);
  36. return bytes_written;
  37. }
  38. namespace detail
  39. {
  40. template <typename WriteHandler>
  41. class buffered_flush_handler
  42. {
  43. public:
  44. buffered_flush_handler(detail::buffered_stream_storage& storage,
  45. WriteHandler& handler)
  46. : storage_(storage),
  47. handler_(static_cast<WriteHandler&&>(handler))
  48. {
  49. }
  50. buffered_flush_handler(const buffered_flush_handler& other)
  51. : storage_(other.storage_),
  52. handler_(other.handler_)
  53. {
  54. }
  55. buffered_flush_handler(buffered_flush_handler&& other)
  56. : storage_(other.storage_),
  57. handler_(static_cast<WriteHandler&&>(other.handler_))
  58. {
  59. }
  60. void operator()(const asio::error_code& ec,
  61. const std::size_t bytes_written)
  62. {
  63. storage_.consume(bytes_written);
  64. static_cast<WriteHandler&&>(handler_)(ec, bytes_written);
  65. }
  66. //private:
  67. detail::buffered_stream_storage& storage_;
  68. WriteHandler handler_;
  69. };
  70. template <typename WriteHandler>
  71. inline bool asio_handler_is_continuation(
  72. buffered_flush_handler<WriteHandler>* this_handler)
  73. {
  74. return asio_handler_cont_helpers::is_continuation(
  75. this_handler->handler_);
  76. }
  77. template <typename Stream>
  78. class initiate_async_buffered_flush
  79. {
  80. public:
  81. typedef typename remove_reference_t<
  82. Stream>::lowest_layer_type::executor_type executor_type;
  83. explicit initiate_async_buffered_flush(
  84. remove_reference_t<Stream>& next_layer)
  85. : next_layer_(next_layer)
  86. {
  87. }
  88. executor_type get_executor() const noexcept
  89. {
  90. return next_layer_.lowest_layer().get_executor();
  91. }
  92. template <typename WriteHandler>
  93. void operator()(WriteHandler&& handler,
  94. buffered_stream_storage* storage) const
  95. {
  96. // If you get an error on the following line it means that your handler
  97. // does not meet the documented type requirements for a WriteHandler.
  98. ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  99. non_const_lvalue<WriteHandler> handler2(handler);
  100. async_write(next_layer_, buffer(storage->data(), storage->size()),
  101. buffered_flush_handler<decay_t<WriteHandler>>(
  102. *storage, handler2.value));
  103. }
  104. private:
  105. remove_reference_t<Stream>& next_layer_;
  106. };
  107. } // namespace detail
  108. #if !defined(GENERATING_DOCUMENTATION)
  109. template <template <typename, typename> class Associator,
  110. typename WriteHandler, typename DefaultCandidate>
  111. struct associator<Associator,
  112. detail::buffered_flush_handler<WriteHandler>,
  113. DefaultCandidate>
  114. : Associator<WriteHandler, DefaultCandidate>
  115. {
  116. static typename Associator<WriteHandler, DefaultCandidate>::type get(
  117. const detail::buffered_flush_handler<WriteHandler>& h) noexcept
  118. {
  119. return Associator<WriteHandler, DefaultCandidate>::get(h.handler_);
  120. }
  121. static auto get(const detail::buffered_flush_handler<WriteHandler>& h,
  122. const DefaultCandidate& c) noexcept
  123. -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c))
  124. {
  125. return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c);
  126. }
  127. };
  128. #endif // !defined(GENERATING_DOCUMENTATION)
  129. template <typename Stream>
  130. template <
  131. ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
  132. std::size_t)) WriteHandler>
  133. inline auto buffered_write_stream<Stream>::async_flush(WriteHandler&& handler)
  134. -> decltype(
  135. async_initiate<WriteHandler,
  136. void (asio::error_code, std::size_t)>(
  137. declval<detail::initiate_async_buffered_flush<Stream>>(),
  138. handler, declval<detail::buffered_stream_storage*>()))
  139. {
  140. return async_initiate<WriteHandler,
  141. void (asio::error_code, std::size_t)>(
  142. detail::initiate_async_buffered_flush<Stream>(next_layer_),
  143. handler, &storage_);
  144. }
  145. template <typename Stream>
  146. template <typename ConstBufferSequence>
  147. std::size_t buffered_write_stream<Stream>::write_some(
  148. const ConstBufferSequence& buffers)
  149. {
  150. using asio::buffer_size;
  151. if (buffer_size(buffers) == 0)
  152. return 0;
  153. if (storage_.size() == storage_.capacity())
  154. this->flush();
  155. return this->copy(buffers);
  156. }
  157. template <typename Stream>
  158. template <typename ConstBufferSequence>
  159. std::size_t buffered_write_stream<Stream>::write_some(
  160. const ConstBufferSequence& buffers, asio::error_code& ec)
  161. {
  162. ec = asio::error_code();
  163. using asio::buffer_size;
  164. if (buffer_size(buffers) == 0)
  165. return 0;
  166. if (storage_.size() == storage_.capacity() && !flush(ec))
  167. return 0;
  168. return this->copy(buffers);
  169. }
  170. namespace detail
  171. {
  172. template <typename ConstBufferSequence, typename WriteHandler>
  173. class buffered_write_some_handler
  174. {
  175. public:
  176. buffered_write_some_handler(detail::buffered_stream_storage& storage,
  177. const ConstBufferSequence& buffers, WriteHandler& handler)
  178. : storage_(storage),
  179. buffers_(buffers),
  180. handler_(static_cast<WriteHandler&&>(handler))
  181. {
  182. }
  183. buffered_write_some_handler(const buffered_write_some_handler& other)
  184. : storage_(other.storage_),
  185. buffers_(other.buffers_),
  186. handler_(other.handler_)
  187. {
  188. }
  189. buffered_write_some_handler(buffered_write_some_handler&& other)
  190. : storage_(other.storage_),
  191. buffers_(other.buffers_),
  192. handler_(static_cast<WriteHandler&&>(other.handler_))
  193. {
  194. }
  195. void operator()(const asio::error_code& ec, std::size_t)
  196. {
  197. if (ec)
  198. {
  199. const std::size_t length = 0;
  200. static_cast<WriteHandler&&>(handler_)(ec, length);
  201. }
  202. else
  203. {
  204. using asio::buffer_size;
  205. std::size_t orig_size = storage_.size();
  206. std::size_t space_avail = storage_.capacity() - orig_size;
  207. std::size_t bytes_avail = buffer_size(buffers_);
  208. std::size_t length = bytes_avail < space_avail
  209. ? bytes_avail : space_avail;
  210. storage_.resize(orig_size + length);
  211. const std::size_t bytes_copied = asio::buffer_copy(
  212. storage_.data() + orig_size, buffers_, length);
  213. static_cast<WriteHandler&&>(handler_)(ec, bytes_copied);
  214. }
  215. }
  216. //private:
  217. detail::buffered_stream_storage& storage_;
  218. ConstBufferSequence buffers_;
  219. WriteHandler handler_;
  220. };
  221. template <typename ConstBufferSequence, typename WriteHandler>
  222. inline bool asio_handler_is_continuation(
  223. buffered_write_some_handler<
  224. ConstBufferSequence, WriteHandler>* this_handler)
  225. {
  226. return asio_handler_cont_helpers::is_continuation(
  227. this_handler->handler_);
  228. }
  229. template <typename Stream>
  230. class initiate_async_buffered_write_some
  231. {
  232. public:
  233. typedef typename remove_reference_t<
  234. Stream>::lowest_layer_type::executor_type executor_type;
  235. explicit initiate_async_buffered_write_some(
  236. remove_reference_t<Stream>& next_layer)
  237. : next_layer_(next_layer)
  238. {
  239. }
  240. executor_type get_executor() const noexcept
  241. {
  242. return next_layer_.lowest_layer().get_executor();
  243. }
  244. template <typename WriteHandler, typename ConstBufferSequence>
  245. void operator()(WriteHandler&& handler,
  246. buffered_stream_storage* storage,
  247. const ConstBufferSequence& buffers) const
  248. {
  249. // If you get an error on the following line it means that your handler
  250. // does not meet the documented type requirements for a WriteHandler.
  251. ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  252. using asio::buffer_size;
  253. non_const_lvalue<WriteHandler> handler2(handler);
  254. if (buffer_size(buffers) == 0 || storage->size() < storage->capacity())
  255. {
  256. next_layer_.async_write_some(ASIO_CONST_BUFFER(0, 0),
  257. buffered_write_some_handler<ConstBufferSequence,
  258. decay_t<WriteHandler>>(
  259. *storage, buffers, handler2.value));
  260. }
  261. else
  262. {
  263. initiate_async_buffered_flush<Stream>(this->next_layer_)(
  264. buffered_write_some_handler<ConstBufferSequence,
  265. decay_t<WriteHandler>>(
  266. *storage, buffers, handler2.value),
  267. storage);
  268. }
  269. }
  270. private:
  271. remove_reference_t<Stream>& next_layer_;
  272. };
  273. } // namespace detail
  274. #if !defined(GENERATING_DOCUMENTATION)
  275. template <template <typename, typename> class Associator,
  276. typename ConstBufferSequence, typename WriteHandler,
  277. typename DefaultCandidate>
  278. struct associator<Associator,
  279. detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
  280. DefaultCandidate>
  281. : Associator<WriteHandler, DefaultCandidate>
  282. {
  283. static typename Associator<WriteHandler, DefaultCandidate>::type get(
  284. const detail::buffered_write_some_handler<
  285. ConstBufferSequence, WriteHandler>& h) noexcept
  286. {
  287. return Associator<WriteHandler, DefaultCandidate>::get(h.handler_);
  288. }
  289. static auto get(
  290. const detail::buffered_write_some_handler<
  291. ConstBufferSequence, WriteHandler>& h,
  292. const DefaultCandidate& c) noexcept
  293. -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c))
  294. {
  295. return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c);
  296. }
  297. };
  298. #endif // !defined(GENERATING_DOCUMENTATION)
  299. template <typename Stream>
  300. template <typename ConstBufferSequence,
  301. ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
  302. std::size_t)) WriteHandler>
  303. inline auto buffered_write_stream<Stream>::async_write_some(
  304. const ConstBufferSequence& buffers, WriteHandler&& handler)
  305. -> decltype(
  306. async_initiate<WriteHandler,
  307. void (asio::error_code, std::size_t)>(
  308. declval<detail::initiate_async_buffered_write_some<Stream>>(),
  309. handler, declval<detail::buffered_stream_storage*>(), buffers))
  310. {
  311. return async_initiate<WriteHandler,
  312. void (asio::error_code, std::size_t)>(
  313. detail::initiate_async_buffered_write_some<Stream>(next_layer_),
  314. handler, &storage_, buffers);
  315. }
  316. template <typename Stream>
  317. template <typename ConstBufferSequence>
  318. std::size_t buffered_write_stream<Stream>::copy(
  319. const ConstBufferSequence& buffers)
  320. {
  321. using asio::buffer_size;
  322. std::size_t orig_size = storage_.size();
  323. std::size_t space_avail = storage_.capacity() - orig_size;
  324. std::size_t bytes_avail = buffer_size(buffers);
  325. std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
  326. storage_.resize(orig_size + length);
  327. return asio::buffer_copy(
  328. storage_.data() + orig_size, buffers, length);
  329. }
  330. } // namespace asio
  331. #include "asio/detail/pop_options.hpp"
  332. #endif // ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP