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_WRITE_AT_HPP
12 #define BOOST_ASIO_IMPL_WRITE_AT_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/buffer.hpp>
21 #include <boost/asio/completion_condition.hpp>
22 #include <boost/asio/detail/array_fwd.hpp>
23 #include <boost/asio/detail/base_from_completion_cond.hpp>
24 #include <boost/asio/detail/bind_handler.hpp>
25 #include <boost/asio/detail/consuming_buffers.hpp>
26 #include <boost/asio/detail/dependent_type.hpp>
27 #include <boost/asio/detail/handler_alloc_helpers.hpp>
28 #include <boost/asio/detail/handler_cont_helpers.hpp>
29 #include <boost/asio/detail/handler_invoke_helpers.hpp>
30 #include <boost/asio/detail/handler_type_requirements.hpp>
31 #include <boost/asio/detail/non_const_lvalue.hpp>
32 #include <boost/asio/detail/throw_error.hpp>
34 #include <boost/asio/detail/push_options.hpp>
41 template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
42 typename ConstBufferIterator, typename CompletionCondition>
43 std::size_t write_at_buffer_sequence(SyncRandomAccessWriteDevice& d,
44 uint64_t offset, const ConstBufferSequence& buffers,
45 const ConstBufferIterator&, CompletionCondition completion_condition,
46 boost::system::error_code& ec)
48 ec = boost::system::error_code();
49 boost::asio::detail::consuming_buffers<const_buffer,
50 ConstBufferSequence, ConstBufferIterator> tmp(buffers);
53 if (std::size_t max_size = detail::adapt_completion_condition_result(
54 completion_condition(ec, tmp.total_consumed())))
56 tmp.consume(d.write_some_at(offset + tmp.total_consumed(),
57 tmp.prepare(max_size), ec));
62 return tmp.total_consumed();;
66 template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
67 typename CompletionCondition>
68 std::size_t write_at(SyncRandomAccessWriteDevice& d,
69 uint64_t offset, const ConstBufferSequence& buffers,
70 CompletionCondition completion_condition, boost::system::error_code& ec)
72 return detail::write_at_buffer_sequence(d, offset, buffers,
73 boost::asio::buffer_sequence_begin(buffers),
74 BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
77 template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
78 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
79 uint64_t offset, const ConstBufferSequence& buffers)
81 boost::system::error_code ec;
82 std::size_t bytes_transferred = write_at(
83 d, offset, buffers, transfer_all(), ec);
84 boost::asio::detail::throw_error(ec, "write_at");
85 return bytes_transferred;
88 template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
89 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
90 uint64_t offset, const ConstBufferSequence& buffers,
91 boost::system::error_code& ec)
93 return write_at(d, offset, buffers, transfer_all(), ec);
96 template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
97 typename CompletionCondition>
98 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
99 uint64_t offset, const ConstBufferSequence& buffers,
100 CompletionCondition completion_condition)
102 boost::system::error_code ec;
103 std::size_t bytes_transferred = write_at(d, offset, buffers,
104 BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
105 boost::asio::detail::throw_error(ec, "write_at");
106 return bytes_transferred;
109 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
110 #if !defined(BOOST_ASIO_NO_IOSTREAM)
112 template <typename SyncRandomAccessWriteDevice, typename Allocator,
113 typename CompletionCondition>
114 std::size_t write_at(SyncRandomAccessWriteDevice& d,
115 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
116 CompletionCondition completion_condition, boost::system::error_code& ec)
118 std::size_t bytes_transferred = write_at(d, offset, b.data(),
119 BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
120 b.consume(bytes_transferred);
121 return bytes_transferred;
124 template <typename SyncRandomAccessWriteDevice, typename Allocator>
125 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
126 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b)
128 boost::system::error_code ec;
129 std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec);
130 boost::asio::detail::throw_error(ec, "write_at");
131 return bytes_transferred;
134 template <typename SyncRandomAccessWriteDevice, typename Allocator>
135 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
136 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
137 boost::system::error_code& ec)
139 return write_at(d, offset, b, transfer_all(), ec);
142 template <typename SyncRandomAccessWriteDevice, typename Allocator,
143 typename CompletionCondition>
144 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
145 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
146 CompletionCondition completion_condition)
148 boost::system::error_code ec;
149 std::size_t bytes_transferred = write_at(d, offset, b,
150 BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec);
151 boost::asio::detail::throw_error(ec, "write_at");
152 return bytes_transferred;
155 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
156 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
160 template <typename AsyncRandomAccessWriteDevice,
161 typename ConstBufferSequence, typename ConstBufferIterator,
162 typename CompletionCondition, typename WriteHandler>
164 : detail::base_from_completion_cond<CompletionCondition>
167 write_at_op(AsyncRandomAccessWriteDevice& device,
168 uint64_t offset, const ConstBufferSequence& buffers,
169 CompletionCondition& completion_condition, WriteHandler& handler)
170 : detail::base_from_completion_cond<
171 CompletionCondition>(completion_condition),
176 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
180 #if defined(BOOST_ASIO_HAS_MOVE)
181 write_at_op(const write_at_op& other)
182 : detail::base_from_completion_cond<CompletionCondition>(other),
183 device_(other.device_),
184 offset_(other.offset_),
185 buffers_(other.buffers_),
186 start_(other.start_),
187 handler_(other.handler_)
191 write_at_op(write_at_op&& other)
192 : detail::base_from_completion_cond<CompletionCondition>(
193 BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond<
194 CompletionCondition>)(other)),
195 device_(other.device_),
196 offset_(other.offset_),
197 buffers_(BOOST_ASIO_MOVE_CAST(buffers_type)(other.buffers_)),
198 start_(other.start_),
199 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
202 #endif // defined(BOOST_ASIO_HAS_MOVE)
204 void operator()(const boost::system::error_code& ec,
205 std::size_t bytes_transferred, int start = 0)
207 std::size_t max_size;
208 switch (start_ = start)
211 max_size = this->check_for_completion(ec, buffers_.total_consumed());
214 device_.async_write_some_at(
215 offset_ + buffers_.total_consumed(), buffers_.prepare(max_size),
216 BOOST_ASIO_MOVE_CAST(write_at_op)(*this));
218 buffers_.consume(bytes_transferred);
219 if ((!ec && bytes_transferred == 0) || buffers_.empty())
221 max_size = this->check_for_completion(ec, buffers_.total_consumed());
222 } while (max_size > 0);
224 handler_(ec, buffers_.total_consumed());
229 typedef boost::asio::detail::consuming_buffers<const_buffer,
230 ConstBufferSequence, ConstBufferIterator> buffers_type;
232 AsyncRandomAccessWriteDevice& device_;
234 buffers_type buffers_;
236 WriteHandler handler_;
239 template <typename AsyncRandomAccessWriteDevice,
240 typename ConstBufferSequence, typename ConstBufferIterator,
241 typename CompletionCondition, typename WriteHandler>
242 inline void* asio_handler_allocate(std::size_t size,
243 write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
244 ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
246 return boost_asio_handler_alloc_helpers::allocate(
247 size, this_handler->handler_);
250 template <typename AsyncRandomAccessWriteDevice,
251 typename ConstBufferSequence, typename ConstBufferIterator,
252 typename CompletionCondition, typename WriteHandler>
253 inline void asio_handler_deallocate(void* pointer, std::size_t size,
254 write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
255 ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
257 boost_asio_handler_alloc_helpers::deallocate(
258 pointer, size, this_handler->handler_);
261 template <typename AsyncRandomAccessWriteDevice,
262 typename ConstBufferSequence, typename ConstBufferIterator,
263 typename CompletionCondition, typename WriteHandler>
264 inline bool asio_handler_is_continuation(
265 write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
266 ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
268 return this_handler->start_ == 0 ? true
269 : boost_asio_handler_cont_helpers::is_continuation(
270 this_handler->handler_);
273 template <typename Function, typename AsyncRandomAccessWriteDevice,
274 typename ConstBufferSequence, typename ConstBufferIterator,
275 typename CompletionCondition, typename WriteHandler>
276 inline void asio_handler_invoke(Function& function,
277 write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
278 ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
280 boost_asio_handler_invoke_helpers::invoke(
281 function, this_handler->handler_);
284 template <typename Function, typename AsyncRandomAccessWriteDevice,
285 typename ConstBufferSequence, typename ConstBufferIterator,
286 typename CompletionCondition, typename WriteHandler>
287 inline void asio_handler_invoke(const Function& function,
288 write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
289 ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
291 boost_asio_handler_invoke_helpers::invoke(
292 function, this_handler->handler_);
295 template <typename AsyncRandomAccessWriteDevice,
296 typename ConstBufferSequence, typename ConstBufferIterator,
297 typename CompletionCondition, typename WriteHandler>
298 inline void start_write_at_buffer_sequence_op(AsyncRandomAccessWriteDevice& d,
299 uint64_t offset, const ConstBufferSequence& buffers,
300 const ConstBufferIterator&, CompletionCondition& completion_condition,
301 WriteHandler& handler)
303 detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
304 ConstBufferIterator, CompletionCondition, WriteHandler>(
305 d, offset, buffers, completion_condition, handler)(
306 boost::system::error_code(), 0, 1);
309 template <typename AsyncRandomAccessWriteDevice>
310 class initiate_async_write_at_buffer_sequence
313 typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type;
315 explicit initiate_async_write_at_buffer_sequence(
316 AsyncRandomAccessWriteDevice& device)
321 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
323 return device_.get_executor();
326 template <typename WriteHandler, typename ConstBufferSequence,
327 typename CompletionCondition>
328 void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
329 uint64_t offset, const ConstBufferSequence& buffers,
330 BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const
332 // If you get an error on the following line it means that your handler
333 // does not meet the documented type requirements for a WriteHandler.
334 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
336 non_const_lvalue<WriteHandler> handler2(handler);
337 non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
338 start_write_at_buffer_sequence_op(device_, offset, buffers,
339 boost::asio::buffer_sequence_begin(buffers),
340 completion_cond2.value, handler2.value);
344 AsyncRandomAccessWriteDevice& device_;
346 } // namespace detail
348 #if !defined(GENERATING_DOCUMENTATION)
350 template <typename AsyncRandomAccessWriteDevice,
351 typename ConstBufferSequence, typename ConstBufferIterator,
352 typename CompletionCondition, typename WriteHandler, typename Allocator>
353 struct associated_allocator<
354 detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
355 ConstBufferIterator, CompletionCondition, WriteHandler>,
358 typedef typename associated_allocator<WriteHandler, Allocator>::type type;
361 const detail::write_at_op<AsyncRandomAccessWriteDevice,
362 ConstBufferSequence, ConstBufferIterator,
363 CompletionCondition, WriteHandler>& h,
364 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
366 return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
370 template <typename AsyncRandomAccessWriteDevice,
371 typename ConstBufferSequence, typename ConstBufferIterator,
372 typename CompletionCondition, typename WriteHandler, typename Executor>
373 struct associated_executor<
374 detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
375 ConstBufferIterator, CompletionCondition, WriteHandler>,
378 typedef typename associated_executor<WriteHandler, Executor>::type type;
381 const detail::write_at_op<AsyncRandomAccessWriteDevice,
382 ConstBufferSequence, ConstBufferIterator,
383 CompletionCondition, WriteHandler>& h,
384 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
386 return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
390 #endif // !defined(GENERATING_DOCUMENTATION)
392 template <typename AsyncRandomAccessWriteDevice,
393 typename ConstBufferSequence, typename CompletionCondition,
394 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
395 std::size_t)) WriteHandler>
396 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
397 void (boost::system::error_code, std::size_t))
398 async_write_at(AsyncRandomAccessWriteDevice& d,
399 uint64_t offset, const ConstBufferSequence& buffers,
400 CompletionCondition completion_condition,
401 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
403 return async_initiate<WriteHandler,
404 void (boost::system::error_code, std::size_t)>(
405 detail::initiate_async_write_at_buffer_sequence<
406 AsyncRandomAccessWriteDevice>(d),
407 handler, offset, buffers,
408 BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
411 template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
412 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
413 std::size_t)) WriteHandler>
414 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
415 void (boost::system::error_code, std::size_t))
416 async_write_at(AsyncRandomAccessWriteDevice& d,
417 uint64_t offset, const ConstBufferSequence& buffers,
418 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
420 return async_initiate<WriteHandler,
421 void (boost::system::error_code, std::size_t)>(
422 detail::initiate_async_write_at_buffer_sequence<
423 AsyncRandomAccessWriteDevice>(d),
424 handler, offset, buffers, transfer_all());
427 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
428 #if !defined(BOOST_ASIO_NO_IOSTREAM)
432 template <typename Allocator, typename WriteHandler>
433 class write_at_streambuf_op
436 write_at_streambuf_op(
437 boost::asio::basic_streambuf<Allocator>& streambuf,
438 WriteHandler& handler)
439 : streambuf_(streambuf),
440 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
444 #if defined(BOOST_ASIO_HAS_MOVE)
445 write_at_streambuf_op(const write_at_streambuf_op& other)
446 : streambuf_(other.streambuf_),
447 handler_(other.handler_)
451 write_at_streambuf_op(write_at_streambuf_op&& other)
452 : streambuf_(other.streambuf_),
453 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
456 #endif // defined(BOOST_ASIO_HAS_MOVE)
458 void operator()(const boost::system::error_code& ec,
459 const std::size_t bytes_transferred)
461 streambuf_.consume(bytes_transferred);
462 handler_(ec, bytes_transferred);
466 boost::asio::basic_streambuf<Allocator>& streambuf_;
467 WriteHandler handler_;
470 template <typename Allocator, typename WriteHandler>
471 inline void* asio_handler_allocate(std::size_t size,
472 write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
474 return boost_asio_handler_alloc_helpers::allocate(
475 size, this_handler->handler_);
478 template <typename Allocator, typename WriteHandler>
479 inline void asio_handler_deallocate(void* pointer, std::size_t size,
480 write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
482 boost_asio_handler_alloc_helpers::deallocate(
483 pointer, size, this_handler->handler_);
486 template <typename Allocator, typename WriteHandler>
487 inline bool asio_handler_is_continuation(
488 write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
490 return boost_asio_handler_cont_helpers::is_continuation(
491 this_handler->handler_);
494 template <typename Function, typename Allocator, typename WriteHandler>
495 inline void asio_handler_invoke(Function& function,
496 write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
498 boost_asio_handler_invoke_helpers::invoke(
499 function, this_handler->handler_);
502 template <typename Function, typename Allocator, typename WriteHandler>
503 inline void asio_handler_invoke(const Function& function,
504 write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
506 boost_asio_handler_invoke_helpers::invoke(
507 function, this_handler->handler_);
510 template <typename AsyncRandomAccessWriteDevice>
511 class initiate_async_write_at_streambuf
514 typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type;
516 explicit initiate_async_write_at_streambuf(
517 AsyncRandomAccessWriteDevice& device)
522 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
524 return device_.get_executor();
527 template <typename WriteHandler,
528 typename Allocator, typename CompletionCondition>
529 void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
530 uint64_t offset, basic_streambuf<Allocator>* b,
531 BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_condition) const
533 // If you get an error on the following line it means that your handler
534 // does not meet the documented type requirements for a WriteHandler.
535 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
537 non_const_lvalue<WriteHandler> handler2(handler);
538 async_write_at(device_, offset, b->data(),
539 BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition),
540 write_at_streambuf_op<Allocator, typename decay<WriteHandler>::type>(
541 *b, handler2.value));
545 AsyncRandomAccessWriteDevice& device_;
547 } // namespace detail
549 #if !defined(GENERATING_DOCUMENTATION)
551 template <typename Allocator, typename WriteHandler, typename Allocator1>
552 struct associated_allocator<
553 detail::write_at_streambuf_op<Allocator, WriteHandler>,
556 typedef typename associated_allocator<WriteHandler, Allocator1>::type type;
559 const detail::write_at_streambuf_op<Allocator, WriteHandler>& h,
560 const Allocator1& a = Allocator1()) BOOST_ASIO_NOEXCEPT
562 return associated_allocator<WriteHandler, Allocator1>::get(h.handler_, a);
566 template <typename Executor, typename WriteHandler, typename Executor1>
567 struct associated_executor<
568 detail::write_at_streambuf_op<Executor, WriteHandler>,
571 typedef typename associated_executor<WriteHandler, Executor1>::type type;
574 const detail::write_at_streambuf_op<Executor, WriteHandler>& h,
575 const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT
577 return associated_executor<WriteHandler, Executor1>::get(h.handler_, ex);
581 #endif // !defined(GENERATING_DOCUMENTATION)
583 template <typename AsyncRandomAccessWriteDevice,
584 typename Allocator, typename CompletionCondition,
585 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
586 std::size_t)) WriteHandler>
587 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
588 void (boost::system::error_code, std::size_t))
589 async_write_at(AsyncRandomAccessWriteDevice& d,
590 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
591 CompletionCondition completion_condition,
592 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
594 return async_initiate<WriteHandler,
595 void (boost::system::error_code, std::size_t)>(
596 detail::initiate_async_write_at_streambuf<
597 AsyncRandomAccessWriteDevice>(d),
599 BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition));
602 template <typename AsyncRandomAccessWriteDevice, typename Allocator,
603 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
604 std::size_t)) WriteHandler>
605 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
606 void (boost::system::error_code, std::size_t))
607 async_write_at(AsyncRandomAccessWriteDevice& d,
608 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
609 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
611 return async_initiate<WriteHandler,
612 void (boost::system::error_code, std::size_t)>(
613 detail::initiate_async_write_at_streambuf<
614 AsyncRandomAccessWriteDevice>(d),
615 handler, offset, &b, transfer_all());
618 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
619 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
624 #include <boost/asio/detail/pop_options.hpp>
626 #endif // BOOST_ASIO_IMPL_WRITE_AT_HPP