2 // impl/buffered_write_stream.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2022 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/associator.hpp>
19 #include <boost/asio/detail/handler_alloc_helpers.hpp>
20 #include <boost/asio/detail/handler_cont_helpers.hpp>
21 #include <boost/asio/detail/handler_invoke_helpers.hpp>
22 #include <boost/asio/detail/handler_type_requirements.hpp>
23 #include <boost/asio/detail/non_const_lvalue.hpp>
25 #include <boost/asio/detail/push_options.hpp>
30 template <typename Stream>
31 std::size_t buffered_write_stream<Stream>::flush()
33 std::size_t bytes_written = write(next_layer_,
34 buffer(storage_.data(), storage_.size()));
35 storage_.consume(bytes_written);
39 template <typename Stream>
40 std::size_t buffered_write_stream<Stream>::flush(boost::system::error_code& ec)
42 std::size_t bytes_written = write(next_layer_,
43 buffer(storage_.data(), storage_.size()),
45 storage_.consume(bytes_written);
51 template <typename WriteHandler>
52 class buffered_flush_handler
55 buffered_flush_handler(detail::buffered_stream_storage& storage,
56 WriteHandler& handler)
58 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
62 #if defined(BOOST_ASIO_HAS_MOVE)
63 buffered_flush_handler(const buffered_flush_handler& other)
64 : storage_(other.storage_),
65 handler_(other.handler_)
69 buffered_flush_handler(buffered_flush_handler&& other)
70 : storage_(other.storage_),
71 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
74 #endif // defined(BOOST_ASIO_HAS_MOVE)
76 void operator()(const boost::system::error_code& ec,
77 const std::size_t bytes_written)
79 storage_.consume(bytes_written);
80 BOOST_ASIO_MOVE_OR_LVALUE(WriteHandler)(handler_)(ec, bytes_written);
84 detail::buffered_stream_storage& storage_;
85 WriteHandler handler_;
88 template <typename WriteHandler>
89 inline asio_handler_allocate_is_deprecated
90 asio_handler_allocate(std::size_t size,
91 buffered_flush_handler<WriteHandler>* this_handler)
93 #if defined(BOOST_ASIO_NO_DEPRECATED)
94 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
95 return asio_handler_allocate_is_no_longer_used();
96 #else // defined(BOOST_ASIO_NO_DEPRECATED)
97 return boost_asio_handler_alloc_helpers::allocate(
98 size, this_handler->handler_);
99 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
102 template <typename WriteHandler>
103 inline asio_handler_deallocate_is_deprecated
104 asio_handler_deallocate(void* pointer, std::size_t size,
105 buffered_flush_handler<WriteHandler>* this_handler)
107 boost_asio_handler_alloc_helpers::deallocate(
108 pointer, size, this_handler->handler_);
109 #if defined(BOOST_ASIO_NO_DEPRECATED)
110 return asio_handler_deallocate_is_no_longer_used();
111 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
114 template <typename WriteHandler>
115 inline bool asio_handler_is_continuation(
116 buffered_flush_handler<WriteHandler>* this_handler)
118 return boost_asio_handler_cont_helpers::is_continuation(
119 this_handler->handler_);
122 template <typename Function, typename WriteHandler>
123 inline asio_handler_invoke_is_deprecated
124 asio_handler_invoke(Function& function,
125 buffered_flush_handler<WriteHandler>* this_handler)
127 boost_asio_handler_invoke_helpers::invoke(
128 function, this_handler->handler_);
129 #if defined(BOOST_ASIO_NO_DEPRECATED)
130 return asio_handler_invoke_is_no_longer_used();
131 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
134 template <typename Function, typename WriteHandler>
135 inline asio_handler_invoke_is_deprecated
136 asio_handler_invoke(const Function& function,
137 buffered_flush_handler<WriteHandler>* this_handler)
139 boost_asio_handler_invoke_helpers::invoke(
140 function, this_handler->handler_);
141 #if defined(BOOST_ASIO_NO_DEPRECATED)
142 return asio_handler_invoke_is_no_longer_used();
143 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
146 template <typename Stream>
147 class initiate_async_buffered_flush
150 typedef typename remove_reference<
151 Stream>::type::lowest_layer_type::executor_type executor_type;
153 explicit initiate_async_buffered_flush(
154 typename remove_reference<Stream>::type& next_layer)
155 : next_layer_(next_layer)
159 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
161 return next_layer_.lowest_layer().get_executor();
164 template <typename WriteHandler>
165 void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
166 buffered_stream_storage* storage) const
168 // If you get an error on the following line it means that your handler
169 // does not meet the documented type requirements for a WriteHandler.
170 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
172 non_const_lvalue<WriteHandler> handler2(handler);
173 async_write(next_layer_, buffer(storage->data(), storage->size()),
174 buffered_flush_handler<typename decay<WriteHandler>::type>(
175 *storage, handler2.value));
179 typename remove_reference<Stream>::type& next_layer_;
181 } // namespace detail
183 #if !defined(GENERATING_DOCUMENTATION)
185 template <template <typename, typename> class Associator,
186 typename WriteHandler, typename DefaultCandidate>
187 struct associator<Associator,
188 detail::buffered_flush_handler<WriteHandler>,
190 : Associator<WriteHandler, DefaultCandidate>
192 static typename Associator<WriteHandler, DefaultCandidate>::type get(
193 const detail::buffered_flush_handler<WriteHandler>& h,
194 const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
196 return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c);
200 #endif // !defined(GENERATING_DOCUMENTATION)
202 template <typename Stream>
204 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
205 std::size_t)) WriteHandler>
206 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
207 void (boost::system::error_code, std::size_t))
208 buffered_write_stream<Stream>::async_flush(
209 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
211 return async_initiate<WriteHandler,
212 void (boost::system::error_code, std::size_t)>(
213 detail::initiate_async_buffered_flush<Stream>(next_layer_),
217 template <typename Stream>
218 template <typename ConstBufferSequence>
219 std::size_t buffered_write_stream<Stream>::write_some(
220 const ConstBufferSequence& buffers)
222 using boost::asio::buffer_size;
223 if (buffer_size(buffers) == 0)
226 if (storage_.size() == storage_.capacity())
229 return this->copy(buffers);
232 template <typename Stream>
233 template <typename ConstBufferSequence>
234 std::size_t buffered_write_stream<Stream>::write_some(
235 const ConstBufferSequence& buffers, boost::system::error_code& ec)
237 ec = boost::system::error_code();
239 using boost::asio::buffer_size;
240 if (buffer_size(buffers) == 0)
243 if (storage_.size() == storage_.capacity() && !flush(ec))
246 return this->copy(buffers);
251 template <typename ConstBufferSequence, typename WriteHandler>
252 class buffered_write_some_handler
255 buffered_write_some_handler(detail::buffered_stream_storage& storage,
256 const ConstBufferSequence& buffers, WriteHandler& handler)
259 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
263 #if defined(BOOST_ASIO_HAS_MOVE)
264 buffered_write_some_handler(const buffered_write_some_handler& other)
265 : storage_(other.storage_),
266 buffers_(other.buffers_),
267 handler_(other.handler_)
271 buffered_write_some_handler(buffered_write_some_handler&& other)
272 : storage_(other.storage_),
273 buffers_(other.buffers_),
274 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
277 #endif // defined(BOOST_ASIO_HAS_MOVE)
279 void operator()(const boost::system::error_code& ec, std::size_t)
283 const std::size_t length = 0;
284 BOOST_ASIO_MOVE_OR_LVALUE(WriteHandler)(handler_)(ec, length);
288 using boost::asio::buffer_size;
289 std::size_t orig_size = storage_.size();
290 std::size_t space_avail = storage_.capacity() - orig_size;
291 std::size_t bytes_avail = buffer_size(buffers_);
292 std::size_t length = bytes_avail < space_avail
293 ? bytes_avail : space_avail;
294 storage_.resize(orig_size + length);
295 const std::size_t bytes_copied = boost::asio::buffer_copy(
296 storage_.data() + orig_size, buffers_, length);
297 BOOST_ASIO_MOVE_OR_LVALUE(WriteHandler)(handler_)(ec, bytes_copied);
302 detail::buffered_stream_storage& storage_;
303 ConstBufferSequence buffers_;
304 WriteHandler handler_;
307 template <typename ConstBufferSequence, typename WriteHandler>
308 inline asio_handler_allocate_is_deprecated
309 asio_handler_allocate(std::size_t size,
310 buffered_write_some_handler<
311 ConstBufferSequence, WriteHandler>* this_handler)
313 #if defined(BOOST_ASIO_NO_DEPRECATED)
314 boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
315 return asio_handler_allocate_is_no_longer_used();
316 #else // defined(BOOST_ASIO_NO_DEPRECATED)
317 return boost_asio_handler_alloc_helpers::allocate(
318 size, this_handler->handler_);
319 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
322 template <typename ConstBufferSequence, typename WriteHandler>
323 inline asio_handler_deallocate_is_deprecated
324 asio_handler_deallocate(void* pointer, std::size_t size,
325 buffered_write_some_handler<
326 ConstBufferSequence, WriteHandler>* this_handler)
328 boost_asio_handler_alloc_helpers::deallocate(
329 pointer, size, this_handler->handler_);
330 #if defined(BOOST_ASIO_NO_DEPRECATED)
331 return asio_handler_deallocate_is_no_longer_used();
332 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
335 template <typename ConstBufferSequence, typename WriteHandler>
336 inline bool asio_handler_is_continuation(
337 buffered_write_some_handler<
338 ConstBufferSequence, WriteHandler>* this_handler)
340 return boost_asio_handler_cont_helpers::is_continuation(
341 this_handler->handler_);
344 template <typename Function, typename ConstBufferSequence,
345 typename WriteHandler>
346 inline asio_handler_invoke_is_deprecated
347 asio_handler_invoke(Function& function,
348 buffered_write_some_handler<
349 ConstBufferSequence, WriteHandler>* this_handler)
351 boost_asio_handler_invoke_helpers::invoke(
352 function, this_handler->handler_);
353 #if defined(BOOST_ASIO_NO_DEPRECATED)
354 return asio_handler_invoke_is_no_longer_used();
355 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
358 template <typename Function, typename ConstBufferSequence,
359 typename WriteHandler>
360 inline asio_handler_invoke_is_deprecated
361 asio_handler_invoke(const Function& function,
362 buffered_write_some_handler<
363 ConstBufferSequence, WriteHandler>* this_handler)
365 boost_asio_handler_invoke_helpers::invoke(
366 function, this_handler->handler_);
367 #if defined(BOOST_ASIO_NO_DEPRECATED)
368 return asio_handler_invoke_is_no_longer_used();
369 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
372 template <typename Stream>
373 class initiate_async_buffered_write_some
376 typedef typename remove_reference<
377 Stream>::type::lowest_layer_type::executor_type executor_type;
379 explicit initiate_async_buffered_write_some(
380 typename remove_reference<Stream>::type& next_layer)
381 : next_layer_(next_layer)
385 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
387 return next_layer_.lowest_layer().get_executor();
390 template <typename WriteHandler, typename ConstBufferSequence>
391 void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
392 buffered_stream_storage* storage,
393 const ConstBufferSequence& buffers) const
395 // If you get an error on the following line it means that your handler
396 // does not meet the documented type requirements for a WriteHandler.
397 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
399 using boost::asio::buffer_size;
400 non_const_lvalue<WriteHandler> handler2(handler);
401 if (buffer_size(buffers) == 0 || storage->size() < storage->capacity())
403 next_layer_.async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0),
404 buffered_write_some_handler<ConstBufferSequence,
405 typename decay<WriteHandler>::type>(
406 *storage, buffers, handler2.value));
410 initiate_async_buffered_flush<Stream>(this->next_layer_)(
411 buffered_write_some_handler<ConstBufferSequence,
412 typename decay<WriteHandler>::type>(
413 *storage, buffers, handler2.value),
419 typename remove_reference<Stream>::type& next_layer_;
421 } // namespace detail
423 #if !defined(GENERATING_DOCUMENTATION)
425 template <template <typename, typename> class Associator,
426 typename ConstBufferSequence, typename WriteHandler,
427 typename DefaultCandidate>
428 struct associator<Associator,
429 detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
431 : Associator<WriteHandler, DefaultCandidate>
433 static typename Associator<WriteHandler, DefaultCandidate>::type get(
434 const detail::buffered_write_some_handler<
435 ConstBufferSequence, WriteHandler>& h,
436 const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
438 return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c);
442 #endif // !defined(GENERATING_DOCUMENTATION)
444 template <typename Stream>
445 template <typename ConstBufferSequence,
446 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
447 std::size_t)) WriteHandler>
448 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
449 void (boost::system::error_code, std::size_t))
450 buffered_write_stream<Stream>::async_write_some(
451 const ConstBufferSequence& buffers,
452 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
454 return async_initiate<WriteHandler,
455 void (boost::system::error_code, std::size_t)>(
456 detail::initiate_async_buffered_write_some<Stream>(next_layer_),
457 handler, &storage_, buffers);
460 template <typename Stream>
461 template <typename ConstBufferSequence>
462 std::size_t buffered_write_stream<Stream>::copy(
463 const ConstBufferSequence& buffers)
465 using boost::asio::buffer_size;
466 std::size_t orig_size = storage_.size();
467 std::size_t space_avail = storage_.capacity() - orig_size;
468 std::size_t bytes_avail = buffer_size(buffers);
469 std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
470 storage_.resize(orig_size + length);
471 return boost::asio::buffer_copy(
472 storage_.data() + orig_size, buffers, length);
478 #include <boost/asio/detail/pop_options.hpp>
480 #endif // BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP