2 // impl/buffered_write_stream.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
12 #define BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/associated_allocator.hpp>
19 #include <boost/asio/associated_executor.hpp>
20 #include <boost/asio/detail/handler_alloc_helpers.hpp>
21 #include <boost/asio/detail/handler_cont_helpers.hpp>
22 #include <boost/asio/detail/handler_invoke_helpers.hpp>
23 #include <boost/asio/detail/handler_type_requirements.hpp>
24 #include <boost/asio/detail/non_const_lvalue.hpp>
26 #include <boost/asio/detail/push_options.hpp>
31 template <typename Stream>
32 std::size_t buffered_write_stream<Stream>::flush()
34 std::size_t bytes_written = write(next_layer_,
35 buffer(storage_.data(), storage_.size()));
36 storage_.consume(bytes_written);
40 template <typename Stream>
41 std::size_t buffered_write_stream<Stream>::flush(boost::system::error_code& ec)
43 std::size_t bytes_written = write(next_layer_,
44 buffer(storage_.data(), storage_.size()),
46 storage_.consume(bytes_written);
52 template <typename WriteHandler>
53 class buffered_flush_handler
56 buffered_flush_handler(detail::buffered_stream_storage& storage,
57 WriteHandler& handler)
59 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
63 #if defined(BOOST_ASIO_HAS_MOVE)
64 buffered_flush_handler(const buffered_flush_handler& other)
65 : storage_(other.storage_),
66 handler_(other.handler_)
70 buffered_flush_handler(buffered_flush_handler&& other)
71 : storage_(other.storage_),
72 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
75 #endif // defined(BOOST_ASIO_HAS_MOVE)
77 void operator()(const boost::system::error_code& ec,
78 const std::size_t bytes_written)
80 storage_.consume(bytes_written);
81 handler_(ec, bytes_written);
85 detail::buffered_stream_storage& storage_;
86 WriteHandler handler_;
89 template <typename WriteHandler>
90 inline void* asio_handler_allocate(std::size_t size,
91 buffered_flush_handler<WriteHandler>* this_handler)
93 return boost_asio_handler_alloc_helpers::allocate(
94 size, this_handler->handler_);
97 template <typename WriteHandler>
98 inline void asio_handler_deallocate(void* pointer, std::size_t size,
99 buffered_flush_handler<WriteHandler>* this_handler)
101 boost_asio_handler_alloc_helpers::deallocate(
102 pointer, size, this_handler->handler_);
105 template <typename WriteHandler>
106 inline bool asio_handler_is_continuation(
107 buffered_flush_handler<WriteHandler>* this_handler)
109 return boost_asio_handler_cont_helpers::is_continuation(
110 this_handler->handler_);
113 template <typename Function, typename WriteHandler>
114 inline void asio_handler_invoke(Function& function,
115 buffered_flush_handler<WriteHandler>* this_handler)
117 boost_asio_handler_invoke_helpers::invoke(
118 function, this_handler->handler_);
121 template <typename Function, typename WriteHandler>
122 inline void asio_handler_invoke(const Function& function,
123 buffered_flush_handler<WriteHandler>* this_handler)
125 boost_asio_handler_invoke_helpers::invoke(
126 function, this_handler->handler_);
129 template <typename Stream>
130 class initiate_async_buffered_flush
133 typedef typename remove_reference<
134 Stream>::type::lowest_layer_type::executor_type executor_type;
136 explicit initiate_async_buffered_flush(Stream& next_layer)
137 : next_layer_(next_layer)
141 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
143 return next_layer_.lowest_layer().get_executor();
146 template <typename WriteHandler>
147 void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
148 buffered_stream_storage* storage) const
150 // If you get an error on the following line it means that your handler
151 // does not meet the documented type requirements for a WriteHandler.
152 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
154 non_const_lvalue<WriteHandler> handler2(handler);
155 async_write(next_layer_, buffer(storage->data(), storage->size()),
156 buffered_flush_handler<typename decay<WriteHandler>::type>(
157 *storage, handler2.value));
163 } // namespace detail
165 #if !defined(GENERATING_DOCUMENTATION)
167 template <typename WriteHandler, typename Allocator>
168 struct associated_allocator<
169 detail::buffered_flush_handler<WriteHandler>, Allocator>
171 typedef typename associated_allocator<WriteHandler, Allocator>::type type;
173 static type get(const detail::buffered_flush_handler<WriteHandler>& h,
174 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
176 return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
180 template <typename WriteHandler, typename Executor>
181 struct associated_executor<
182 detail::buffered_flush_handler<WriteHandler>, Executor>
184 typedef typename associated_executor<WriteHandler, Executor>::type type;
186 static type get(const detail::buffered_flush_handler<WriteHandler>& h,
187 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
189 return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
193 #endif // !defined(GENERATING_DOCUMENTATION)
195 template <typename Stream>
197 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
198 std::size_t)) WriteHandler>
199 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
200 void (boost::system::error_code, std::size_t))
201 buffered_write_stream<Stream>::async_flush(
202 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
204 return async_initiate<WriteHandler,
205 void (boost::system::error_code, std::size_t)>(
206 detail::initiate_async_buffered_flush<Stream>(next_layer_),
210 template <typename Stream>
211 template <typename ConstBufferSequence>
212 std::size_t buffered_write_stream<Stream>::write_some(
213 const ConstBufferSequence& buffers)
215 using boost::asio::buffer_size;
216 if (buffer_size(buffers) == 0)
219 if (storage_.size() == storage_.capacity())
222 return this->copy(buffers);
225 template <typename Stream>
226 template <typename ConstBufferSequence>
227 std::size_t buffered_write_stream<Stream>::write_some(
228 const ConstBufferSequence& buffers, boost::system::error_code& ec)
230 ec = boost::system::error_code();
232 using boost::asio::buffer_size;
233 if (buffer_size(buffers) == 0)
236 if (storage_.size() == storage_.capacity() && !flush(ec))
239 return this->copy(buffers);
244 template <typename ConstBufferSequence, typename WriteHandler>
245 class buffered_write_some_handler
248 buffered_write_some_handler(detail::buffered_stream_storage& storage,
249 const ConstBufferSequence& buffers, WriteHandler& handler)
252 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
256 #if defined(BOOST_ASIO_HAS_MOVE)
257 buffered_write_some_handler(const buffered_write_some_handler& other)
258 : storage_(other.storage_),
259 buffers_(other.buffers_),
260 handler_(other.handler_)
264 buffered_write_some_handler(buffered_write_some_handler&& other)
265 : storage_(other.storage_),
266 buffers_(other.buffers_),
267 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
270 #endif // defined(BOOST_ASIO_HAS_MOVE)
272 void operator()(const boost::system::error_code& ec, std::size_t)
276 const std::size_t length = 0;
277 handler_(ec, length);
281 using boost::asio::buffer_size;
282 std::size_t orig_size = storage_.size();
283 std::size_t space_avail = storage_.capacity() - orig_size;
284 std::size_t bytes_avail = buffer_size(buffers_);
285 std::size_t length = bytes_avail < space_avail
286 ? bytes_avail : space_avail;
287 storage_.resize(orig_size + length);
288 const std::size_t bytes_copied = boost::asio::buffer_copy(
289 storage_.data() + orig_size, buffers_, length);
290 handler_(ec, bytes_copied);
295 detail::buffered_stream_storage& storage_;
296 ConstBufferSequence buffers_;
297 WriteHandler handler_;
300 template <typename ConstBufferSequence, typename WriteHandler>
301 inline void* asio_handler_allocate(std::size_t size,
302 buffered_write_some_handler<
303 ConstBufferSequence, WriteHandler>* this_handler)
305 return boost_asio_handler_alloc_helpers::allocate(
306 size, this_handler->handler_);
309 template <typename ConstBufferSequence, typename WriteHandler>
310 inline void asio_handler_deallocate(void* pointer, std::size_t size,
311 buffered_write_some_handler<
312 ConstBufferSequence, WriteHandler>* this_handler)
314 boost_asio_handler_alloc_helpers::deallocate(
315 pointer, size, this_handler->handler_);
318 template <typename ConstBufferSequence, typename WriteHandler>
319 inline bool asio_handler_is_continuation(
320 buffered_write_some_handler<
321 ConstBufferSequence, WriteHandler>* this_handler)
323 return boost_asio_handler_cont_helpers::is_continuation(
324 this_handler->handler_);
327 template <typename Function, typename ConstBufferSequence,
328 typename WriteHandler>
329 inline void asio_handler_invoke(Function& function,
330 buffered_write_some_handler<
331 ConstBufferSequence, WriteHandler>* this_handler)
333 boost_asio_handler_invoke_helpers::invoke(
334 function, this_handler->handler_);
337 template <typename Function, typename ConstBufferSequence,
338 typename WriteHandler>
339 inline void asio_handler_invoke(const Function& function,
340 buffered_write_some_handler<
341 ConstBufferSequence, WriteHandler>* this_handler)
343 boost_asio_handler_invoke_helpers::invoke(
344 function, this_handler->handler_);
347 template <typename Stream>
348 class initiate_async_buffered_write_some
351 typedef typename remove_reference<
352 Stream>::type::lowest_layer_type::executor_type executor_type;
354 explicit initiate_async_buffered_write_some(Stream& next_layer)
355 : next_layer_(next_layer)
359 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
361 return next_layer_.lowest_layer().get_executor();
364 template <typename WriteHandler, typename ConstBufferSequence>
365 void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
366 buffered_stream_storage* storage,
367 const ConstBufferSequence& buffers) const
369 // If you get an error on the following line it means that your handler
370 // does not meet the documented type requirements for a WriteHandler.
371 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
373 using boost::asio::buffer_size;
374 non_const_lvalue<WriteHandler> handler2(handler);
375 if (buffer_size(buffers) == 0 || storage->size() < storage->capacity())
377 next_layer_.async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0),
378 buffered_write_some_handler<ConstBufferSequence,
379 typename decay<WriteHandler>::type>(
380 *storage, buffers, handler2.value));
384 initiate_async_buffered_flush<Stream>(this->next_layer_)(
385 buffered_write_some_handler<ConstBufferSequence,
386 typename decay<WriteHandler>::type>(
387 *storage, buffers, handler2.value),
395 } // namespace detail
397 #if !defined(GENERATING_DOCUMENTATION)
399 template <typename ConstBufferSequence,
400 typename WriteHandler, typename Allocator>
401 struct associated_allocator<
402 detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
405 typedef typename associated_allocator<WriteHandler, Allocator>::type type;
408 const detail::buffered_write_some_handler<
409 ConstBufferSequence, WriteHandler>& h,
410 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
412 return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
416 template <typename ConstBufferSequence,
417 typename WriteHandler, typename Executor>
418 struct associated_executor<
419 detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
422 typedef typename associated_executor<WriteHandler, Executor>::type type;
425 const detail::buffered_write_some_handler<
426 ConstBufferSequence, WriteHandler>& h,
427 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
429 return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
433 #endif // !defined(GENERATING_DOCUMENTATION)
435 template <typename Stream>
436 template <typename ConstBufferSequence,
437 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
438 std::size_t)) WriteHandler>
439 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
440 void (boost::system::error_code, std::size_t))
441 buffered_write_stream<Stream>::async_write_some(
442 const ConstBufferSequence& buffers,
443 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
445 return async_initiate<WriteHandler,
446 void (boost::system::error_code, std::size_t)>(
447 detail::initiate_async_buffered_write_some<Stream>(next_layer_),
448 handler, &storage_, buffers);
451 template <typename Stream>
452 template <typename ConstBufferSequence>
453 std::size_t buffered_write_stream<Stream>::copy(
454 const ConstBufferSequence& buffers)
456 using boost::asio::buffer_size;
457 std::size_t orig_size = storage_.size();
458 std::size_t space_avail = storage_.capacity() - orig_size;
459 std::size_t bytes_avail = buffer_size(buffers);
460 std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
461 storage_.resize(orig_size + length);
462 return boost::asio::buffer_copy(
463 storage_.data() + orig_size, buffers, length);
469 #include <boost/asio/detail/pop_options.hpp>
471 #endif // BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP