buffered_write_stream.hpp 12 KB

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