5 // Copyright (c) 2003-2017 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/throw_error.hpp>
33 #include <boost/asio/detail/push_options.hpp>
40 template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
41 typename ConstBufferIterator, typename CompletionCondition>
42 std::size_t write_at_buffer_sequence(SyncRandomAccessWriteDevice& d,
43 uint64_t offset, const ConstBufferSequence& buffers,
44 const ConstBufferIterator&, CompletionCondition completion_condition,
45 boost::system::error_code& ec)
47 ec = boost::system::error_code();
48 boost::asio::detail::consuming_buffers<const_buffer,
49 ConstBufferSequence, ConstBufferIterator> tmp(buffers);
52 if (std::size_t max_size = detail::adapt_completion_condition_result(
53 completion_condition(ec, tmp.total_consumed())))
55 tmp.consume(d.write_some_at(offset + tmp.total_consumed(),
56 tmp.prepare(max_size), ec));
61 return tmp.total_consumed();;
65 template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
66 typename CompletionCondition>
67 std::size_t write_at(SyncRandomAccessWriteDevice& d,
68 uint64_t offset, const ConstBufferSequence& buffers,
69 CompletionCondition completion_condition, boost::system::error_code& ec)
71 return detail::write_at_buffer_sequence(d, offset, buffers,
72 boost::asio::buffer_sequence_begin(buffers), completion_condition, ec);
75 template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
76 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
77 uint64_t offset, const ConstBufferSequence& buffers)
79 boost::system::error_code ec;
80 std::size_t bytes_transferred = write_at(
81 d, offset, buffers, transfer_all(), ec);
82 boost::asio::detail::throw_error(ec, "write_at");
83 return bytes_transferred;
86 template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence>
87 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
88 uint64_t offset, const ConstBufferSequence& buffers,
89 boost::system::error_code& ec)
91 return write_at(d, offset, buffers, transfer_all(), ec);
94 template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence,
95 typename CompletionCondition>
96 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
97 uint64_t offset, const ConstBufferSequence& buffers,
98 CompletionCondition completion_condition)
100 boost::system::error_code ec;
101 std::size_t bytes_transferred = write_at(
102 d, offset, buffers, completion_condition, ec);
103 boost::asio::detail::throw_error(ec, "write_at");
104 return bytes_transferred;
107 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
108 #if !defined(BOOST_ASIO_NO_IOSTREAM)
110 template <typename SyncRandomAccessWriteDevice, typename Allocator,
111 typename CompletionCondition>
112 std::size_t write_at(SyncRandomAccessWriteDevice& d,
113 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
114 CompletionCondition completion_condition, boost::system::error_code& ec)
116 std::size_t bytes_transferred = write_at(
117 d, offset, b.data(), completion_condition, ec);
118 b.consume(bytes_transferred);
119 return bytes_transferred;
122 template <typename SyncRandomAccessWriteDevice, typename Allocator>
123 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
124 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b)
126 boost::system::error_code ec;
127 std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec);
128 boost::asio::detail::throw_error(ec, "write_at");
129 return bytes_transferred;
132 template <typename SyncRandomAccessWriteDevice, typename Allocator>
133 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
134 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
135 boost::system::error_code& ec)
137 return write_at(d, offset, b, transfer_all(), ec);
140 template <typename SyncRandomAccessWriteDevice, typename Allocator,
141 typename CompletionCondition>
142 inline std::size_t write_at(SyncRandomAccessWriteDevice& d,
143 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
144 CompletionCondition completion_condition)
146 boost::system::error_code ec;
147 std::size_t bytes_transferred = write_at(
148 d, offset, b, completion_condition, ec);
149 boost::asio::detail::throw_error(ec, "write_at");
150 return bytes_transferred;
153 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
154 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
158 template <typename AsyncRandomAccessWriteDevice,
159 typename ConstBufferSequence, typename ConstBufferIterator,
160 typename CompletionCondition, typename WriteHandler>
162 : detail::base_from_completion_cond<CompletionCondition>
165 write_at_op(AsyncRandomAccessWriteDevice& device,
166 uint64_t offset, const ConstBufferSequence& buffers,
167 CompletionCondition completion_condition, WriteHandler& handler)
168 : detail::base_from_completion_cond<
169 CompletionCondition>(completion_condition),
174 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
178 #if defined(BOOST_ASIO_HAS_MOVE)
179 write_at_op(const write_at_op& other)
180 : detail::base_from_completion_cond<CompletionCondition>(other),
181 device_(other.device_),
182 offset_(other.offset_),
183 buffers_(other.buffers_),
184 start_(other.start_),
185 handler_(other.handler_)
189 write_at_op(write_at_op&& other)
190 : detail::base_from_completion_cond<CompletionCondition>(other),
191 device_(other.device_),
192 offset_(other.offset_),
193 buffers_(other.buffers_),
194 start_(other.start_),
195 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
198 #endif // defined(BOOST_ASIO_HAS_MOVE)
200 void operator()(const boost::system::error_code& ec,
201 std::size_t bytes_transferred, int start = 0)
203 std::size_t max_size;
204 switch (start_ = start)
207 max_size = this->check_for_completion(ec, buffers_.total_consumed());
210 device_.async_write_some_at(
211 offset_ + buffers_.total_consumed(), buffers_.prepare(max_size),
212 BOOST_ASIO_MOVE_CAST(write_at_op)(*this));
214 buffers_.consume(bytes_transferred);
215 if ((!ec && bytes_transferred == 0) || buffers_.empty())
217 max_size = this->check_for_completion(ec, buffers_.total_consumed());
218 } while (max_size > 0);
220 handler_(ec, buffers_.total_consumed());
225 AsyncRandomAccessWriteDevice& device_;
227 boost::asio::detail::consuming_buffers<const_buffer,
228 ConstBufferSequence, ConstBufferIterator> buffers_;
230 WriteHandler handler_;
233 template <typename AsyncRandomAccessWriteDevice,
234 typename ConstBufferSequence, typename ConstBufferIterator,
235 typename CompletionCondition, typename WriteHandler>
236 inline void* asio_handler_allocate(std::size_t size,
237 write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
238 ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
240 return boost_asio_handler_alloc_helpers::allocate(
241 size, this_handler->handler_);
244 template <typename AsyncRandomAccessWriteDevice,
245 typename ConstBufferSequence, typename ConstBufferIterator,
246 typename CompletionCondition, typename WriteHandler>
247 inline void asio_handler_deallocate(void* pointer, std::size_t size,
248 write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
249 ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
251 boost_asio_handler_alloc_helpers::deallocate(
252 pointer, size, this_handler->handler_);
255 template <typename AsyncRandomAccessWriteDevice,
256 typename ConstBufferSequence, typename ConstBufferIterator,
257 typename CompletionCondition, typename WriteHandler>
258 inline bool asio_handler_is_continuation(
259 write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
260 ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
262 return this_handler->start_ == 0 ? true
263 : boost_asio_handler_cont_helpers::is_continuation(
264 this_handler->handler_);
267 template <typename Function, typename AsyncRandomAccessWriteDevice,
268 typename ConstBufferSequence, typename ConstBufferIterator,
269 typename CompletionCondition, typename WriteHandler>
270 inline void asio_handler_invoke(Function& function,
271 write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
272 ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
274 boost_asio_handler_invoke_helpers::invoke(
275 function, this_handler->handler_);
278 template <typename Function, typename AsyncRandomAccessWriteDevice,
279 typename ConstBufferSequence, typename ConstBufferIterator,
280 typename CompletionCondition, typename WriteHandler>
281 inline void asio_handler_invoke(const Function& function,
282 write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
283 ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler)
285 boost_asio_handler_invoke_helpers::invoke(
286 function, this_handler->handler_);
289 template <typename AsyncRandomAccessWriteDevice,
290 typename ConstBufferSequence, typename ConstBufferIterator,
291 typename CompletionCondition, typename WriteHandler>
292 inline void start_write_at_buffer_sequence_op(AsyncRandomAccessWriteDevice& d,
293 uint64_t offset, const ConstBufferSequence& buffers,
294 const ConstBufferIterator&, CompletionCondition completion_condition,
295 WriteHandler& handler)
297 detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
298 ConstBufferIterator, CompletionCondition, WriteHandler>(
299 d, offset, buffers, completion_condition, handler)(
300 boost::system::error_code(), 0, 1);
302 } // namespace detail
304 #if !defined(GENERATING_DOCUMENTATION)
306 template <typename AsyncRandomAccessWriteDevice,
307 typename ConstBufferSequence, typename ConstBufferIterator,
308 typename CompletionCondition, typename WriteHandler, typename Allocator>
309 struct associated_allocator<
310 detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
311 ConstBufferIterator, CompletionCondition, WriteHandler>,
314 typedef typename associated_allocator<WriteHandler, Allocator>::type type;
317 const detail::write_at_op<AsyncRandomAccessWriteDevice,
318 ConstBufferSequence, ConstBufferIterator,
319 CompletionCondition, WriteHandler>& h,
320 const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT
322 return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
326 template <typename AsyncRandomAccessWriteDevice,
327 typename ConstBufferSequence, typename ConstBufferIterator,
328 typename CompletionCondition, typename WriteHandler, typename Executor>
329 struct associated_executor<
330 detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence,
331 ConstBufferIterator, CompletionCondition, WriteHandler>,
334 typedef typename associated_executor<WriteHandler, Executor>::type type;
337 const detail::write_at_op<AsyncRandomAccessWriteDevice,
338 ConstBufferSequence, ConstBufferIterator,
339 CompletionCondition, WriteHandler>& h,
340 const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT
342 return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
346 #endif // !defined(GENERATING_DOCUMENTATION)
348 template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
349 typename CompletionCondition, typename WriteHandler>
350 inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
351 void (boost::system::error_code, std::size_t))
352 async_write_at(AsyncRandomAccessWriteDevice& d,
353 uint64_t offset, const ConstBufferSequence& buffers,
354 CompletionCondition completion_condition,
355 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
357 // If you get an error on the following line it means that your handler does
358 // not meet the documented type requirements for a WriteHandler.
359 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
361 async_completion<WriteHandler,
362 void (boost::system::error_code, std::size_t)> init(handler);
364 detail::start_write_at_buffer_sequence_op(d, offset, buffers,
365 boost::asio::buffer_sequence_begin(buffers), completion_condition,
366 init.completion_handler);
368 return init.result.get();
371 template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence,
372 typename WriteHandler>
373 inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
374 void (boost::system::error_code, std::size_t))
375 async_write_at(AsyncRandomAccessWriteDevice& d,
376 uint64_t offset, const ConstBufferSequence& buffers,
377 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
379 // If you get an error on the following line it means that your handler does
380 // not meet the documented type requirements for a WriteHandler.
381 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
383 async_completion<WriteHandler,
384 void (boost::system::error_code, std::size_t)> init(handler);
386 detail::start_write_at_buffer_sequence_op(d, offset, buffers,
387 boost::asio::buffer_sequence_begin(buffers), transfer_all(),
388 init.completion_handler);
390 return init.result.get();
393 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
394 #if !defined(BOOST_ASIO_NO_IOSTREAM)
398 template <typename Allocator, typename WriteHandler>
399 class write_at_streambuf_op
402 write_at_streambuf_op(
403 boost::asio::basic_streambuf<Allocator>& streambuf,
404 WriteHandler& handler)
405 : streambuf_(streambuf),
406 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler))
410 #if defined(BOOST_ASIO_HAS_MOVE)
411 write_at_streambuf_op(const write_at_streambuf_op& other)
412 : streambuf_(other.streambuf_),
413 handler_(other.handler_)
417 write_at_streambuf_op(write_at_streambuf_op&& other)
418 : streambuf_(other.streambuf_),
419 handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_))
422 #endif // defined(BOOST_ASIO_HAS_MOVE)
424 void operator()(const boost::system::error_code& ec,
425 const std::size_t bytes_transferred)
427 streambuf_.consume(bytes_transferred);
428 handler_(ec, bytes_transferred);
432 boost::asio::basic_streambuf<Allocator>& streambuf_;
433 WriteHandler handler_;
436 template <typename Allocator, typename WriteHandler>
437 inline void* asio_handler_allocate(std::size_t size,
438 write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
440 return boost_asio_handler_alloc_helpers::allocate(
441 size, this_handler->handler_);
444 template <typename Allocator, typename WriteHandler>
445 inline void asio_handler_deallocate(void* pointer, std::size_t size,
446 write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
448 boost_asio_handler_alloc_helpers::deallocate(
449 pointer, size, this_handler->handler_);
452 template <typename Allocator, typename WriteHandler>
453 inline bool asio_handler_is_continuation(
454 write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
456 return boost_asio_handler_cont_helpers::is_continuation(
457 this_handler->handler_);
460 template <typename Function, typename Allocator, typename WriteHandler>
461 inline void asio_handler_invoke(Function& function,
462 write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
464 boost_asio_handler_invoke_helpers::invoke(
465 function, this_handler->handler_);
468 template <typename Function, typename Allocator, typename WriteHandler>
469 inline void asio_handler_invoke(const Function& function,
470 write_at_streambuf_op<Allocator, WriteHandler>* this_handler)
472 boost_asio_handler_invoke_helpers::invoke(
473 function, this_handler->handler_);
476 template <typename Allocator, typename WriteHandler>
477 inline write_at_streambuf_op<Allocator, WriteHandler>
478 make_write_at_streambuf_op(
479 boost::asio::basic_streambuf<Allocator>& b, WriteHandler handler)
481 return write_at_streambuf_op<Allocator, WriteHandler>(b, handler);
483 } // namespace detail
485 #if !defined(GENERATING_DOCUMENTATION)
487 template <typename Allocator, typename WriteHandler, typename Allocator1>
488 struct associated_allocator<
489 detail::write_at_streambuf_op<Allocator, WriteHandler>,
492 typedef typename associated_allocator<WriteHandler, Allocator1>::type type;
495 const detail::write_at_streambuf_op<Allocator, WriteHandler>& h,
496 const Allocator1& a = Allocator1()) BOOST_ASIO_NOEXCEPT
498 return associated_allocator<WriteHandler, Allocator1>::get(h.handler_, a);
502 template <typename Executor, typename WriteHandler, typename Executor1>
503 struct associated_executor<
504 detail::write_at_streambuf_op<Executor, WriteHandler>,
507 typedef typename associated_executor<WriteHandler, Executor1>::type type;
510 const detail::write_at_streambuf_op<Executor, WriteHandler>& h,
511 const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT
513 return associated_executor<WriteHandler, Executor1>::get(h.handler_, ex);
517 #endif // !defined(GENERATING_DOCUMENTATION)
519 template <typename AsyncRandomAccessWriteDevice, typename Allocator,
520 typename CompletionCondition, typename WriteHandler>
521 inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
522 void (boost::system::error_code, std::size_t))
523 async_write_at(AsyncRandomAccessWriteDevice& d,
524 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
525 CompletionCondition completion_condition,
526 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
528 // If you get an error on the following line it means that your handler does
529 // not meet the documented type requirements for a WriteHandler.
530 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
532 async_completion<WriteHandler,
533 void (boost::system::error_code, std::size_t)> init(handler);
535 async_write_at(d, offset, b.data(), completion_condition,
536 detail::write_at_streambuf_op<Allocator, BOOST_ASIO_HANDLER_TYPE(
537 WriteHandler, void (boost::system::error_code, std::size_t))>(
538 b, init.completion_handler));
540 return init.result.get();
543 template <typename AsyncRandomAccessWriteDevice, typename Allocator,
544 typename WriteHandler>
545 inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
546 void (boost::system::error_code, std::size_t))
547 async_write_at(AsyncRandomAccessWriteDevice& d,
548 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
549 BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
551 // If you get an error on the following line it means that your handler does
552 // not meet the documented type requirements for a WriteHandler.
553 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
555 async_completion<WriteHandler,
556 void (boost::system::error_code, std::size_t)> init(handler);
558 async_write_at(d, offset, b.data(), transfer_all(),
559 detail::write_at_streambuf_op<Allocator, BOOST_ASIO_HANDLER_TYPE(
560 WriteHandler, void (boost::system::error_code, std::size_t))>(
561 b, init.completion_handler));
563 return init.result.get();
566 #endif // !defined(BOOST_ASIO_NO_IOSTREAM)
567 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
572 #include <boost/asio/detail/pop_options.hpp>
574 #endif // BOOST_ASIO_IMPL_WRITE_AT_HPP