1 | // |
2 | // impl/write.hpp |
3 | // ~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2024 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_WRITE_HPP |
12 | #define BOOST_ASIO_IMPL_WRITE_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/associator.hpp> |
19 | #include <boost/asio/buffer.hpp> |
20 | #include <boost/asio/detail/array_fwd.hpp> |
21 | #include <boost/asio/detail/base_from_cancellation_state.hpp> |
22 | #include <boost/asio/detail/base_from_completion_cond.hpp> |
23 | #include <boost/asio/detail/bind_handler.hpp> |
24 | #include <boost/asio/detail/consuming_buffers.hpp> |
25 | #include <boost/asio/detail/dependent_type.hpp> |
26 | #include <boost/asio/detail/handler_cont_helpers.hpp> |
27 | #include <boost/asio/detail/handler_tracking.hpp> |
28 | #include <boost/asio/detail/handler_type_requirements.hpp> |
29 | #include <boost/asio/detail/non_const_lvalue.hpp> |
30 | #include <boost/asio/detail/throw_error.hpp> |
31 | |
32 | #include <boost/asio/detail/push_options.hpp> |
33 | |
34 | namespace boost { |
35 | namespace asio { |
36 | |
37 | namespace detail |
38 | { |
39 | template <typename SyncWriteStream, typename ConstBufferSequence, |
40 | typename ConstBufferIterator, typename CompletionCondition> |
41 | std::size_t write(SyncWriteStream& s, |
42 | const ConstBufferSequence& buffers, const ConstBufferIterator&, |
43 | CompletionCondition completion_condition, boost::system::error_code& ec) |
44 | { |
45 | ec = boost::system::error_code(); |
46 | boost::asio::detail::consuming_buffers<const_buffer, |
47 | ConstBufferSequence, ConstBufferIterator> tmp(buffers); |
48 | while (!tmp.empty()) |
49 | { |
50 | if (std::size_t max_size = detail::adapt_completion_condition_result( |
51 | completion_condition(ec, tmp.total_consumed()))) |
52 | tmp.consume(s.write_some(tmp.prepare(max_size), ec)); |
53 | else |
54 | break; |
55 | } |
56 | return tmp.total_consumed(); |
57 | } |
58 | } // namespace detail |
59 | |
60 | template <typename SyncWriteStream, typename ConstBufferSequence, |
61 | typename CompletionCondition> |
62 | inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, |
63 | CompletionCondition completion_condition, boost::system::error_code& ec, |
64 | constraint_t< |
65 | is_const_buffer_sequence<ConstBufferSequence>::value |
66 | >) |
67 | { |
68 | return detail::write(s, buffers, |
69 | boost::asio::buffer_sequence_begin(buffers), |
70 | static_cast<CompletionCondition&&>(completion_condition), ec); |
71 | } |
72 | |
73 | template <typename SyncWriteStream, typename ConstBufferSequence> |
74 | inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, |
75 | constraint_t< |
76 | is_const_buffer_sequence<ConstBufferSequence>::value |
77 | >) |
78 | { |
79 | boost::system::error_code ec; |
80 | std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec); |
81 | boost::asio::detail::throw_error(err: ec, location: "write" ); |
82 | return bytes_transferred; |
83 | } |
84 | |
85 | template <typename SyncWriteStream, typename ConstBufferSequence> |
86 | inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, |
87 | boost::system::error_code& ec, |
88 | constraint_t< |
89 | is_const_buffer_sequence<ConstBufferSequence>::value |
90 | >) |
91 | { |
92 | return write(s, buffers, transfer_all(), ec); |
93 | } |
94 | |
95 | template <typename SyncWriteStream, typename ConstBufferSequence, |
96 | typename CompletionCondition> |
97 | inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, |
98 | CompletionCondition completion_condition, |
99 | constraint_t< |
100 | is_const_buffer_sequence<ConstBufferSequence>::value |
101 | >) |
102 | { |
103 | boost::system::error_code ec; |
104 | std::size_t bytes_transferred = write(s, buffers, |
105 | static_cast<CompletionCondition&&>(completion_condition), ec); |
106 | boost::asio::detail::throw_error(err: ec, location: "write" ); |
107 | return bytes_transferred; |
108 | } |
109 | |
110 | #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) |
111 | |
112 | template <typename SyncWriteStream, typename DynamicBuffer_v1, |
113 | typename CompletionCondition> |
114 | std::size_t write(SyncWriteStream& s, |
115 | DynamicBuffer_v1&& buffers, |
116 | CompletionCondition completion_condition, boost::system::error_code& ec, |
117 | constraint_t< |
118 | is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value |
119 | >, |
120 | constraint_t< |
121 | !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value |
122 | >) |
123 | { |
124 | decay_t<DynamicBuffer_v1> b( |
125 | static_cast<DynamicBuffer_v1&&>(buffers)); |
126 | |
127 | std::size_t bytes_transferred = write(s, b.data(), |
128 | static_cast<CompletionCondition&&>(completion_condition), ec); |
129 | b.consume(bytes_transferred); |
130 | return bytes_transferred; |
131 | } |
132 | |
133 | template <typename SyncWriteStream, typename DynamicBuffer_v1> |
134 | inline std::size_t write(SyncWriteStream& s, |
135 | DynamicBuffer_v1&& buffers, |
136 | constraint_t< |
137 | is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value |
138 | >, |
139 | constraint_t< |
140 | !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value |
141 | >) |
142 | { |
143 | boost::system::error_code ec; |
144 | std::size_t bytes_transferred = write(s, |
145 | static_cast<DynamicBuffer_v1&&>(buffers), |
146 | transfer_all(), ec); |
147 | boost::asio::detail::throw_error(err: ec, location: "write" ); |
148 | return bytes_transferred; |
149 | } |
150 | |
151 | template <typename SyncWriteStream, typename DynamicBuffer_v1> |
152 | inline std::size_t write(SyncWriteStream& s, |
153 | DynamicBuffer_v1&& buffers, |
154 | boost::system::error_code& ec, |
155 | constraint_t< |
156 | is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value |
157 | >, |
158 | constraint_t< |
159 | !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value |
160 | >) |
161 | { |
162 | return write(s, static_cast<DynamicBuffer_v1&&>(buffers), |
163 | transfer_all(), ec); |
164 | } |
165 | |
166 | template <typename SyncWriteStream, typename DynamicBuffer_v1, |
167 | typename CompletionCondition> |
168 | inline std::size_t write(SyncWriteStream& s, |
169 | DynamicBuffer_v1&& buffers, |
170 | CompletionCondition completion_condition, |
171 | constraint_t< |
172 | is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value |
173 | >, |
174 | constraint_t< |
175 | !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value |
176 | >) |
177 | { |
178 | boost::system::error_code ec; |
179 | std::size_t bytes_transferred = write(s, |
180 | static_cast<DynamicBuffer_v1&&>(buffers), |
181 | static_cast<CompletionCondition&&>(completion_condition), ec); |
182 | boost::asio::detail::throw_error(err: ec, location: "write" ); |
183 | return bytes_transferred; |
184 | } |
185 | |
186 | #if !defined(BOOST_ASIO_NO_EXTENSIONS) |
187 | #if !defined(BOOST_ASIO_NO_IOSTREAM) |
188 | |
189 | template <typename SyncWriteStream, typename Allocator, |
190 | typename CompletionCondition> |
191 | inline std::size_t write(SyncWriteStream& s, |
192 | boost::asio::basic_streambuf<Allocator>& b, |
193 | CompletionCondition completion_condition, boost::system::error_code& ec) |
194 | { |
195 | return write(s, basic_streambuf_ref<Allocator>(b), |
196 | static_cast<CompletionCondition&&>(completion_condition), ec); |
197 | } |
198 | |
199 | template <typename SyncWriteStream, typename Allocator> |
200 | inline std::size_t write(SyncWriteStream& s, |
201 | boost::asio::basic_streambuf<Allocator>& b) |
202 | { |
203 | return write(s, basic_streambuf_ref<Allocator>(b)); |
204 | } |
205 | |
206 | template <typename SyncWriteStream, typename Allocator> |
207 | inline std::size_t write(SyncWriteStream& s, |
208 | boost::asio::basic_streambuf<Allocator>& b, |
209 | boost::system::error_code& ec) |
210 | { |
211 | return write(s, basic_streambuf_ref<Allocator>(b), ec); |
212 | } |
213 | |
214 | template <typename SyncWriteStream, typename Allocator, |
215 | typename CompletionCondition> |
216 | inline std::size_t write(SyncWriteStream& s, |
217 | boost::asio::basic_streambuf<Allocator>& b, |
218 | CompletionCondition completion_condition) |
219 | { |
220 | return write(s, basic_streambuf_ref<Allocator>(b), |
221 | static_cast<CompletionCondition&&>(completion_condition)); |
222 | } |
223 | |
224 | #endif // !defined(BOOST_ASIO_NO_IOSTREAM) |
225 | #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) |
226 | #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) |
227 | |
228 | template <typename SyncWriteStream, typename DynamicBuffer_v2, |
229 | typename CompletionCondition> |
230 | std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, |
231 | CompletionCondition completion_condition, boost::system::error_code& ec, |
232 | constraint_t< |
233 | is_dynamic_buffer_v2<DynamicBuffer_v2>::value |
234 | >) |
235 | { |
236 | std::size_t bytes_transferred = write(s, buffers.data(0, buffers.size()), |
237 | static_cast<CompletionCondition&&>(completion_condition), ec); |
238 | buffers.consume(bytes_transferred); |
239 | return bytes_transferred; |
240 | } |
241 | |
242 | template <typename SyncWriteStream, typename DynamicBuffer_v2> |
243 | inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, |
244 | constraint_t< |
245 | is_dynamic_buffer_v2<DynamicBuffer_v2>::value |
246 | >) |
247 | { |
248 | boost::system::error_code ec; |
249 | std::size_t bytes_transferred = write(s, |
250 | static_cast<DynamicBuffer_v2&&>(buffers), |
251 | transfer_all(), ec); |
252 | boost::asio::detail::throw_error(err: ec, location: "write" ); |
253 | return bytes_transferred; |
254 | } |
255 | |
256 | template <typename SyncWriteStream, typename DynamicBuffer_v2> |
257 | inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, |
258 | boost::system::error_code& ec, |
259 | constraint_t< |
260 | is_dynamic_buffer_v2<DynamicBuffer_v2>::value |
261 | >) |
262 | { |
263 | return write(s, static_cast<DynamicBuffer_v2&&>(buffers), |
264 | transfer_all(), ec); |
265 | } |
266 | |
267 | template <typename SyncWriteStream, typename DynamicBuffer_v2, |
268 | typename CompletionCondition> |
269 | inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, |
270 | CompletionCondition completion_condition, |
271 | constraint_t< |
272 | is_dynamic_buffer_v2<DynamicBuffer_v2>::value |
273 | >) |
274 | { |
275 | boost::system::error_code ec; |
276 | std::size_t bytes_transferred = write(s, |
277 | static_cast<DynamicBuffer_v2&&>(buffers), |
278 | static_cast<CompletionCondition&&>(completion_condition), ec); |
279 | boost::asio::detail::throw_error(err: ec, location: "write" ); |
280 | return bytes_transferred; |
281 | } |
282 | |
283 | namespace detail |
284 | { |
285 | template <typename AsyncWriteStream, typename ConstBufferSequence, |
286 | typename ConstBufferIterator, typename CompletionCondition, |
287 | typename WriteHandler> |
288 | class write_op |
289 | : public base_from_cancellation_state<WriteHandler>, |
290 | base_from_completion_cond<CompletionCondition> |
291 | { |
292 | public: |
293 | write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, |
294 | CompletionCondition& completion_condition, WriteHandler& handler) |
295 | : base_from_cancellation_state<WriteHandler>( |
296 | handler, enable_partial_cancellation()), |
297 | base_from_completion_cond<CompletionCondition>(completion_condition), |
298 | stream_(stream), |
299 | buffers_(buffers), |
300 | start_(0), |
301 | handler_(static_cast<WriteHandler&&>(handler)) |
302 | { |
303 | } |
304 | |
305 | write_op(const write_op& other) |
306 | : base_from_cancellation_state<WriteHandler>(other), |
307 | base_from_completion_cond<CompletionCondition>(other), |
308 | stream_(other.stream_), |
309 | buffers_(other.buffers_), |
310 | start_(other.start_), |
311 | handler_(other.handler_) |
312 | { |
313 | } |
314 | |
315 | write_op(write_op&& other) |
316 | : base_from_cancellation_state<WriteHandler>( |
317 | static_cast<base_from_cancellation_state<WriteHandler>&&>(other)), |
318 | base_from_completion_cond<CompletionCondition>( |
319 | static_cast<base_from_completion_cond<CompletionCondition>&&>(other)), |
320 | stream_(other.stream_), |
321 | buffers_(static_cast<buffers_type&&>(other.buffers_)), |
322 | start_(other.start_), |
323 | handler_(static_cast<WriteHandler&&>(other.handler_)) |
324 | { |
325 | } |
326 | |
327 | void operator()(boost::system::error_code ec, |
328 | std::size_t bytes_transferred, int start = 0) |
329 | { |
330 | std::size_t max_size; |
331 | switch (start_ = start) |
332 | { |
333 | case 1: |
334 | max_size = this->check_for_completion(ec, buffers_.total_consumed()); |
335 | for (;;) |
336 | { |
337 | { |
338 | BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write" )); |
339 | stream_.async_write_some(buffers_.prepare(max_size), |
340 | static_cast<write_op&&>(*this)); |
341 | } |
342 | return; default: |
343 | buffers_.consume(bytes_transferred); |
344 | if ((!ec && bytes_transferred == 0) || buffers_.empty()) |
345 | break; |
346 | max_size = this->check_for_completion(ec, buffers_.total_consumed()); |
347 | if (max_size == 0) |
348 | break; |
349 | if (this->cancelled() != cancellation_type::none) |
350 | { |
351 | ec = error::operation_aborted; |
352 | break; |
353 | } |
354 | } |
355 | |
356 | static_cast<WriteHandler&&>(handler_)( |
357 | static_cast<const boost::system::error_code&>(ec), |
358 | static_cast<const std::size_t&>(buffers_.total_consumed())); |
359 | } |
360 | } |
361 | |
362 | //private: |
363 | typedef boost::asio::detail::consuming_buffers<const_buffer, |
364 | ConstBufferSequence, ConstBufferIterator> buffers_type; |
365 | |
366 | AsyncWriteStream& stream_; |
367 | buffers_type buffers_; |
368 | int start_; |
369 | WriteHandler handler_; |
370 | }; |
371 | |
372 | template <typename AsyncWriteStream, typename ConstBufferSequence, |
373 | typename ConstBufferIterator, typename CompletionCondition, |
374 | typename WriteHandler> |
375 | inline bool asio_handler_is_continuation( |
376 | write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, |
377 | CompletionCondition, WriteHandler>* this_handler) |
378 | { |
379 | return this_handler->start_ == 0 ? true |
380 | : boost_asio_handler_cont_helpers::is_continuation( |
381 | this_handler->handler_); |
382 | } |
383 | |
384 | template <typename AsyncWriteStream, typename ConstBufferSequence, |
385 | typename ConstBufferIterator, typename CompletionCondition, |
386 | typename WriteHandler> |
387 | inline void start_write_op(AsyncWriteStream& stream, |
388 | const ConstBufferSequence& buffers, const ConstBufferIterator&, |
389 | CompletionCondition& completion_condition, WriteHandler& handler) |
390 | { |
391 | detail::write_op<AsyncWriteStream, ConstBufferSequence, |
392 | ConstBufferIterator, CompletionCondition, WriteHandler>( |
393 | stream, buffers, completion_condition, handler)( |
394 | boost::system::error_code(), 0, 1); |
395 | } |
396 | |
397 | template <typename AsyncWriteStream> |
398 | class initiate_async_write |
399 | { |
400 | public: |
401 | typedef typename AsyncWriteStream::executor_type executor_type; |
402 | |
403 | explicit initiate_async_write(AsyncWriteStream& stream) |
404 | : stream_(stream) |
405 | { |
406 | } |
407 | |
408 | executor_type get_executor() const noexcept |
409 | { |
410 | return stream_.get_executor(); |
411 | } |
412 | |
413 | template <typename WriteHandler, typename ConstBufferSequence, |
414 | typename CompletionCondition> |
415 | void operator()(WriteHandler&& handler, |
416 | const ConstBufferSequence& buffers, |
417 | CompletionCondition&& completion_cond) const |
418 | { |
419 | // If you get an error on the following line it means that your handler |
420 | // does not meet the documented type requirements for a WriteHandler. |
421 | BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; |
422 | |
423 | non_const_lvalue<WriteHandler> handler2(handler); |
424 | non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); |
425 | start_write_op(stream_, buffers, |
426 | boost::asio::buffer_sequence_begin(buffers), |
427 | completion_cond2.value, handler2.value); |
428 | } |
429 | |
430 | private: |
431 | AsyncWriteStream& stream_; |
432 | }; |
433 | } // namespace detail |
434 | |
435 | #if !defined(GENERATING_DOCUMENTATION) |
436 | |
437 | template <template <typename, typename> class Associator, |
438 | typename AsyncWriteStream, typename ConstBufferSequence, |
439 | typename ConstBufferIterator, typename CompletionCondition, |
440 | typename WriteHandler, typename DefaultCandidate> |
441 | struct associator<Associator, |
442 | detail::write_op<AsyncWriteStream, ConstBufferSequence, |
443 | ConstBufferIterator, CompletionCondition, WriteHandler>, |
444 | DefaultCandidate> |
445 | : Associator<WriteHandler, DefaultCandidate> |
446 | { |
447 | static typename Associator<WriteHandler, DefaultCandidate>::type get( |
448 | const detail::write_op<AsyncWriteStream, ConstBufferSequence, |
449 | ConstBufferIterator, CompletionCondition, WriteHandler>& h) noexcept |
450 | { |
451 | return Associator<WriteHandler, DefaultCandidate>::get(h.handler_); |
452 | } |
453 | |
454 | static auto get( |
455 | const detail::write_op<AsyncWriteStream, ConstBufferSequence, |
456 | ConstBufferIterator, CompletionCondition, WriteHandler>& h, |
457 | const DefaultCandidate& c) noexcept |
458 | -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c)) |
459 | { |
460 | return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c); |
461 | } |
462 | }; |
463 | |
464 | #endif // !defined(GENERATING_DOCUMENTATION) |
465 | |
466 | template <typename AsyncWriteStream, |
467 | typename ConstBufferSequence, typename CompletionCondition, |
468 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
469 | std::size_t)) WriteToken> |
470 | inline auto async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, |
471 | CompletionCondition completion_condition, WriteToken&& token, |
472 | constraint_t< |
473 | is_const_buffer_sequence<ConstBufferSequence>::value |
474 | >) |
475 | -> decltype( |
476 | async_initiate<WriteToken, |
477 | void (boost::system::error_code, std::size_t)>( |
478 | declval<detail::initiate_async_write<AsyncWriteStream>>(), |
479 | token, buffers, |
480 | static_cast<CompletionCondition&&>(completion_condition))) |
481 | { |
482 | return async_initiate<WriteToken, |
483 | void (boost::system::error_code, std::size_t)>( |
484 | detail::initiate_async_write<AsyncWriteStream>(s), |
485 | token, buffers, |
486 | static_cast<CompletionCondition&&>(completion_condition)); |
487 | } |
488 | |
489 | template <typename AsyncWriteStream, typename ConstBufferSequence, |
490 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
491 | std::size_t)) WriteToken> |
492 | inline auto async_write(AsyncWriteStream& s, |
493 | const ConstBufferSequence& buffers, WriteToken&& token, |
494 | constraint_t< |
495 | is_const_buffer_sequence<ConstBufferSequence>::value |
496 | >) |
497 | -> decltype( |
498 | async_initiate<WriteToken, |
499 | void (boost::system::error_code, std::size_t)>( |
500 | declval<detail::initiate_async_write<AsyncWriteStream>>(), |
501 | token, buffers, transfer_all())) |
502 | { |
503 | return async_initiate<WriteToken, |
504 | void (boost::system::error_code, std::size_t)>( |
505 | detail::initiate_async_write<AsyncWriteStream>(s), |
506 | token, buffers, transfer_all()); |
507 | } |
508 | |
509 | #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) |
510 | |
511 | namespace detail |
512 | { |
513 | template <typename AsyncWriteStream, typename DynamicBuffer_v1, |
514 | typename CompletionCondition, typename WriteHandler> |
515 | class write_dynbuf_v1_op |
516 | { |
517 | public: |
518 | template <typename BufferSequence> |
519 | write_dynbuf_v1_op(AsyncWriteStream& stream, |
520 | BufferSequence&& buffers, |
521 | CompletionCondition& completion_condition, WriteHandler& handler) |
522 | : stream_(stream), |
523 | buffers_(static_cast<BufferSequence&&>(buffers)), |
524 | completion_condition_( |
525 | static_cast<CompletionCondition&&>(completion_condition)), |
526 | handler_(static_cast<WriteHandler&&>(handler)) |
527 | { |
528 | } |
529 | |
530 | write_dynbuf_v1_op(const write_dynbuf_v1_op& other) |
531 | : stream_(other.stream_), |
532 | buffers_(other.buffers_), |
533 | completion_condition_(other.completion_condition_), |
534 | handler_(other.handler_) |
535 | { |
536 | } |
537 | |
538 | write_dynbuf_v1_op(write_dynbuf_v1_op&& other) |
539 | : stream_(other.stream_), |
540 | buffers_(static_cast<DynamicBuffer_v1&&>(other.buffers_)), |
541 | completion_condition_( |
542 | static_cast<CompletionCondition&&>( |
543 | other.completion_condition_)), |
544 | handler_(static_cast<WriteHandler&&>(other.handler_)) |
545 | { |
546 | } |
547 | |
548 | void operator()(const boost::system::error_code& ec, |
549 | std::size_t bytes_transferred, int start = 0) |
550 | { |
551 | switch (start) |
552 | { |
553 | case 1: |
554 | async_write(stream_, buffers_.data(), |
555 | static_cast<CompletionCondition&&>(completion_condition_), |
556 | static_cast<write_dynbuf_v1_op&&>(*this)); |
557 | return; default: |
558 | buffers_.consume(bytes_transferred); |
559 | static_cast<WriteHandler&&>(handler_)(ec, |
560 | static_cast<const std::size_t&>(bytes_transferred)); |
561 | } |
562 | } |
563 | |
564 | //private: |
565 | AsyncWriteStream& stream_; |
566 | DynamicBuffer_v1 buffers_; |
567 | CompletionCondition completion_condition_; |
568 | WriteHandler handler_; |
569 | }; |
570 | |
571 | template <typename AsyncWriteStream, typename DynamicBuffer_v1, |
572 | typename CompletionCondition, typename WriteHandler> |
573 | inline bool asio_handler_is_continuation( |
574 | write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, |
575 | CompletionCondition, WriteHandler>* this_handler) |
576 | { |
577 | return boost_asio_handler_cont_helpers::is_continuation( |
578 | this_handler->handler_); |
579 | } |
580 | |
581 | template <typename AsyncWriteStream> |
582 | class initiate_async_write_dynbuf_v1 |
583 | { |
584 | public: |
585 | typedef typename AsyncWriteStream::executor_type executor_type; |
586 | |
587 | explicit initiate_async_write_dynbuf_v1(AsyncWriteStream& stream) |
588 | : stream_(stream) |
589 | { |
590 | } |
591 | |
592 | executor_type get_executor() const noexcept |
593 | { |
594 | return stream_.get_executor(); |
595 | } |
596 | |
597 | template <typename WriteHandler, typename DynamicBuffer_v1, |
598 | typename CompletionCondition> |
599 | void operator()(WriteHandler&& handler, |
600 | DynamicBuffer_v1&& buffers, |
601 | CompletionCondition&& completion_cond) const |
602 | { |
603 | // If you get an error on the following line it means that your handler |
604 | // does not meet the documented type requirements for a WriteHandler. |
605 | BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; |
606 | |
607 | non_const_lvalue<WriteHandler> handler2(handler); |
608 | non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); |
609 | write_dynbuf_v1_op<AsyncWriteStream, |
610 | decay_t<DynamicBuffer_v1>, |
611 | CompletionCondition, decay_t<WriteHandler>>( |
612 | stream_, static_cast<DynamicBuffer_v1&&>(buffers), |
613 | completion_cond2.value, handler2.value)( |
614 | boost::system::error_code(), 0, 1); |
615 | } |
616 | |
617 | private: |
618 | AsyncWriteStream& stream_; |
619 | }; |
620 | } // namespace detail |
621 | |
622 | #if !defined(GENERATING_DOCUMENTATION) |
623 | |
624 | template <template <typename, typename> class Associator, |
625 | typename AsyncWriteStream, typename DynamicBuffer_v1, |
626 | typename CompletionCondition, typename WriteHandler, |
627 | typename DefaultCandidate> |
628 | struct associator<Associator, |
629 | detail::write_dynbuf_v1_op<AsyncWriteStream, |
630 | DynamicBuffer_v1, CompletionCondition, WriteHandler>, |
631 | DefaultCandidate> |
632 | : Associator<WriteHandler, DefaultCandidate> |
633 | { |
634 | static typename Associator<WriteHandler, DefaultCandidate>::type get( |
635 | const detail::write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, |
636 | CompletionCondition, WriteHandler>& h) noexcept |
637 | { |
638 | return Associator<WriteHandler, DefaultCandidate>::get(h.handler_); |
639 | } |
640 | |
641 | static auto get( |
642 | const detail::write_dynbuf_v1_op<AsyncWriteStream, |
643 | DynamicBuffer_v1, CompletionCondition, WriteHandler>& h, |
644 | const DefaultCandidate& c) noexcept |
645 | -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c)) |
646 | { |
647 | return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c); |
648 | } |
649 | }; |
650 | |
651 | #endif // !defined(GENERATING_DOCUMENTATION) |
652 | |
653 | template <typename AsyncWriteStream, typename DynamicBuffer_v1, |
654 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
655 | std::size_t)) WriteToken> |
656 | inline auto async_write(AsyncWriteStream& s, |
657 | DynamicBuffer_v1&& buffers, WriteToken&& token, |
658 | constraint_t< |
659 | is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value |
660 | >, |
661 | constraint_t< |
662 | !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value |
663 | >) |
664 | -> decltype( |
665 | async_initiate<WriteToken, |
666 | void (boost::system::error_code, std::size_t)>( |
667 | declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), |
668 | token, static_cast<DynamicBuffer_v1&&>(buffers), |
669 | transfer_all())) |
670 | { |
671 | return async_initiate<WriteToken, |
672 | void (boost::system::error_code, std::size_t)>( |
673 | detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s), |
674 | token, static_cast<DynamicBuffer_v1&&>(buffers), |
675 | transfer_all()); |
676 | } |
677 | |
678 | template <typename AsyncWriteStream, |
679 | typename DynamicBuffer_v1, typename CompletionCondition, |
680 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
681 | std::size_t)) WriteToken> |
682 | inline auto async_write(AsyncWriteStream& s, DynamicBuffer_v1&& buffers, |
683 | CompletionCondition completion_condition, WriteToken&& token, |
684 | constraint_t< |
685 | is_dynamic_buffer_v1<decay_t<DynamicBuffer_v1>>::value |
686 | >, |
687 | constraint_t< |
688 | !is_dynamic_buffer_v2<decay_t<DynamicBuffer_v1>>::value |
689 | >) |
690 | -> decltype( |
691 | async_initiate<WriteToken, |
692 | void (boost::system::error_code, std::size_t)>( |
693 | declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), |
694 | token, static_cast<DynamicBuffer_v1&&>(buffers), |
695 | static_cast<CompletionCondition&&>(completion_condition))) |
696 | { |
697 | return async_initiate<WriteToken, |
698 | void (boost::system::error_code, std::size_t)>( |
699 | detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s), |
700 | token, static_cast<DynamicBuffer_v1&&>(buffers), |
701 | static_cast<CompletionCondition&&>(completion_condition)); |
702 | } |
703 | |
704 | #if !defined(BOOST_ASIO_NO_EXTENSIONS) |
705 | #if !defined(BOOST_ASIO_NO_IOSTREAM) |
706 | |
707 | template <typename AsyncWriteStream, typename Allocator, |
708 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
709 | std::size_t)) WriteToken> |
710 | inline auto async_write(AsyncWriteStream& s, |
711 | boost::asio::basic_streambuf<Allocator>& b, |
712 | WriteToken&& token) |
713 | -> decltype( |
714 | async_initiate<WriteToken, |
715 | void (boost::system::error_code, std::size_t)>( |
716 | declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), |
717 | token, basic_streambuf_ref<Allocator>(b), transfer_all())) |
718 | { |
719 | return async_initiate<WriteToken, |
720 | void (boost::system::error_code, std::size_t)>( |
721 | detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s), |
722 | token, basic_streambuf_ref<Allocator>(b), transfer_all()); |
723 | } |
724 | |
725 | template <typename AsyncWriteStream, |
726 | typename Allocator, typename CompletionCondition, |
727 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
728 | std::size_t)) WriteToken> |
729 | inline auto async_write(AsyncWriteStream& s, |
730 | boost::asio::basic_streambuf<Allocator>& b, |
731 | CompletionCondition completion_condition, WriteToken&& token) |
732 | -> decltype( |
733 | async_initiate<WriteToken, |
734 | void (boost::system::error_code, std::size_t)>( |
735 | declval<detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>>(), |
736 | token, basic_streambuf_ref<Allocator>(b), |
737 | static_cast<CompletionCondition&&>(completion_condition))) |
738 | { |
739 | return async_initiate<WriteToken, |
740 | void (boost::system::error_code, std::size_t)>( |
741 | detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s), |
742 | token, basic_streambuf_ref<Allocator>(b), |
743 | static_cast<CompletionCondition&&>(completion_condition)); |
744 | } |
745 | |
746 | #endif // !defined(BOOST_ASIO_NO_IOSTREAM) |
747 | #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) |
748 | #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) |
749 | |
750 | namespace detail |
751 | { |
752 | template <typename AsyncWriteStream, typename DynamicBuffer_v2, |
753 | typename CompletionCondition, typename WriteHandler> |
754 | class write_dynbuf_v2_op |
755 | { |
756 | public: |
757 | template <typename BufferSequence> |
758 | write_dynbuf_v2_op(AsyncWriteStream& stream, |
759 | BufferSequence&& buffers, |
760 | CompletionCondition& completion_condition, WriteHandler& handler) |
761 | : stream_(stream), |
762 | buffers_(static_cast<BufferSequence&&>(buffers)), |
763 | completion_condition_( |
764 | static_cast<CompletionCondition&&>(completion_condition)), |
765 | handler_(static_cast<WriteHandler&&>(handler)) |
766 | { |
767 | } |
768 | |
769 | write_dynbuf_v2_op(const write_dynbuf_v2_op& other) |
770 | : stream_(other.stream_), |
771 | buffers_(other.buffers_), |
772 | completion_condition_(other.completion_condition_), |
773 | handler_(other.handler_) |
774 | { |
775 | } |
776 | |
777 | write_dynbuf_v2_op(write_dynbuf_v2_op&& other) |
778 | : stream_(other.stream_), |
779 | buffers_(static_cast<DynamicBuffer_v2&&>(other.buffers_)), |
780 | completion_condition_( |
781 | static_cast<CompletionCondition&&>( |
782 | other.completion_condition_)), |
783 | handler_(static_cast<WriteHandler&&>(other.handler_)) |
784 | { |
785 | } |
786 | |
787 | void operator()(const boost::system::error_code& ec, |
788 | std::size_t bytes_transferred, int start = 0) |
789 | { |
790 | switch (start) |
791 | { |
792 | case 1: |
793 | async_write(stream_, buffers_.data(0, buffers_.size()), |
794 | static_cast<CompletionCondition&&>(completion_condition_), |
795 | static_cast<write_dynbuf_v2_op&&>(*this)); |
796 | return; default: |
797 | buffers_.consume(bytes_transferred); |
798 | static_cast<WriteHandler&&>(handler_)(ec, |
799 | static_cast<const std::size_t&>(bytes_transferred)); |
800 | } |
801 | } |
802 | |
803 | //private: |
804 | AsyncWriteStream& stream_; |
805 | DynamicBuffer_v2 buffers_; |
806 | CompletionCondition completion_condition_; |
807 | WriteHandler handler_; |
808 | }; |
809 | |
810 | template <typename AsyncWriteStream, typename DynamicBuffer_v2, |
811 | typename CompletionCondition, typename WriteHandler> |
812 | inline bool asio_handler_is_continuation( |
813 | write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, |
814 | CompletionCondition, WriteHandler>* this_handler) |
815 | { |
816 | return boost_asio_handler_cont_helpers::is_continuation( |
817 | this_handler->handler_); |
818 | } |
819 | |
820 | template <typename AsyncWriteStream> |
821 | class initiate_async_write_dynbuf_v2 |
822 | { |
823 | public: |
824 | typedef typename AsyncWriteStream::executor_type executor_type; |
825 | |
826 | explicit initiate_async_write_dynbuf_v2(AsyncWriteStream& stream) |
827 | : stream_(stream) |
828 | { |
829 | } |
830 | |
831 | executor_type get_executor() const noexcept |
832 | { |
833 | return stream_.get_executor(); |
834 | } |
835 | |
836 | template <typename WriteHandler, typename DynamicBuffer_v2, |
837 | typename CompletionCondition> |
838 | void operator()(WriteHandler&& handler, |
839 | DynamicBuffer_v2&& buffers, |
840 | CompletionCondition&& completion_cond) const |
841 | { |
842 | // If you get an error on the following line it means that your handler |
843 | // does not meet the documented type requirements for a WriteHandler. |
844 | BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; |
845 | |
846 | non_const_lvalue<WriteHandler> handler2(handler); |
847 | non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); |
848 | write_dynbuf_v2_op<AsyncWriteStream, decay_t<DynamicBuffer_v2>, |
849 | CompletionCondition, decay_t<WriteHandler>>( |
850 | stream_, static_cast<DynamicBuffer_v2&&>(buffers), |
851 | completion_cond2.value, handler2.value)( |
852 | boost::system::error_code(), 0, 1); |
853 | } |
854 | |
855 | private: |
856 | AsyncWriteStream& stream_; |
857 | }; |
858 | } // namespace detail |
859 | |
860 | #if !defined(GENERATING_DOCUMENTATION) |
861 | |
862 | template <template <typename, typename> class Associator, |
863 | typename AsyncWriteStream, typename DynamicBuffer_v2, |
864 | typename CompletionCondition, typename WriteHandler, |
865 | typename DefaultCandidate> |
866 | struct associator<Associator, |
867 | detail::write_dynbuf_v2_op<AsyncWriteStream, |
868 | DynamicBuffer_v2, CompletionCondition, WriteHandler>, |
869 | DefaultCandidate> |
870 | : Associator<WriteHandler, DefaultCandidate> |
871 | { |
872 | static typename Associator<WriteHandler, DefaultCandidate>::type get( |
873 | const detail::write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, |
874 | CompletionCondition, WriteHandler>& h) noexcept |
875 | { |
876 | return Associator<WriteHandler, DefaultCandidate>::get(h.handler_); |
877 | } |
878 | |
879 | static auto get( |
880 | const detail::write_dynbuf_v2_op<AsyncWriteStream, |
881 | DynamicBuffer_v2, CompletionCondition, WriteHandler>& h, |
882 | const DefaultCandidate& c) noexcept |
883 | -> decltype(Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c)) |
884 | { |
885 | return Associator<WriteHandler, DefaultCandidate>::get(h.handler_, c); |
886 | } |
887 | }; |
888 | |
889 | #endif // !defined(GENERATING_DOCUMENTATION) |
890 | |
891 | template <typename AsyncWriteStream, typename DynamicBuffer_v2, |
892 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
893 | std::size_t)) WriteToken> |
894 | inline auto async_write(AsyncWriteStream& s, |
895 | DynamicBuffer_v2 buffers, WriteToken&& token, |
896 | constraint_t< |
897 | is_dynamic_buffer_v2<DynamicBuffer_v2>::value |
898 | >) |
899 | -> decltype( |
900 | async_initiate<WriteToken, |
901 | void (boost::system::error_code, std::size_t)>( |
902 | declval<detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>>(), |
903 | token, static_cast<DynamicBuffer_v2&&>(buffers), |
904 | transfer_all())) |
905 | { |
906 | return async_initiate<WriteToken, |
907 | void (boost::system::error_code, std::size_t)>( |
908 | detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>(s), |
909 | token, static_cast<DynamicBuffer_v2&&>(buffers), |
910 | transfer_all()); |
911 | } |
912 | |
913 | template <typename AsyncWriteStream, |
914 | typename DynamicBuffer_v2, typename CompletionCondition, |
915 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
916 | std::size_t)) WriteToken> |
917 | inline auto async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, |
918 | CompletionCondition completion_condition, WriteToken&& token, |
919 | constraint_t< |
920 | is_dynamic_buffer_v2<DynamicBuffer_v2>::value |
921 | >) |
922 | -> decltype( |
923 | async_initiate<WriteToken, |
924 | void (boost::system::error_code, std::size_t)>( |
925 | declval<detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>>(), |
926 | token, static_cast<DynamicBuffer_v2&&>(buffers), |
927 | static_cast<CompletionCondition&&>(completion_condition))) |
928 | { |
929 | return async_initiate<WriteToken, |
930 | void (boost::system::error_code, std::size_t)>( |
931 | detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>(s), |
932 | token, static_cast<DynamicBuffer_v2&&>(buffers), |
933 | static_cast<CompletionCondition&&>(completion_condition)); |
934 | } |
935 | |
936 | } // namespace asio |
937 | } // namespace boost |
938 | |
939 | #include <boost/asio/detail/pop_options.hpp> |
940 | |
941 | #endif // BOOST_ASIO_IMPL_WRITE_HPP |
942 | |