buffered_write_stream.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. //
  2. // buffered_write_stream.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2008 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_BUFFERED_WRITE_STREAM_HPP
  11. #define BOOST_ASIO_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/detail/push_options.hpp>
  16. #include <boost/asio/detail/push_options.hpp>
  17. #include <cstddef>
  18. #include <cstring>
  19. #include <boost/config.hpp>
  20. #include <boost/type_traits.hpp>
  21. #include <boost/asio/detail/pop_options.hpp>
  22. #include <boost/asio/buffered_write_stream_fwd.hpp>
  23. #include <boost/asio/buffer.hpp>
  24. #include <boost/asio/completion_condition.hpp>
  25. #include <boost/asio/error.hpp>
  26. #include <boost/asio/io_service.hpp>
  27. #include <boost/asio/write.hpp>
  28. #include <boost/asio/detail/bind_handler.hpp>
  29. #include <boost/asio/detail/buffered_stream_storage.hpp>
  30. #include <boost/asio/detail/noncopyable.hpp>
  31. namespace boost {
  32. namespace asio {
  33. /// Adds buffering to the write-related operations of a stream.
  34. /**
  35. * The buffered_write_stream class template can be used to add buffering to the
  36. * synchronous and asynchronous write operations of a stream.
  37. *
  38. * @par Thread Safety
  39. * @e Distinct @e objects: Safe.@n
  40. * @e Shared @e objects: Unsafe.
  41. *
  42. * @par Concepts:
  43. * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
  44. */
  45. template <typename Stream>
  46. class buffered_write_stream
  47. : private noncopyable
  48. {
  49. public:
  50. /// The type of the next layer.
  51. typedef typename boost::remove_reference<Stream>::type next_layer_type;
  52. /// The type of the lowest layer.
  53. typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
  54. #if defined(GENERATING_DOCUMENTATION)
  55. /// The default buffer size.
  56. static const std::size_t default_buffer_size = implementation_defined;
  57. #else
  58. BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
  59. #endif
  60. /// Construct, passing the specified argument to initialise the next layer.
  61. template <typename Arg>
  62. explicit buffered_write_stream(Arg& a)
  63. : next_layer_(a),
  64. storage_(default_buffer_size)
  65. {
  66. }
  67. /// Construct, passing the specified argument to initialise the next layer.
  68. template <typename Arg>
  69. buffered_write_stream(Arg& a, std::size_t buffer_size)
  70. : next_layer_(a),
  71. storage_(buffer_size)
  72. {
  73. }
  74. /// Get a reference to the next layer.
  75. next_layer_type& next_layer()
  76. {
  77. return next_layer_;
  78. }
  79. /// Get a reference to the lowest layer.
  80. lowest_layer_type& lowest_layer()
  81. {
  82. return next_layer_.lowest_layer();
  83. }
  84. /// Get a const reference to the lowest layer.
  85. const lowest_layer_type& lowest_layer() const
  86. {
  87. return next_layer_.lowest_layer();
  88. }
  89. /// (Deprecated: use get_io_service().) Get the io_service associated with
  90. /// the object.
  91. boost::asio::io_service& io_service()
  92. {
  93. return next_layer_.get_io_service();
  94. }
  95. /// Get the io_service associated with the object.
  96. boost::asio::io_service& get_io_service()
  97. {
  98. return next_layer_.get_io_service();
  99. }
  100. /// Close the stream.
  101. void close()
  102. {
  103. next_layer_.close();
  104. }
  105. /// Close the stream.
  106. boost::system::error_code close(boost::system::error_code& ec)
  107. {
  108. return next_layer_.close(ec);
  109. }
  110. /// Flush all data from the buffer to the next layer. Returns the number of
  111. /// bytes written to the next layer on the last write operation. Throws an
  112. /// exception on failure.
  113. std::size_t flush()
  114. {
  115. std::size_t bytes_written = write(next_layer_,
  116. buffer(storage_.data(), storage_.size()));
  117. storage_.consume(bytes_written);
  118. return bytes_written;
  119. }
  120. /// Flush all data from the buffer to the next layer. Returns the number of
  121. /// bytes written to the next layer on the last write operation, or 0 if an
  122. /// error occurred.
  123. std::size_t flush(boost::system::error_code& ec)
  124. {
  125. std::size_t bytes_written = write(next_layer_,
  126. buffer(storage_.data(), storage_.size()),
  127. transfer_all(), ec);
  128. storage_.consume(bytes_written);
  129. return bytes_written;
  130. }
  131. template <typename WriteHandler>
  132. class flush_handler
  133. {
  134. public:
  135. flush_handler(boost::asio::io_service& io_service,
  136. detail::buffered_stream_storage& storage, WriteHandler handler)
  137. : io_service_(io_service),
  138. storage_(storage),
  139. handler_(handler)
  140. {
  141. }
  142. void operator()(const boost::system::error_code& ec,
  143. std::size_t bytes_written)
  144. {
  145. storage_.consume(bytes_written);
  146. io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_written));
  147. }
  148. private:
  149. boost::asio::io_service& io_service_;
  150. detail::buffered_stream_storage& storage_;
  151. WriteHandler handler_;
  152. };
  153. /// Start an asynchronous flush.
  154. template <typename WriteHandler>
  155. void async_flush(WriteHandler handler)
  156. {
  157. async_write(next_layer_, buffer(storage_.data(), storage_.size()),
  158. flush_handler<WriteHandler>(get_io_service(), storage_, handler));
  159. }
  160. /// Write the given data to the stream. Returns the number of bytes written.
  161. /// Throws an exception on failure.
  162. template <typename ConstBufferSequence>
  163. std::size_t write_some(const ConstBufferSequence& buffers)
  164. {
  165. typename ConstBufferSequence::const_iterator iter = buffers.begin();
  166. typename ConstBufferSequence::const_iterator end = buffers.end();
  167. size_t total_buffer_size = 0;
  168. for (; iter != end; ++iter)
  169. {
  170. boost::asio::const_buffer buffer(*iter);
  171. total_buffer_size += boost::asio::buffer_size(buffer);
  172. }
  173. if (total_buffer_size == 0)
  174. return 0;
  175. if (storage_.size() == storage_.capacity())
  176. flush();
  177. return copy(buffers);
  178. }
  179. /// Write the given data to the stream. Returns the number of bytes written,
  180. /// or 0 if an error occurred and the error handler did not throw.
  181. template <typename ConstBufferSequence>
  182. std::size_t write_some(const ConstBufferSequence& buffers,
  183. boost::system::error_code& ec)
  184. {
  185. ec = boost::system::error_code();
  186. typename ConstBufferSequence::const_iterator iter = buffers.begin();
  187. typename ConstBufferSequence::const_iterator end = buffers.end();
  188. size_t total_buffer_size = 0;
  189. for (; iter != end; ++iter)
  190. {
  191. boost::asio::const_buffer buffer(*iter);
  192. total_buffer_size += boost::asio::buffer_size(buffer);
  193. }
  194. if (total_buffer_size == 0)
  195. return 0;
  196. if (storage_.size() == storage_.capacity() && !flush(ec))
  197. return 0;
  198. return copy(buffers);
  199. }
  200. template <typename ConstBufferSequence, typename WriteHandler>
  201. class write_some_handler
  202. {
  203. public:
  204. write_some_handler(boost::asio::io_service& io_service,
  205. detail::buffered_stream_storage& storage,
  206. const ConstBufferSequence& buffers, WriteHandler handler)
  207. : io_service_(io_service),
  208. storage_(storage),
  209. buffers_(buffers),
  210. handler_(handler)
  211. {
  212. }
  213. void operator()(const boost::system::error_code& ec, std::size_t)
  214. {
  215. if (ec)
  216. {
  217. std::size_t length = 0;
  218. io_service_.dispatch(detail::bind_handler(handler_, ec, length));
  219. }
  220. else
  221. {
  222. using namespace std; // For memcpy.
  223. std::size_t orig_size = storage_.size();
  224. std::size_t space_avail = storage_.capacity() - orig_size;
  225. std::size_t bytes_copied = 0;
  226. typename ConstBufferSequence::const_iterator iter = buffers_.begin();
  227. typename ConstBufferSequence::const_iterator end = buffers_.end();
  228. for (; iter != end && space_avail > 0; ++iter)
  229. {
  230. std::size_t bytes_avail = buffer_size(*iter);
  231. std::size_t length = (bytes_avail < space_avail)
  232. ? bytes_avail : space_avail;
  233. storage_.resize(orig_size + bytes_copied + length);
  234. memcpy(storage_.data() + orig_size + bytes_copied,
  235. buffer_cast<const void*>(*iter), length);
  236. bytes_copied += length;
  237. space_avail -= length;
  238. }
  239. io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied));
  240. }
  241. }
  242. private:
  243. boost::asio::io_service& io_service_;
  244. detail::buffered_stream_storage& storage_;
  245. ConstBufferSequence buffers_;
  246. WriteHandler handler_;
  247. };
  248. /// Start an asynchronous write. The data being written must be valid for the
  249. /// lifetime of the asynchronous operation.
  250. template <typename ConstBufferSequence, typename WriteHandler>
  251. void async_write_some(const ConstBufferSequence& buffers,
  252. WriteHandler handler)
  253. {
  254. typename ConstBufferSequence::const_iterator iter = buffers.begin();
  255. typename ConstBufferSequence::const_iterator end = buffers.end();
  256. size_t total_buffer_size = 0;
  257. for (; iter != end; ++iter)
  258. {
  259. boost::asio::const_buffer buffer(*iter);
  260. total_buffer_size += boost::asio::buffer_size(buffer);
  261. }
  262. if (total_buffer_size == 0)
  263. {
  264. get_io_service().post(detail::bind_handler(
  265. handler, boost::system::error_code(), 0));
  266. }
  267. else if (storage_.size() == storage_.capacity())
  268. {
  269. async_flush(write_some_handler<ConstBufferSequence, WriteHandler>(
  270. get_io_service(), storage_, buffers, handler));
  271. }
  272. else
  273. {
  274. std::size_t bytes_copied = copy(buffers);
  275. get_io_service().post(detail::bind_handler(
  276. handler, boost::system::error_code(), bytes_copied));
  277. }
  278. }
  279. /// Read some data from the stream. Returns the number of bytes read. Throws
  280. /// an exception on failure.
  281. template <typename MutableBufferSequence>
  282. std::size_t read_some(const MutableBufferSequence& buffers)
  283. {
  284. return next_layer_.read_some(buffers);
  285. }
  286. /// Read some data from the stream. Returns the number of bytes read or 0 if
  287. /// an error occurred.
  288. template <typename MutableBufferSequence>
  289. std::size_t read_some(const MutableBufferSequence& buffers,
  290. boost::system::error_code& ec)
  291. {
  292. return next_layer_.read_some(buffers, ec);
  293. }
  294. /// Start an asynchronous read. The buffer into which the data will be read
  295. /// must be valid for the lifetime of the asynchronous operation.
  296. template <typename MutableBufferSequence, typename ReadHandler>
  297. void async_read_some(const MutableBufferSequence& buffers,
  298. ReadHandler handler)
  299. {
  300. next_layer_.async_read_some(buffers, handler);
  301. }
  302. /// Peek at the incoming data on the stream. Returns the number of bytes read.
  303. /// Throws an exception on failure.
  304. template <typename MutableBufferSequence>
  305. std::size_t peek(const MutableBufferSequence& buffers)
  306. {
  307. return next_layer_.peek(buffers);
  308. }
  309. /// Peek at the incoming data on the stream. Returns the number of bytes read,
  310. /// or 0 if an error occurred.
  311. template <typename MutableBufferSequence>
  312. std::size_t peek(const MutableBufferSequence& buffers,
  313. boost::system::error_code& ec)
  314. {
  315. return next_layer_.peek(buffers, ec);
  316. }
  317. /// Determine the amount of data that may be read without blocking.
  318. std::size_t in_avail()
  319. {
  320. return next_layer_.in_avail();
  321. }
  322. /// Determine the amount of data that may be read without blocking.
  323. std::size_t in_avail(boost::system::error_code& ec)
  324. {
  325. return next_layer_.in_avail(ec);
  326. }
  327. private:
  328. /// Copy data into the internal buffer from the specified source buffer.
  329. /// Returns the number of bytes copied.
  330. template <typename ConstBufferSequence>
  331. std::size_t copy(const ConstBufferSequence& buffers)
  332. {
  333. using namespace std; // For memcpy.
  334. std::size_t orig_size = storage_.size();
  335. std::size_t space_avail = storage_.capacity() - orig_size;
  336. std::size_t bytes_copied = 0;
  337. typename ConstBufferSequence::const_iterator iter = buffers.begin();
  338. typename ConstBufferSequence::const_iterator end = buffers.end();
  339. for (; iter != end && space_avail > 0; ++iter)
  340. {
  341. std::size_t bytes_avail = buffer_size(*iter);
  342. std::size_t length = (bytes_avail < space_avail)
  343. ? bytes_avail : space_avail;
  344. storage_.resize(orig_size + bytes_copied + length);
  345. memcpy(storage_.data() + orig_size + bytes_copied,
  346. buffer_cast<const void*>(*iter), length);
  347. bytes_copied += length;
  348. space_avail -= length;
  349. }
  350. return bytes_copied;
  351. }
  352. /// The next layer.
  353. Stream next_layer_;
  354. // The data in the buffer.
  355. detail::buffered_stream_storage storage_;
  356. };
  357. } // namespace asio
  358. } // namespace boost
  359. #include <boost/asio/detail/pop_options.hpp>
  360. #endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP