buffered_write_stream.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. //
  2. // impl/buffered_write_stream.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 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. struct initiate_async_buffered_flush
  112. {
  113. template <typename WriteHandler, typename Stream>
  114. void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
  115. buffered_stream_storage* storage, Stream* next_layer) const
  116. {
  117. // If you get an error on the following line it means that your handler
  118. // does not meet the documented type requirements for a WriteHandler.
  119. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  120. non_const_lvalue<WriteHandler> handler2(handler);
  121. async_write(*next_layer, buffer(storage->data(), storage->size()),
  122. buffered_flush_handler<typename decay<WriteHandler>::type>(
  123. *storage, handler2.value));
  124. }
  125. };
  126. } // namespace detail
  127. #if !defined(GENERATING_DOCUMENTATION)
  128. template <typename WriteHandler, typename Allocator>
  129. struct associated_allocator<
  130. detail::buffered_flush_handler<WriteHandler>, Allocator>
  131. {
  132. typedef typename associated_allocator<WriteHandler, Allocator>::type type;
  133. static type get(const detail::buffered_flush_handler<WriteHandler>& h,
  134. const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
  135. {
  136. return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
  137. }
  138. };
  139. template <typename WriteHandler, typename Executor>
  140. struct associated_executor<
  141. detail::buffered_flush_handler<WriteHandler>, Executor>
  142. {
  143. typedef typename associated_executor<WriteHandler, Executor>::type type;
  144. static type get(const detail::buffered_flush_handler<WriteHandler>& h,
  145. const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
  146. {
  147. return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
  148. }
  149. };
  150. #endif // !defined(GENERATING_DOCUMENTATION)
  151. template <typename Stream>
  152. template <typename WriteHandler>
  153. BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
  154. void (boost::system::error_code, std::size_t))
  155. buffered_write_stream<Stream>::async_flush(
  156. BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
  157. {
  158. return async_initiate<WriteHandler,
  159. void (boost::system::error_code, std::size_t)>(
  160. detail::initiate_async_buffered_flush(),
  161. handler, &storage_, &next_layer_);
  162. }
  163. template <typename Stream>
  164. template <typename ConstBufferSequence>
  165. std::size_t buffered_write_stream<Stream>::write_some(
  166. const ConstBufferSequence& buffers)
  167. {
  168. using boost::asio::buffer_size;
  169. if (buffer_size(buffers) == 0)
  170. return 0;
  171. if (storage_.size() == storage_.capacity())
  172. this->flush();
  173. return this->copy(buffers);
  174. }
  175. template <typename Stream>
  176. template <typename ConstBufferSequence>
  177. std::size_t buffered_write_stream<Stream>::write_some(
  178. const ConstBufferSequence& buffers, boost::system::error_code& ec)
  179. {
  180. ec = boost::system::error_code();
  181. using boost::asio::buffer_size;
  182. if (buffer_size(buffers) == 0)
  183. return 0;
  184. if (storage_.size() == storage_.capacity() && !flush(ec))
  185. return 0;
  186. return this->copy(buffers);
  187. }
  188. namespace detail
  189. {
  190. template <typename ConstBufferSequence, typename WriteHandler>
  191. class buffered_write_some_handler
  192. {
  193. public:
  194. buffered_write_some_handler(detail::buffered_stream_storage& storage,
  195. const ConstBufferSequence& buffers, WriteHandler& handler)
  196. : storage_(storage),
  197. buffers_(buffers),
  198. handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
  199. {
  200. }
  201. #if defined(BOOST_ASIO_HAS_MOVE)
  202. buffered_write_some_handler(const buffered_write_some_handler& other)
  203. : storage_(other.storage_),
  204. buffers_(other.buffers_),
  205. handler_(other.handler_)
  206. {
  207. }
  208. buffered_write_some_handler(buffered_write_some_handler&& other)
  209. : storage_(other.storage_),
  210. buffers_(other.buffers_),
  211. handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
  212. {
  213. }
  214. #endif // defined(BOOST_ASIO_HAS_MOVE)
  215. void operator()(const boost::system::error_code& ec, std::size_t)
  216. {
  217. if (ec)
  218. {
  219. const std::size_t length = 0;
  220. handler_(ec, length);
  221. }
  222. else
  223. {
  224. using boost::asio::buffer_size;
  225. std::size_t orig_size = storage_.size();
  226. std::size_t space_avail = storage_.capacity() - orig_size;
  227. std::size_t bytes_avail = buffer_size(buffers_);
  228. std::size_t length = bytes_avail < space_avail
  229. ? bytes_avail : space_avail;
  230. storage_.resize(orig_size + length);
  231. const std::size_t bytes_copied = boost::asio::buffer_copy(
  232. storage_.data() + orig_size, buffers_, length);
  233. handler_(ec, bytes_copied);
  234. }
  235. }
  236. //private:
  237. detail::buffered_stream_storage& storage_;
  238. ConstBufferSequence buffers_;
  239. WriteHandler handler_;
  240. };
  241. template <typename ConstBufferSequence, typename WriteHandler>
  242. inline void* asio_handler_allocate(std::size_t size,
  243. buffered_write_some_handler<
  244. ConstBufferSequence, WriteHandler>* this_handler)
  245. {
  246. return boost_asio_handler_alloc_helpers::allocate(
  247. size, this_handler->handler_);
  248. }
  249. template <typename ConstBufferSequence, typename WriteHandler>
  250. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  251. buffered_write_some_handler<
  252. ConstBufferSequence, WriteHandler>* this_handler)
  253. {
  254. boost_asio_handler_alloc_helpers::deallocate(
  255. pointer, size, this_handler->handler_);
  256. }
  257. template <typename ConstBufferSequence, typename WriteHandler>
  258. inline bool asio_handler_is_continuation(
  259. buffered_write_some_handler<
  260. ConstBufferSequence, WriteHandler>* this_handler)
  261. {
  262. return boost_asio_handler_cont_helpers::is_continuation(
  263. this_handler->handler_);
  264. }
  265. template <typename Function, typename ConstBufferSequence,
  266. typename WriteHandler>
  267. inline void asio_handler_invoke(Function& function,
  268. buffered_write_some_handler<
  269. ConstBufferSequence, WriteHandler>* this_handler)
  270. {
  271. boost_asio_handler_invoke_helpers::invoke(
  272. function, this_handler->handler_);
  273. }
  274. template <typename Function, typename ConstBufferSequence,
  275. typename WriteHandler>
  276. inline void asio_handler_invoke(const Function& function,
  277. buffered_write_some_handler<
  278. ConstBufferSequence, WriteHandler>* this_handler)
  279. {
  280. boost_asio_handler_invoke_helpers::invoke(
  281. function, this_handler->handler_);
  282. }
  283. struct initiate_async_buffered_write_some
  284. {
  285. template <typename WriteHandler, typename Stream,
  286. typename ConstBufferSequence>
  287. void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
  288. buffered_stream_storage* storage, Stream* next_layer,
  289. const ConstBufferSequence& buffers) const
  290. {
  291. // If you get an error on the following line it means that your handler
  292. // does not meet the documented type requirements for a WriteHandler.
  293. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  294. using boost::asio::buffer_size;
  295. non_const_lvalue<WriteHandler> handler2(handler);
  296. if (buffer_size(buffers) == 0 || storage->size() < storage->capacity())
  297. {
  298. next_layer->async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0),
  299. buffered_write_some_handler<ConstBufferSequence,
  300. typename decay<WriteHandler>::type>(
  301. *storage, buffers, handler2.value));
  302. }
  303. else
  304. {
  305. initiate_async_buffered_flush()(
  306. buffered_write_some_handler<ConstBufferSequence,
  307. typename decay<WriteHandler>::type>(
  308. *storage, buffers, handler2.value),
  309. storage, next_layer);
  310. }
  311. }
  312. };
  313. } // namespace detail
  314. #if !defined(GENERATING_DOCUMENTATION)
  315. template <typename ConstBufferSequence,
  316. typename WriteHandler, typename Allocator>
  317. struct associated_allocator<
  318. detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
  319. Allocator>
  320. {
  321. typedef typename associated_allocator<WriteHandler, Allocator>::type type;
  322. static type get(
  323. const detail::buffered_write_some_handler<
  324. ConstBufferSequence, WriteHandler>& h,
  325. const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
  326. {
  327. return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
  328. }
  329. };
  330. template <typename ConstBufferSequence,
  331. typename WriteHandler, typename Executor>
  332. struct associated_executor<
  333. detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
  334. Executor>
  335. {
  336. typedef typename associated_executor<WriteHandler, Executor>::type type;
  337. static type get(
  338. const detail::buffered_write_some_handler<
  339. ConstBufferSequence, WriteHandler>& h,
  340. const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
  341. {
  342. return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
  343. }
  344. };
  345. #endif // !defined(GENERATING_DOCUMENTATION)
  346. template <typename Stream>
  347. template <typename ConstBufferSequence, typename WriteHandler>
  348. BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
  349. void (boost::system::error_code, std::size_t))
  350. buffered_write_stream<Stream>::async_write_some(
  351. const ConstBufferSequence& buffers,
  352. BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
  353. {
  354. return async_initiate<WriteHandler,
  355. void (boost::system::error_code, std::size_t)>(
  356. detail::initiate_async_buffered_write_some(),
  357. handler, &storage_, &next_layer_, buffers);
  358. }
  359. template <typename Stream>
  360. template <typename ConstBufferSequence>
  361. std::size_t buffered_write_stream<Stream>::copy(
  362. const ConstBufferSequence& buffers)
  363. {
  364. using boost::asio::buffer_size;
  365. std::size_t orig_size = storage_.size();
  366. std::size_t space_avail = storage_.capacity() - orig_size;
  367. std::size_t bytes_avail = buffer_size(buffers);
  368. std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
  369. storage_.resize(orig_size + length);
  370. return boost::asio::buffer_copy(
  371. storage_.data() + orig_size, buffers, length);
  372. }
  373. } // namespace asio
  374. } // namespace boost
  375. #include <boost/asio/detail/pop_options.hpp>
  376. #endif // BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP