1 //
2 // buffered_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 
11 #ifndef BOOST_ASIO_BUFFERED_STREAM_HPP
12 #define BOOST_ASIO_BUFFERED_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/async_result.hpp>
21 #include <boost/asio/buffered_read_stream.hpp>
22 #include <boost/asio/buffered_write_stream.hpp>
23 #include <boost/asio/buffered_stream_fwd.hpp>
24 #include <boost/asio/detail/noncopyable.hpp>
25 #include <boost/asio/error.hpp>
26 
27 #include <boost/asio/detail/push_options.hpp>
28 
29 namespace boost {
30 namespace asio {
31 
32 /// Adds buffering to the read- and write-related operations of a stream.
33 /**
34  * The buffered_stream class template can be used to add buffering to the
35  * synchronous and asynchronous read and write operations of a stream.
36  *
37  * @par Thread Safety
38  * @e Distinct @e objects: Safe.@n
39  * @e Shared @e objects: Unsafe.
40  *
41  * @par Concepts:
42  * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
43  */
44 template <typename Stream>
45 class buffered_stream
46   : private noncopyable
47 {
48 public:
49   /// The type of the next layer.
50   typedef typename remove_reference<Stream>::type next_layer_type;
51 
52   /// The type of the lowest layer.
53   typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
54 
55   /// The type of the executor associated with the object.
56   typedef typename lowest_layer_type::executor_type executor_type;
57 
58   /// Construct, passing the specified argument to initialise the next layer.
59   template <typename Arg>
buffered_stream(Arg & a)60   explicit buffered_stream(Arg& a)
61     : inner_stream_impl_(a),
62       stream_impl_(inner_stream_impl_)
63   {
64   }
65 
66   /// Construct, passing the specified argument to initialise the next layer.
67   template <typename Arg>
buffered_stream(Arg & a,std::size_t read_buffer_size,std::size_t write_buffer_size)68   explicit buffered_stream(Arg& a, std::size_t read_buffer_size,
69       std::size_t write_buffer_size)
70     : inner_stream_impl_(a, write_buffer_size),
71       stream_impl_(inner_stream_impl_, read_buffer_size)
72   {
73   }
74 
75   /// Get a reference to the next layer.
next_layer()76   next_layer_type& next_layer()
77   {
78     return stream_impl_.next_layer().next_layer();
79   }
80 
81   /// Get a reference to the lowest layer.
lowest_layer()82   lowest_layer_type& lowest_layer()
83   {
84     return stream_impl_.lowest_layer();
85   }
86 
87   /// Get a const reference to the lowest layer.
lowest_layer() const88   const lowest_layer_type& lowest_layer() const
89   {
90     return stream_impl_.lowest_layer();
91   }
92 
93   /// Get the executor associated with the object.
get_executor()94   executor_type get_executor() BOOST_ASIO_NOEXCEPT
95   {
96     return stream_impl_.lowest_layer().get_executor();
97   }
98 
99   /// Close the stream.
close()100   void close()
101   {
102     stream_impl_.close();
103   }
104 
105   /// Close the stream.
close(boost::system::error_code & ec)106   BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
107   {
108     stream_impl_.close(ec);
109     BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
110   }
111 
112   /// Flush all data from the buffer to the next layer. Returns the number of
113   /// bytes written to the next layer on the last write operation. Throws an
114   /// exception on failure.
flush()115   std::size_t flush()
116   {
117     return stream_impl_.next_layer().flush();
118   }
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.
flush(boost::system::error_code & ec)123   std::size_t flush(boost::system::error_code& ec)
124   {
125     return stream_impl_.next_layer().flush(ec);
126   }
127 
128   /// Start an asynchronous flush.
129   template <
130       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
131         std::size_t)) WriteHandler
132           BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,void (boost::system::error_code,std::size_t))133   BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
134       void (boost::system::error_code, std::size_t))
135   async_flush(
136       BOOST_ASIO_MOVE_ARG(WriteHandler) handler
137         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
138   {
139     return stream_impl_.next_layer().async_flush(
140         BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
141   }
142 
143   /// Write the given data to the stream. Returns the number of bytes written.
144   /// Throws an exception on failure.
145   template <typename ConstBufferSequence>
write_some(const ConstBufferSequence & buffers)146   std::size_t write_some(const ConstBufferSequence& buffers)
147   {
148     return stream_impl_.write_some(buffers);
149   }
150 
151   /// Write the given data to the stream. Returns the number of bytes written,
152   /// or 0 if an error occurred.
153   template <typename ConstBufferSequence>
write_some(const ConstBufferSequence & buffers,boost::system::error_code & ec)154   std::size_t write_some(const ConstBufferSequence& buffers,
155       boost::system::error_code& ec)
156   {
157     return stream_impl_.write_some(buffers, ec);
158   }
159 
160   /// Start an asynchronous write. The data being written must be valid for the
161   /// lifetime of the asynchronous operation.
162   template <typename ConstBufferSequence,
163       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
164         std::size_t)) WriteHandler
165           BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,void (boost::system::error_code,std::size_t))166   BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
167       void (boost::system::error_code, std::size_t))
168   async_write_some(const ConstBufferSequence& buffers,
169       BOOST_ASIO_MOVE_ARG(WriteHandler) handler
170         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
171   {
172     return stream_impl_.async_write_some(buffers,
173         BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
174   }
175 
176   /// Fill the buffer with some data. Returns the number of bytes placed in the
177   /// buffer as a result of the operation. Throws an exception on failure.
fill()178   std::size_t fill()
179   {
180     return stream_impl_.fill();
181   }
182 
183   /// Fill the buffer with some data. Returns the number of bytes placed in the
184   /// buffer as a result of the operation, or 0 if an error occurred.
fill(boost::system::error_code & ec)185   std::size_t fill(boost::system::error_code& ec)
186   {
187     return stream_impl_.fill(ec);
188   }
189 
190   /// Start an asynchronous fill.
191   template <
192       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
193         std::size_t)) ReadHandler
194           BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,void (boost::system::error_code,std::size_t))195   BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
196       void (boost::system::error_code, std::size_t))
197   async_fill(
198       BOOST_ASIO_MOVE_ARG(ReadHandler) handler
199         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
200   {
201     return stream_impl_.async_fill(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
202   }
203 
204   /// Read some data from the stream. Returns the number of bytes read. Throws
205   /// an exception on failure.
206   template <typename MutableBufferSequence>
read_some(const MutableBufferSequence & buffers)207   std::size_t read_some(const MutableBufferSequence& buffers)
208   {
209     return stream_impl_.read_some(buffers);
210   }
211 
212   /// Read some data from the stream. Returns the number of bytes read or 0 if
213   /// an error occurred.
214   template <typename MutableBufferSequence>
read_some(const MutableBufferSequence & buffers,boost::system::error_code & ec)215   std::size_t read_some(const MutableBufferSequence& buffers,
216       boost::system::error_code& ec)
217   {
218     return stream_impl_.read_some(buffers, ec);
219   }
220 
221   /// Start an asynchronous read. The buffer into which the data will be read
222   /// must be valid for the lifetime of the asynchronous operation.
223   template <typename MutableBufferSequence,
224       BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
225         std::size_t)) ReadHandler
226           BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,void (boost::system::error_code,std::size_t))227   BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
228       void (boost::system::error_code, std::size_t))
229   async_read_some(const MutableBufferSequence& buffers,
230       BOOST_ASIO_MOVE_ARG(ReadHandler) handler
231         BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
232   {
233     return stream_impl_.async_read_some(buffers,
234         BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
235   }
236 
237   /// Peek at the incoming data on the stream. Returns the number of bytes read.
238   /// Throws an exception on failure.
239   template <typename MutableBufferSequence>
peek(const MutableBufferSequence & buffers)240   std::size_t peek(const MutableBufferSequence& buffers)
241   {
242     return stream_impl_.peek(buffers);
243   }
244 
245   /// Peek at the incoming data on the stream. Returns the number of bytes read,
246   /// or 0 if an error occurred.
247   template <typename MutableBufferSequence>
peek(const MutableBufferSequence & buffers,boost::system::error_code & ec)248   std::size_t peek(const MutableBufferSequence& buffers,
249       boost::system::error_code& ec)
250   {
251     return stream_impl_.peek(buffers, ec);
252   }
253 
254   /// Determine the amount of data that may be read without blocking.
in_avail()255   std::size_t in_avail()
256   {
257     return stream_impl_.in_avail();
258   }
259 
260   /// Determine the amount of data that may be read without blocking.
in_avail(boost::system::error_code & ec)261   std::size_t in_avail(boost::system::error_code& ec)
262   {
263     return stream_impl_.in_avail(ec);
264   }
265 
266 private:
267   // The buffered write stream.
268   typedef buffered_write_stream<Stream> write_stream_type;
269   write_stream_type inner_stream_impl_;
270 
271   // The buffered read stream.
272   typedef buffered_read_stream<write_stream_type&> read_stream_type;
273   read_stream_type stream_impl_;
274 };
275 
276 } // namespace asio
277 } // namespace boost
278 
279 #include <boost/asio/detail/pop_options.hpp>
280 
281 #endif // BOOST_ASIO_BUFFERED_STREAM_HPP
282