buffered_write_stream.hpp 16 KB

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