File indexing completed on 2025-01-18 09:28:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
0012 #define BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/associator.hpp>
0019 #include <boost/asio/detail/handler_cont_helpers.hpp>
0020 #include <boost/asio/detail/handler_type_requirements.hpp>
0021 #include <boost/asio/detail/non_const_lvalue.hpp>
0022
0023 #include <boost/asio/detail/push_options.hpp>
0024
0025 namespace boost {
0026 namespace asio {
0027
0028 template <typename Stream>
0029 std::size_t buffered_write_stream<Stream>::flush()
0030 {
0031 std::size_t bytes_written = write(next_layer_,
0032 buffer(storage_.data(), storage_.size()));
0033 storage_.consume(bytes_written);
0034 return bytes_written;
0035 }
0036
0037 template <typename Stream>
0038 std::size_t buffered_write_stream<Stream>::flush(boost::system::error_code& ec)
0039 {
0040 std::size_t bytes_written = write(next_layer_,
0041 buffer(storage_.data(), storage_.size()),
0042 transfer_all(), ec);
0043 storage_.consume(bytes_written);
0044 return bytes_written;
0045 }
0046
0047 namespace detail
0048 {
0049 template <typename WriteHandler>
0050 class buffered_flush_handler
0051 {
0052 public:
0053 buffered_flush_handler(detail::buffered_stream_storage& storage,
0054 WriteHandler& handler)
0055 : storage_(storage),
0056 handler_(static_cast<WriteHandler&&>(handler))
0057 {
0058 }
0059
0060 buffered_flush_handler(const buffered_flush_handler& other)
0061 : storage_(other.storage_),
0062 handler_(other.handler_)
0063 {
0064 }
0065
0066 buffered_flush_handler(buffered_flush_handler&& other)
0067 : storage_(other.storage_),
0068 handler_(static_cast<WriteHandler&&>(other.handler_))
0069 {
0070 }
0071
0072 void operator()(const boost::system::error_code& ec,
0073 const std::size_t bytes_written)
0074 {
0075 storage_.consume(bytes_written);
0076 static_cast<WriteHandler&&>(handler_)(ec, bytes_written);
0077 }
0078
0079
0080 detail::buffered_stream_storage& storage_;
0081 WriteHandler handler_;
0082 };
0083
0084 template <typename WriteHandler>
0085 inline bool asio_handler_is_continuation(
0086 buffered_flush_handler<WriteHandler>* this_handler)
0087 {
0088 return boost_asio_handler_cont_helpers::is_continuation(
0089 this_handler->handler_);
0090 }
0091
0092 template <typename Stream>
0093 class initiate_async_buffered_flush
0094 {
0095 public:
0096 typedef typename remove_reference_t<
0097 Stream>::lowest_layer_type::executor_type executor_type;
0098
0099 explicit initiate_async_buffered_flush(
0100 remove_reference_t<Stream>& next_layer)
0101 : next_layer_(next_layer)
0102 {
0103 }
0104
0105 executor_type get_executor() const noexcept
0106 {
0107 return next_layer_.lowest_layer().get_executor();
0108 }
0109
0110 template <typename WriteHandler>
0111 void operator()(WriteHandler&& handler,
0112 buffered_stream_storage* storage) const
0113 {
0114
0115
0116 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
0117
0118 non_const_lvalue<WriteHandler> handler2(handler);
0119 async_write(next_layer_, buffer(storage->data(), storage->size()),
0120 buffered_flush_handler<decay_t<WriteHandler>>(
0121 *storage, handler2.value));
0122 }
0123
0124 private:
0125 remove_reference_t<Stream>& next_layer_;
0126 };
0127 }
0128
0129 #if !defined(GENERATING_DOCUMENTATION)
0130
0131 template <template <typename, typename> class Associator,
0132 typename WriteHandler, typename DefaultCandidate>
0133 struct associator<Associator,
0134 detail::buffered_flush_handler<WriteHandler>,
0135 DefaultCandidate>
0136 : Associator<WriteHandler, DefaultCandidate>
0137 {
0138 static typename Associator<WriteHandler, DefaultCandidate>::type get(
0139 const detail::buffered_flush_handler<WriteHandler>& h) noexcept
0140 {
0141 return Associator<WriteHandler, DefaultCandidate>::get(h.handler_);
0142 }
0143
0144 static auto get(const detail::buffered_flush_handler<WriteHandler>& h,
0145 const DefaultCandidate& c) noexcept
0146 -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c))
0147 {
0148 return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c);
0149 }
0150 };
0151
0152 #endif
0153
0154 template <typename Stream>
0155 template <
0156 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
0157 std::size_t)) WriteHandler>
0158 inline auto buffered_write_stream<Stream>::async_flush(WriteHandler&& handler)
0159 -> decltype(
0160 async_initiate<WriteHandler,
0161 void (boost::system::error_code, std::size_t)>(
0162 declval<detail::initiate_async_buffered_flush<Stream>>(),
0163 handler, declval<detail::buffered_stream_storage*>()))
0164 {
0165 return async_initiate<WriteHandler,
0166 void (boost::system::error_code, std::size_t)>(
0167 detail::initiate_async_buffered_flush<Stream>(next_layer_),
0168 handler, &storage_);
0169 }
0170
0171 template <typename Stream>
0172 template <typename ConstBufferSequence>
0173 std::size_t buffered_write_stream<Stream>::write_some(
0174 const ConstBufferSequence& buffers)
0175 {
0176 using boost::asio::buffer_size;
0177 if (buffer_size(buffers) == 0)
0178 return 0;
0179
0180 if (storage_.size() == storage_.capacity())
0181 this->flush();
0182
0183 return this->copy(buffers);
0184 }
0185
0186 template <typename Stream>
0187 template <typename ConstBufferSequence>
0188 std::size_t buffered_write_stream<Stream>::write_some(
0189 const ConstBufferSequence& buffers, boost::system::error_code& ec)
0190 {
0191 ec = boost::system::error_code();
0192
0193 using boost::asio::buffer_size;
0194 if (buffer_size(buffers) == 0)
0195 return 0;
0196
0197 if (storage_.size() == storage_.capacity() && !flush(ec))
0198 return 0;
0199
0200 return this->copy(buffers);
0201 }
0202
0203 namespace detail
0204 {
0205 template <typename ConstBufferSequence, typename WriteHandler>
0206 class buffered_write_some_handler
0207 {
0208 public:
0209 buffered_write_some_handler(detail::buffered_stream_storage& storage,
0210 const ConstBufferSequence& buffers, WriteHandler& handler)
0211 : storage_(storage),
0212 buffers_(buffers),
0213 handler_(static_cast<WriteHandler&&>(handler))
0214 {
0215 }
0216
0217 buffered_write_some_handler(const buffered_write_some_handler& other)
0218 : storage_(other.storage_),
0219 buffers_(other.buffers_),
0220 handler_(other.handler_)
0221 {
0222 }
0223
0224 buffered_write_some_handler(buffered_write_some_handler&& other)
0225 : storage_(other.storage_),
0226 buffers_(other.buffers_),
0227 handler_(static_cast<WriteHandler&&>(other.handler_))
0228 {
0229 }
0230
0231 void operator()(const boost::system::error_code& ec, std::size_t)
0232 {
0233 if (ec)
0234 {
0235 const std::size_t length = 0;
0236 static_cast<WriteHandler&&>(handler_)(ec, length);
0237 }
0238 else
0239 {
0240 using boost::asio::buffer_size;
0241 std::size_t orig_size = storage_.size();
0242 std::size_t space_avail = storage_.capacity() - orig_size;
0243 std::size_t bytes_avail = buffer_size(buffers_);
0244 std::size_t length = bytes_avail < space_avail
0245 ? bytes_avail : space_avail;
0246 storage_.resize(orig_size + length);
0247 const std::size_t bytes_copied = boost::asio::buffer_copy(
0248 storage_.data() + orig_size, buffers_, length);
0249 static_cast<WriteHandler&&>(handler_)(ec, bytes_copied);
0250 }
0251 }
0252
0253
0254 detail::buffered_stream_storage& storage_;
0255 ConstBufferSequence buffers_;
0256 WriteHandler handler_;
0257 };
0258
0259 template <typename ConstBufferSequence, typename WriteHandler>
0260 inline bool asio_handler_is_continuation(
0261 buffered_write_some_handler<
0262 ConstBufferSequence, WriteHandler>* this_handler)
0263 {
0264 return boost_asio_handler_cont_helpers::is_continuation(
0265 this_handler->handler_);
0266 }
0267
0268 template <typename Stream>
0269 class initiate_async_buffered_write_some
0270 {
0271 public:
0272 typedef typename remove_reference_t<
0273 Stream>::lowest_layer_type::executor_type executor_type;
0274
0275 explicit initiate_async_buffered_write_some(
0276 remove_reference_t<Stream>& next_layer)
0277 : next_layer_(next_layer)
0278 {
0279 }
0280
0281 executor_type get_executor() const noexcept
0282 {
0283 return next_layer_.lowest_layer().get_executor();
0284 }
0285
0286 template <typename WriteHandler, typename ConstBufferSequence>
0287 void operator()(WriteHandler&& handler,
0288 buffered_stream_storage* storage,
0289 const ConstBufferSequence& buffers) const
0290 {
0291
0292
0293 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
0294
0295 using boost::asio::buffer_size;
0296 non_const_lvalue<WriteHandler> handler2(handler);
0297 if (buffer_size(buffers) == 0 || storage->size() < storage->capacity())
0298 {
0299 next_layer_.async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0),
0300 buffered_write_some_handler<ConstBufferSequence,
0301 decay_t<WriteHandler>>(
0302 *storage, buffers, handler2.value));
0303 }
0304 else
0305 {
0306 initiate_async_buffered_flush<Stream>(this->next_layer_)(
0307 buffered_write_some_handler<ConstBufferSequence,
0308 decay_t<WriteHandler>>(
0309 *storage, buffers, handler2.value),
0310 storage);
0311 }
0312 }
0313
0314 private:
0315 remove_reference_t<Stream>& next_layer_;
0316 };
0317 }
0318
0319 #if !defined(GENERATING_DOCUMENTATION)
0320
0321 template <template <typename, typename> class Associator,
0322 typename ConstBufferSequence, typename WriteHandler,
0323 typename DefaultCandidate>
0324 struct associator<Associator,
0325 detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
0326 DefaultCandidate>
0327 : Associator<WriteHandler, DefaultCandidate>
0328 {
0329 static typename Associator<WriteHandler, DefaultCandidate>::type get(
0330 const detail::buffered_write_some_handler<
0331 ConstBufferSequence, WriteHandler>& h) noexcept
0332 {
0333 return Associator<WriteHandler, DefaultCandidate>::get(h.handler_);
0334 }
0335
0336 static auto get(
0337 const detail::buffered_write_some_handler<
0338 ConstBufferSequence, WriteHandler>& h,
0339 const DefaultCandidate& c) noexcept
0340 -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c))
0341 {
0342 return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c);
0343 }
0344 };
0345
0346 #endif
0347
0348 template <typename Stream>
0349 template <typename ConstBufferSequence,
0350 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
0351 std::size_t)) WriteHandler>
0352 inline auto buffered_write_stream<Stream>::async_write_some(
0353 const ConstBufferSequence& buffers, WriteHandler&& handler)
0354 -> decltype(
0355 async_initiate<WriteHandler,
0356 void (boost::system::error_code, std::size_t)>(
0357 declval<detail::initiate_async_buffered_write_some<Stream>>(),
0358 handler, declval<detail::buffered_stream_storage*>(), buffers))
0359 {
0360 return async_initiate<WriteHandler,
0361 void (boost::system::error_code, std::size_t)>(
0362 detail::initiate_async_buffered_write_some<Stream>(next_layer_),
0363 handler, &storage_, buffers);
0364 }
0365
0366 template <typename Stream>
0367 template <typename ConstBufferSequence>
0368 std::size_t buffered_write_stream<Stream>::copy(
0369 const ConstBufferSequence& buffers)
0370 {
0371 using boost::asio::buffer_size;
0372 std::size_t orig_size = storage_.size();
0373 std::size_t space_avail = storage_.capacity() - orig_size;
0374 std::size_t bytes_avail = buffer_size(buffers);
0375 std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
0376 storage_.resize(orig_size + length);
0377 return boost::asio::buffer_copy(
0378 storage_.data() + orig_size, buffers, length);
0379 }
0380
0381 }
0382 }
0383
0384 #include <boost/asio/detail/pop_options.hpp>
0385
0386 #endif