1 //
2 // 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 
11 #ifndef BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP
12 #define BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/config.hpp>
19 #include <cstddef>
20 #include <boost/asio/buffered_write_stream_fwd.hpp>
21 #include <boost/asio/buffer.hpp>
22 #include <boost/asio/completion_condition.hpp>
23 #include <boost/asio/detail/bind_handler.hpp>
24 #include <boost/asio/detail/buffered_stream_storage.hpp>
25 #include <boost/asio/detail/noncopyable.hpp>
26 #include <boost/asio/detail/type_traits.hpp>
27 #include <boost/asio/error.hpp>
28 #include <boost/asio/io_service.hpp>
29 #include <boost/asio/write.hpp>
30 
31 #include <boost/asio/detail/push_options.hpp>
32 
33 namespace boost {
34 namespace asio {
35 
36 /// Adds buffering to the write-related operations of a stream.
37 /**
38  * The buffered_write_stream class template can be used to add buffering to the
39  * synchronous and asynchronous write operations of a stream.
40  *
41  * @par Thread Safety
42  * @e Distinct @e objects: Safe.@n
43  * @e Shared @e objects: Unsafe.
44  *
45  * @par Concepts:
46  * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
47  */
48 template <typename Stream>
49 class buffered_write_stream
50   : private noncopyable
51 {
52 public:
53   /// The type of the next layer.
54   typedef typename remove_reference<Stream>::type next_layer_type;
55 
56   /// The type of the lowest layer.
57   typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
58 
59 #if defined(GENERATING_DOCUMENTATION)
60   /// The default buffer size.
61   static const std::size_t default_buffer_size = implementation_defined;
62 #else
63   BOOST_ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
64 #endif
65 
66   /// Construct, passing the specified argument to initialise the next layer.
67   template <typename Arg>
buffered_write_stream(Arg & a)68   explicit buffered_write_stream(Arg& a)
69     : next_layer_(a),
70       storage_(default_buffer_size)
71   {
72   }
73 
74   /// Construct, passing the specified argument to initialise the next layer.
75   template <typename Arg>
buffered_write_stream(Arg & a,std::size_t buffer_size)76   buffered_write_stream(Arg& a, std::size_t buffer_size)
77     : next_layer_(a),
78       storage_(buffer_size)
79   {
80   }
81 
82   /// Get a reference to the next layer.
next_layer()83   next_layer_type& next_layer()
84   {
85     return next_layer_;
86   }
87 
88   /// Get a reference to the lowest layer.
lowest_layer()89   lowest_layer_type& lowest_layer()
90   {
91     return next_layer_.lowest_layer();
92   }
93 
94   /// Get a const reference to the lowest layer.
lowest_layer() const95   const lowest_layer_type& lowest_layer() const
96   {
97     return next_layer_.lowest_layer();
98   }
99 
100   /// Get the io_service associated with the object.
get_io_service()101   boost::asio::io_service& get_io_service()
102   {
103     return next_layer_.get_io_service();
104   }
105 
106   /// Close the stream.
close()107   void close()
108   {
109     next_layer_.close();
110   }
111 
112   /// Close the stream.
close(boost::system::error_code & ec)113   boost::system::error_code close(boost::system::error_code& ec)
114   {
115     return next_layer_.close(ec);
116   }
117 
118   /// Flush all data from the buffer to the next layer. Returns the number of
119   /// bytes written to the next layer on the last write operation. Throws an
120   /// exception on failure.
121   std::size_t flush();
122 
123   /// Flush all data from the buffer to the next layer. Returns the number of
124   /// bytes written to the next layer on the last write operation, or 0 if an
125   /// error occurred.
126   std::size_t flush(boost::system::error_code& ec);
127 
128   /// Start an asynchronous flush.
129   template <typename WriteHandler>
130   BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
131       void (boost::system::error_code, std::size_t))
132   async_flush(BOOST_ASIO_MOVE_ARG(WriteHandler) handler);
133 
134   /// Write the given data to the stream. Returns the number of bytes written.
135   /// Throws an exception on failure.
136   template <typename ConstBufferSequence>
137   std::size_t write_some(const ConstBufferSequence& buffers);
138 
139   /// Write the given data to the stream. Returns the number of bytes written,
140   /// or 0 if an error occurred and the error handler did not throw.
141   template <typename ConstBufferSequence>
142   std::size_t write_some(const ConstBufferSequence& buffers,
143       boost::system::error_code& ec);
144 
145   /// Start an asynchronous write. The data being written must be valid for the
146   /// lifetime of the asynchronous operation.
147   template <typename ConstBufferSequence, typename WriteHandler>
148   BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
149       void (boost::system::error_code, std::size_t))
150   async_write_some(const ConstBufferSequence& buffers,
151       BOOST_ASIO_MOVE_ARG(WriteHandler) handler);
152 
153   /// Read some data from the stream. Returns the number of bytes read. Throws
154   /// an exception on failure.
155   template <typename MutableBufferSequence>
read_some(const MutableBufferSequence & buffers)156   std::size_t read_some(const MutableBufferSequence& buffers)
157   {
158     return next_layer_.read_some(buffers);
159   }
160 
161   /// Read some data from the stream. Returns the number of bytes read or 0 if
162   /// an error occurred.
163   template <typename MutableBufferSequence>
read_some(const MutableBufferSequence & buffers,boost::system::error_code & ec)164   std::size_t read_some(const MutableBufferSequence& buffers,
165       boost::system::error_code& ec)
166   {
167     return next_layer_.read_some(buffers, ec);
168   }
169 
170   /// Start an asynchronous read. The buffer into which the data will be read
171   /// must be valid for the lifetime of the asynchronous operation.
172   template <typename MutableBufferSequence, typename ReadHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,void (boost::system::error_code,std::size_t))173   BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
174       void (boost::system::error_code, std::size_t))
175   async_read_some(const MutableBufferSequence& buffers,
176       BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
177   {
178     detail::async_result_init<
179       ReadHandler, void (boost::system::error_code, std::size_t)> init(
180         BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
181 
182     next_layer_.async_read_some(buffers,
183         BOOST_ASIO_MOVE_CAST(BOOST_ASIO_HANDLER_TYPE(ReadHandler,
184             void (boost::system::error_code, std::size_t)))(init.handler));
185 
186     return init.result.get();
187   }
188 
189   /// Peek at the incoming data on the stream. Returns the number of bytes read.
190   /// Throws an exception on failure.
191   template <typename MutableBufferSequence>
peek(const MutableBufferSequence & buffers)192   std::size_t peek(const MutableBufferSequence& buffers)
193   {
194     return next_layer_.peek(buffers);
195   }
196 
197   /// Peek at the incoming data on the stream. Returns the number of bytes read,
198   /// or 0 if an error occurred.
199   template <typename MutableBufferSequence>
peek(const MutableBufferSequence & buffers,boost::system::error_code & ec)200   std::size_t peek(const MutableBufferSequence& buffers,
201       boost::system::error_code& ec)
202   {
203     return next_layer_.peek(buffers, ec);
204   }
205 
206   /// Determine the amount of data that may be read without blocking.
in_avail()207   std::size_t in_avail()
208   {
209     return next_layer_.in_avail();
210   }
211 
212   /// Determine the amount of data that may be read without blocking.
in_avail(boost::system::error_code & ec)213   std::size_t in_avail(boost::system::error_code& ec)
214   {
215     return next_layer_.in_avail(ec);
216   }
217 
218 private:
219   /// Copy data into the internal buffer from the specified source buffer.
220   /// Returns the number of bytes copied.
221   template <typename ConstBufferSequence>
222   std::size_t copy(const ConstBufferSequence& buffers);
223 
224   /// The next layer.
225   Stream next_layer_;
226 
227   // The data in the buffer.
228   detail::buffered_stream_storage storage_;
229 };
230 
231 } // namespace asio
232 } // namespace boost
233 
234 #include <boost/asio/detail/pop_options.hpp>
235 
236 #include <boost/asio/impl/buffered_write_stream.hpp>
237 
238 #endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP
239