buffered_write_stream.hpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. //
  2. // impl/buffered_write_stream.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2015 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/detail/handler_alloc_helpers.hpp"
  16. #include "asio/detail/handler_cont_helpers.hpp"
  17. #include "asio/detail/handler_invoke_helpers.hpp"
  18. #include "asio/detail/handler_type_requirements.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_(handler)
  48. {
  49. }
  50. #if defined(ASIO_HAS_MOVE)
  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_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
  59. {
  60. }
  61. #endif // defined(ASIO_HAS_MOVE)
  62. void operator()(const asio::error_code& ec,
  63. const std::size_t bytes_written)
  64. {
  65. storage_.consume(bytes_written);
  66. handler_(ec, bytes_written);
  67. }
  68. //private:
  69. detail::buffered_stream_storage& storage_;
  70. WriteHandler handler_;
  71. };
  72. template <typename WriteHandler>
  73. inline void* asio_handler_allocate(std::size_t size,
  74. buffered_flush_handler<WriteHandler>* this_handler)
  75. {
  76. return asio_handler_alloc_helpers::allocate(
  77. size, this_handler->handler_);
  78. }
  79. template <typename WriteHandler>
  80. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  81. buffered_flush_handler<WriteHandler>* this_handler)
  82. {
  83. asio_handler_alloc_helpers::deallocate(
  84. pointer, size, this_handler->handler_);
  85. }
  86. template <typename WriteHandler>
  87. inline bool asio_handler_is_continuation(
  88. buffered_flush_handler<WriteHandler>* this_handler)
  89. {
  90. return asio_handler_cont_helpers::is_continuation(
  91. this_handler->handler_);
  92. }
  93. template <typename Function, typename WriteHandler>
  94. inline void asio_handler_invoke(Function& function,
  95. buffered_flush_handler<WriteHandler>* this_handler)
  96. {
  97. asio_handler_invoke_helpers::invoke(
  98. function, this_handler->handler_);
  99. }
  100. template <typename Function, typename WriteHandler>
  101. inline void asio_handler_invoke(const Function& function,
  102. buffered_flush_handler<WriteHandler>* this_handler)
  103. {
  104. asio_handler_invoke_helpers::invoke(
  105. function, this_handler->handler_);
  106. }
  107. }
  108. template <typename Stream>
  109. template <typename WriteHandler>
  110. ASIO_INITFN_RESULT_TYPE(WriteHandler,
  111. void (asio::error_code, std::size_t))
  112. buffered_write_stream<Stream>::async_flush(
  113. ASIO_MOVE_ARG(WriteHandler) handler)
  114. {
  115. // If you get an error on the following line it means that your handler does
  116. // not meet the documented type requirements for a WriteHandler.
  117. ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  118. detail::async_result_init<
  119. WriteHandler, void (asio::error_code, std::size_t)> init(
  120. ASIO_MOVE_CAST(WriteHandler)(handler));
  121. async_write(next_layer_, buffer(storage_.data(), storage_.size()),
  122. detail::buffered_flush_handler<ASIO_HANDLER_TYPE(
  123. WriteHandler, void (asio::error_code, std::size_t))>(
  124. storage_, init.handler));
  125. return init.result.get();
  126. }
  127. template <typename Stream>
  128. template <typename ConstBufferSequence>
  129. std::size_t buffered_write_stream<Stream>::write_some(
  130. const ConstBufferSequence& buffers)
  131. {
  132. if (asio::buffer_size(buffers) == 0)
  133. return 0;
  134. if (storage_.size() == storage_.capacity())
  135. this->flush();
  136. return this->copy(buffers);
  137. }
  138. template <typename Stream>
  139. template <typename ConstBufferSequence>
  140. std::size_t buffered_write_stream<Stream>::write_some(
  141. const ConstBufferSequence& buffers, asio::error_code& ec)
  142. {
  143. ec = asio::error_code();
  144. if (asio::buffer_size(buffers) == 0)
  145. return 0;
  146. if (storage_.size() == storage_.capacity() && !flush(ec))
  147. return 0;
  148. return this->copy(buffers);
  149. }
  150. namespace detail
  151. {
  152. template <typename ConstBufferSequence, typename WriteHandler>
  153. class buffered_write_some_handler
  154. {
  155. public:
  156. buffered_write_some_handler(detail::buffered_stream_storage& storage,
  157. const ConstBufferSequence& buffers, WriteHandler& handler)
  158. : storage_(storage),
  159. buffers_(buffers),
  160. handler_(handler)
  161. {
  162. }
  163. #if defined(ASIO_HAS_MOVE)
  164. buffered_write_some_handler(const buffered_write_some_handler& other)
  165. : storage_(other.storage_),
  166. buffers_(other.buffers_),
  167. handler_(other.handler_)
  168. {
  169. }
  170. buffered_write_some_handler(buffered_write_some_handler&& other)
  171. : storage_(other.storage_),
  172. buffers_(other.buffers_),
  173. handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
  174. {
  175. }
  176. #endif // defined(ASIO_HAS_MOVE)
  177. void operator()(const asio::error_code& ec, std::size_t)
  178. {
  179. if (ec)
  180. {
  181. const std::size_t length = 0;
  182. handler_(ec, length);
  183. }
  184. else
  185. {
  186. std::size_t orig_size = storage_.size();
  187. std::size_t space_avail = storage_.capacity() - orig_size;
  188. std::size_t bytes_avail = asio::buffer_size(buffers_);
  189. std::size_t length = bytes_avail < space_avail
  190. ? bytes_avail : space_avail;
  191. storage_.resize(orig_size + length);
  192. const std::size_t bytes_copied = asio::buffer_copy(
  193. storage_.data() + orig_size, buffers_, length);
  194. handler_(ec, bytes_copied);
  195. }
  196. }
  197. //private:
  198. detail::buffered_stream_storage& storage_;
  199. ConstBufferSequence buffers_;
  200. WriteHandler handler_;
  201. };
  202. template <typename ConstBufferSequence, typename WriteHandler>
  203. inline void* asio_handler_allocate(std::size_t size,
  204. buffered_write_some_handler<
  205. ConstBufferSequence, WriteHandler>* this_handler)
  206. {
  207. return asio_handler_alloc_helpers::allocate(
  208. size, this_handler->handler_);
  209. }
  210. template <typename ConstBufferSequence, typename WriteHandler>
  211. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  212. buffered_write_some_handler<
  213. ConstBufferSequence, WriteHandler>* this_handler)
  214. {
  215. asio_handler_alloc_helpers::deallocate(
  216. pointer, size, this_handler->handler_);
  217. }
  218. template <typename ConstBufferSequence, typename WriteHandler>
  219. inline bool asio_handler_is_continuation(
  220. buffered_write_some_handler<
  221. ConstBufferSequence, WriteHandler>* this_handler)
  222. {
  223. return asio_handler_cont_helpers::is_continuation(
  224. this_handler->handler_);
  225. }
  226. template <typename Function, typename ConstBufferSequence,
  227. typename WriteHandler>
  228. inline void asio_handler_invoke(Function& function,
  229. buffered_write_some_handler<
  230. ConstBufferSequence, WriteHandler>* this_handler)
  231. {
  232. asio_handler_invoke_helpers::invoke(
  233. function, this_handler->handler_);
  234. }
  235. template <typename Function, typename ConstBufferSequence,
  236. typename WriteHandler>
  237. inline void asio_handler_invoke(const Function& function,
  238. buffered_write_some_handler<
  239. ConstBufferSequence, WriteHandler>* this_handler)
  240. {
  241. asio_handler_invoke_helpers::invoke(
  242. function, this_handler->handler_);
  243. }
  244. } // namespace detail
  245. template <typename Stream>
  246. template <typename ConstBufferSequence, typename WriteHandler>
  247. ASIO_INITFN_RESULT_TYPE(WriteHandler,
  248. void (asio::error_code, std::size_t))
  249. buffered_write_stream<Stream>::async_write_some(
  250. const ConstBufferSequence& buffers,
  251. ASIO_MOVE_ARG(WriteHandler) handler)
  252. {
  253. // If you get an error on the following line it means that your handler does
  254. // not meet the documented type requirements for a WriteHandler.
  255. ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  256. detail::async_result_init<
  257. WriteHandler, void (asio::error_code, std::size_t)> init(
  258. ASIO_MOVE_CAST(WriteHandler)(handler));
  259. if (asio::buffer_size(buffers) == 0
  260. || storage_.size() < storage_.capacity())
  261. {
  262. next_layer_.async_write_some(asio::const_buffers_1(0, 0),
  263. detail::buffered_write_some_handler<
  264. ConstBufferSequence, ASIO_HANDLER_TYPE(
  265. WriteHandler, void (asio::error_code, std::size_t))>(
  266. storage_, buffers, init.handler));
  267. }
  268. else
  269. {
  270. this->async_flush(detail::buffered_write_some_handler<
  271. ConstBufferSequence, ASIO_HANDLER_TYPE(
  272. WriteHandler, void (asio::error_code, std::size_t))>(
  273. storage_, buffers, init.handler));
  274. }
  275. return init.result.get();
  276. }
  277. template <typename Stream>
  278. template <typename ConstBufferSequence>
  279. std::size_t buffered_write_stream<Stream>::copy(
  280. const ConstBufferSequence& buffers)
  281. {
  282. std::size_t orig_size = storage_.size();
  283. std::size_t space_avail = storage_.capacity() - orig_size;
  284. std::size_t bytes_avail = asio::buffer_size(buffers);
  285. std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
  286. storage_.resize(orig_size + length);
  287. return asio::buffer_copy(
  288. storage_.data() + orig_size, buffers, length);
  289. }
  290. } // namespace asio
  291. #include "asio/detail/pop_options.hpp"
  292. #endif // ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP