buffered_write_stream.hpp 14 KB

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