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
11#ifndef BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
12#define BOOST_ASIO_IMPL_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/handler_alloc_helpers.hpp>
19#include <boost/asio/detail/handler_cont_helpers.hpp>
20#include <boost/asio/detail/handler_invoke_helpers.hpp>
21#include <boost/asio/detail/handler_type_requirements.hpp>
22
23#include <boost/asio/detail/push_options.hpp>
24
25namespace boost {
26namespace asio {
27
28template <typename Stream>
29std::size_t buffered_write_stream<Stream>::flush()
30{
31 std::size_t bytes_written = write(next_layer_,
32 buffer(storage_.data(), storage_.size()));
33 storage_.consume(bytes_written);
34 return bytes_written;
35}
36
37template <typename Stream>
38std::size_t buffered_write_stream<Stream>::flush(boost::system::error_code& ec)
39{
40 std::size_t bytes_written = write(next_layer_,
41 buffer(storage_.data(), storage_.size()),
42 transfer_all(), ec);
43 storage_.consume(bytes_written);
44 return bytes_written;
45}
46
47namespace detail
48{
49 template <typename WriteHandler>
50 class buffered_flush_handler
51 {
52 public:
53 buffered_flush_handler(detail::buffered_stream_storage& storage,
54 WriteHandler& handler)
55 : storage_(storage),
56 handler_(handler)
57 {
58 }
59
60#if defined(BOOST_ASIO_HAS_MOVE)
61 buffered_flush_handler(const buffered_flush_handler& other)
62 : storage_(other.storage_),
63 handler_(other.handler_)
64 {
65 }
66
67 buffered_flush_handler(buffered_flush_handler&& other)
68 : storage_(other.storage_),
69 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
70 {
71 }
72#endif // defined(BOOST_ASIO_HAS_MOVE)
73
74 void operator()(const boost::system::error_code& ec,
75 const std::size_t bytes_written)
76 {
77 storage_.consume(bytes_written);
78 handler_(ec, bytes_written);
79 }
80
81 //private:
82 detail::buffered_stream_storage& storage_;
83 WriteHandler handler_;
84 };
85
86 template <typename WriteHandler>
87 inline void* asio_handler_allocate(std::size_t size,
88 buffered_flush_handler<WriteHandler>* this_handler)
89 {
90 return boost_asio_handler_alloc_helpers::allocate(
91 size, this_handler->handler_);
92 }
93
94 template <typename WriteHandler>
95 inline void asio_handler_deallocate(void* pointer, std::size_t size,
96 buffered_flush_handler<WriteHandler>* this_handler)
97 {
98 boost_asio_handler_alloc_helpers::deallocate(
99 pointer, size, this_handler->handler_);
100 }
101
102 template <typename WriteHandler>
103 inline bool asio_handler_is_continuation(
104 buffered_flush_handler<WriteHandler>* this_handler)
105 {
106 return boost_asio_handler_cont_helpers::is_continuation(
107 this_handler->handler_);
108 }
109
110 template <typename Function, typename WriteHandler>
111 inline void asio_handler_invoke(Function& function,
112 buffered_flush_handler<WriteHandler>* this_handler)
113 {
114 boost_asio_handler_invoke_helpers::invoke(
115 function, this_handler->handler_);
116 }
117
118 template <typename Function, typename WriteHandler>
119 inline void asio_handler_invoke(const Function& function,
120 buffered_flush_handler<WriteHandler>* this_handler)
121 {
122 boost_asio_handler_invoke_helpers::invoke(
123 function, this_handler->handler_);
124 }
125}
126
127template <typename Stream>
128template <typename WriteHandler>
129BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
130 void (boost::system::error_code, std::size_t))
131buffered_write_stream<Stream>::async_flush(
132 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
133{
134 // If you get an error on the following line it means that your handler does
135 // not meet the documented type requirements for a WriteHandler.
136 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
137
138 detail::async_result_init<
139 WriteHandler, void (boost::system::error_code, std::size_t)> init(
140 BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
141
142 async_write(next_layer_, buffer(storage_.data(), storage_.size()),
143 detail::buffered_flush_handler<BOOST_ASIO_HANDLER_TYPE(
144 WriteHandler, void (boost::system::error_code, std::size_t))>(
145 storage_, init.handler));
146
147 return init.result.get();
148}
149
150template <typename Stream>
151template <typename ConstBufferSequence>
152std::size_t buffered_write_stream<Stream>::write_some(
153 const ConstBufferSequence& buffers)
154{
155 if (boost::asio::buffer_size(buffers) == 0)
156 return 0;
157
158 if (storage_.size() == storage_.capacity())
159 this->flush();
160
161 return this->copy(buffers);
162}
163
164template <typename Stream>
165template <typename ConstBufferSequence>
166std::size_t buffered_write_stream<Stream>::write_some(
167 const ConstBufferSequence& buffers, boost::system::error_code& ec)
168{
169 ec = boost::system::error_code();
170
171 if (boost::asio::buffer_size(buffers) == 0)
172 return 0;
173
174 if (storage_.size() == storage_.capacity() && !flush(ec))
175 return 0;
176
177 return this->copy(buffers);
178}
179
180namespace detail
181{
182 template <typename ConstBufferSequence, typename WriteHandler>
183 class buffered_write_some_handler
184 {
185 public:
186 buffered_write_some_handler(detail::buffered_stream_storage& storage,
187 const ConstBufferSequence& buffers, WriteHandler& handler)
188 : storage_(storage),
189 buffers_(buffers),
190 handler_(handler)
191 {
192 }
193
194#if defined(BOOST_ASIO_HAS_MOVE)
195 buffered_write_some_handler(const buffered_write_some_handler& other)
196 : storage_(other.storage_),
197 buffers_(other.buffers_),
198 handler_(other.handler_)
199 {
200 }
201
202 buffered_write_some_handler(buffered_write_some_handler&& other)
203 : storage_(other.storage_),
204 buffers_(other.buffers_),
205 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
206 {
207 }
208#endif // defined(BOOST_ASIO_HAS_MOVE)
209
210 void operator()(const boost::system::error_code& ec, std::size_t)
211 {
212 if (ec)
213 {
214 const std::size_t length = 0;
215 handler_(ec, length);
216 }
217 else
218 {
219 std::size_t orig_size = storage_.size();
220 std::size_t space_avail = storage_.capacity() - orig_size;
221 std::size_t bytes_avail = boost::asio::buffer_size(buffers_);
222 std::size_t length = bytes_avail < space_avail
223 ? bytes_avail : space_avail;
224 storage_.resize(orig_size + length);
225 const std::size_t bytes_copied = boost::asio::buffer_copy(
226 storage_.data() + orig_size, buffers_, length);
227 handler_(ec, bytes_copied);
228 }
229 }
230
231 //private:
232 detail::buffered_stream_storage& storage_;
233 ConstBufferSequence buffers_;
234 WriteHandler handler_;
235 };
236
237 template <typename ConstBufferSequence, typename WriteHandler>
238 inline void* asio_handler_allocate(std::size_t size,
239 buffered_write_some_handler<
240 ConstBufferSequence, WriteHandler>* this_handler)
241 {
242 return boost_asio_handler_alloc_helpers::allocate(
243 size, this_handler->handler_);
244 }
245
246 template <typename ConstBufferSequence, typename WriteHandler>
247 inline void asio_handler_deallocate(void* pointer, std::size_t size,
248 buffered_write_some_handler<
249 ConstBufferSequence, WriteHandler>* this_handler)
250 {
251 boost_asio_handler_alloc_helpers::deallocate(
252 pointer, size, this_handler->handler_);
253 }
254
255 template <typename ConstBufferSequence, typename WriteHandler>
256 inline bool asio_handler_is_continuation(
257 buffered_write_some_handler<
258 ConstBufferSequence, WriteHandler>* this_handler)
259 {
260 return boost_asio_handler_cont_helpers::is_continuation(
261 this_handler->handler_);
262 }
263
264 template <typename Function, typename ConstBufferSequence,
265 typename WriteHandler>
266 inline void asio_handler_invoke(Function& function,
267 buffered_write_some_handler<
268 ConstBufferSequence, WriteHandler>* this_handler)
269 {
270 boost_asio_handler_invoke_helpers::invoke(
271 function, this_handler->handler_);
272 }
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} // namespace detail
284
285template <typename Stream>
286template <typename ConstBufferSequence, typename WriteHandler>
287BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
288 void (boost::system::error_code, std::size_t))
289buffered_write_stream<Stream>::async_write_some(
290 const ConstBufferSequence& buffers,
291 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
292{
293 // If you get an error on the following line it means that your handler does
294 // not meet the documented type requirements for a WriteHandler.
295 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
296
297 detail::async_result_init<
298 WriteHandler, void (boost::system::error_code, std::size_t)> init(
299 BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
300
301 if (boost::asio::buffer_size(buffers) == 0
302 || storage_.size() < storage_.capacity())
303 {
304 next_layer_.async_write_some(boost::asio::const_buffers_1(0, 0),
305 detail::buffered_write_some_handler<
306 ConstBufferSequence, BOOST_ASIO_HANDLER_TYPE(
307 WriteHandler, void (boost::system::error_code, std::size_t))>(
308 storage_, buffers, init.handler));
309 }
310 else
311 {
312 this->async_flush(detail::buffered_write_some_handler<
313 ConstBufferSequence, BOOST_ASIO_HANDLER_TYPE(
314 WriteHandler, void (boost::system::error_code, std::size_t))>(
315 storage_, buffers, init.handler));
316 }
317
318 return init.result.get();
319}
320
321template <typename Stream>
322template <typename ConstBufferSequence>
323std::size_t buffered_write_stream<Stream>::copy(
324 const ConstBufferSequence& buffers)
325{
326 std::size_t orig_size = storage_.size();
327 std::size_t space_avail = storage_.capacity() - orig_size;
328 std::size_t bytes_avail = boost::asio::buffer_size(buffers);
329 std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
330 storage_.resize(orig_size + length);
331 return boost::asio::buffer_copy(
332 storage_.data() + orig_size, buffers, length);
333}
334
335} // namespace asio
336} // namespace boost
337
338#include <boost/asio/detail/pop_options.hpp>
339
340#endif // BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
341