File indexing completed on 2025-07-01 08:09:02
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_IMPL_READ_AT_HPP
0012 #define BOOST_ASIO_IMPL_READ_AT_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <algorithm>
0019 #include <boost/asio/associator.hpp>
0020 #include <boost/asio/buffer.hpp>
0021 #include <boost/asio/detail/array_fwd.hpp>
0022 #include <boost/asio/detail/base_from_cancellation_state.hpp>
0023 #include <boost/asio/detail/base_from_completion_cond.hpp>
0024 #include <boost/asio/detail/bind_handler.hpp>
0025 #include <boost/asio/detail/consuming_buffers.hpp>
0026 #include <boost/asio/detail/dependent_type.hpp>
0027 #include <boost/asio/detail/handler_cont_helpers.hpp>
0028 #include <boost/asio/detail/handler_tracking.hpp>
0029 #include <boost/asio/detail/handler_type_requirements.hpp>
0030 #include <boost/asio/detail/non_const_lvalue.hpp>
0031 #include <boost/asio/detail/throw_error.hpp>
0032 #include <boost/asio/error.hpp>
0033
0034 #include <boost/asio/detail/push_options.hpp>
0035
0036 namespace boost {
0037 namespace asio {
0038
0039 namespace detail
0040 {
0041 template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
0042 typename MutableBufferIterator, typename CompletionCondition>
0043 std::size_t read_at_buffer_sequence(SyncRandomAccessReadDevice& d,
0044 uint64_t offset, const MutableBufferSequence& buffers,
0045 const MutableBufferIterator&, CompletionCondition completion_condition,
0046 boost::system::error_code& ec)
0047 {
0048 ec = boost::system::error_code();
0049 boost::asio::detail::consuming_buffers<mutable_buffer,
0050 MutableBufferSequence, MutableBufferIterator> tmp(buffers);
0051 while (!tmp.empty())
0052 {
0053 if (std::size_t max_size = detail::adapt_completion_condition_result(
0054 completion_condition(ec, tmp.total_consumed())))
0055 {
0056 tmp.consume(d.read_some_at(offset + tmp.total_consumed(),
0057 tmp.prepare(max_size), ec));
0058 }
0059 else
0060 break;
0061 }
0062 return tmp.total_consumed();
0063 }
0064 }
0065
0066 template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
0067 typename CompletionCondition>
0068 std::size_t read_at(SyncRandomAccessReadDevice& d,
0069 uint64_t offset, const MutableBufferSequence& buffers,
0070 CompletionCondition completion_condition, boost::system::error_code& ec,
0071 constraint_t<
0072 is_completion_condition<CompletionCondition>::value
0073 >)
0074 {
0075 return detail::read_at_buffer_sequence(d, offset, buffers,
0076 boost::asio::buffer_sequence_begin(buffers),
0077 static_cast<CompletionCondition&&>(completion_condition), ec);
0078 }
0079
0080 template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
0081 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
0082 uint64_t offset, const MutableBufferSequence& buffers)
0083 {
0084 boost::system::error_code ec;
0085 std::size_t bytes_transferred = read_at(
0086 d, offset, buffers, transfer_all(), ec);
0087 boost::asio::detail::throw_error(ec, "read_at");
0088 return bytes_transferred;
0089 }
0090
0091 template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
0092 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
0093 uint64_t offset, const MutableBufferSequence& buffers,
0094 boost::system::error_code& ec)
0095 {
0096 return read_at(d, offset, buffers, transfer_all(), ec);
0097 }
0098
0099 template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
0100 typename CompletionCondition>
0101 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
0102 uint64_t offset, const MutableBufferSequence& buffers,
0103 CompletionCondition completion_condition,
0104 constraint_t<
0105 is_completion_condition<CompletionCondition>::value
0106 >)
0107 {
0108 boost::system::error_code ec;
0109 std::size_t bytes_transferred = read_at(d, offset, buffers,
0110 static_cast<CompletionCondition&&>(completion_condition), ec);
0111 boost::asio::detail::throw_error(ec, "read_at");
0112 return bytes_transferred;
0113 }
0114
0115 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
0116 #if !defined(BOOST_ASIO_NO_IOSTREAM)
0117
0118 template <typename SyncRandomAccessReadDevice, typename Allocator,
0119 typename CompletionCondition>
0120 std::size_t read_at(SyncRandomAccessReadDevice& d,
0121 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
0122 CompletionCondition completion_condition, boost::system::error_code& ec,
0123 constraint_t<
0124 is_completion_condition<CompletionCondition>::value
0125 >)
0126 {
0127 ec = boost::system::error_code();
0128 std::size_t total_transferred = 0;
0129 std::size_t max_size = detail::adapt_completion_condition_result(
0130 completion_condition(ec, total_transferred));
0131 std::size_t bytes_available = read_size_helper(b, max_size);
0132 while (bytes_available > 0)
0133 {
0134 std::size_t bytes_transferred = d.read_some_at(
0135 offset + total_transferred, b.prepare(bytes_available), ec);
0136 b.commit(bytes_transferred);
0137 total_transferred += bytes_transferred;
0138 max_size = detail::adapt_completion_condition_result(
0139 completion_condition(ec, total_transferred));
0140 bytes_available = read_size_helper(b, max_size);
0141 }
0142 return total_transferred;
0143 }
0144
0145 template <typename SyncRandomAccessReadDevice, typename Allocator>
0146 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
0147 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b)
0148 {
0149 boost::system::error_code ec;
0150 std::size_t bytes_transferred = read_at(
0151 d, offset, b, transfer_all(), ec);
0152 boost::asio::detail::throw_error(ec, "read_at");
0153 return bytes_transferred;
0154 }
0155
0156 template <typename SyncRandomAccessReadDevice, typename Allocator>
0157 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
0158 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
0159 boost::system::error_code& ec)
0160 {
0161 return read_at(d, offset, b, transfer_all(), ec);
0162 }
0163
0164 template <typename SyncRandomAccessReadDevice, typename Allocator,
0165 typename CompletionCondition>
0166 inline std::size_t read_at(SyncRandomAccessReadDevice& d,
0167 uint64_t offset, boost::asio::basic_streambuf<Allocator>& b,
0168 CompletionCondition completion_condition,
0169 constraint_t<
0170 is_completion_condition<CompletionCondition>::value
0171 >)
0172 {
0173 boost::system::error_code ec;
0174 std::size_t bytes_transferred = read_at(d, offset, b,
0175 static_cast<CompletionCondition&&>(completion_condition), ec);
0176 boost::asio::detail::throw_error(ec, "read_at");
0177 return bytes_transferred;
0178 }
0179
0180 #endif
0181 #endif
0182
0183 namespace detail
0184 {
0185 template <typename AsyncRandomAccessReadDevice,
0186 typename MutableBufferSequence, typename MutableBufferIterator,
0187 typename CompletionCondition, typename ReadHandler>
0188 class read_at_op
0189 : public base_from_cancellation_state<ReadHandler>,
0190 base_from_completion_cond<CompletionCondition>
0191 {
0192 public:
0193 read_at_op(AsyncRandomAccessReadDevice& device,
0194 uint64_t offset, const MutableBufferSequence& buffers,
0195 CompletionCondition& completion_condition, ReadHandler& handler)
0196 : base_from_cancellation_state<ReadHandler>(
0197 handler, enable_partial_cancellation()),
0198 base_from_completion_cond<CompletionCondition>(completion_condition),
0199 device_(device),
0200 offset_(offset),
0201 buffers_(buffers),
0202 start_(0),
0203 handler_(static_cast<ReadHandler&&>(handler))
0204 {
0205 }
0206
0207 read_at_op(const read_at_op& other)
0208 : base_from_cancellation_state<ReadHandler>(other),
0209 base_from_completion_cond<CompletionCondition>(other),
0210 device_(other.device_),
0211 offset_(other.offset_),
0212 buffers_(other.buffers_),
0213 start_(other.start_),
0214 handler_(other.handler_)
0215 {
0216 }
0217
0218 read_at_op(read_at_op&& other)
0219 : base_from_cancellation_state<ReadHandler>(
0220 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
0221 base_from_completion_cond<CompletionCondition>(
0222 static_cast<base_from_completion_cond<CompletionCondition>&&>(other)),
0223 device_(other.device_),
0224 offset_(other.offset_),
0225 buffers_(static_cast<buffers_type&&>(other.buffers_)),
0226 start_(other.start_),
0227 handler_(static_cast<ReadHandler&&>(other.handler_))
0228 {
0229 }
0230
0231 void operator()(boost::system::error_code ec,
0232 std::size_t bytes_transferred, int start = 0)
0233 {
0234 std::size_t max_size;
0235 switch (start_ = start)
0236 {
0237 case 1:
0238 max_size = this->check_for_completion(ec, buffers_.total_consumed());
0239 for (;;)
0240 {
0241 {
0242 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at"));
0243 device_.async_read_some_at(
0244 offset_ + buffers_.total_consumed(), buffers_.prepare(max_size),
0245 static_cast<read_at_op&&>(*this));
0246 }
0247 return; default:
0248 buffers_.consume(bytes_transferred);
0249 if ((!ec && bytes_transferred == 0) || buffers_.empty())
0250 break;
0251 max_size = this->check_for_completion(ec, buffers_.total_consumed());
0252 if (max_size == 0)
0253 break;
0254 if (this->cancelled() != cancellation_type::none)
0255 {
0256 ec = boost::asio::error::operation_aborted;
0257 break;
0258 }
0259 }
0260
0261 static_cast<ReadHandler&&>(handler_)(
0262 static_cast<const boost::system::error_code&>(ec),
0263 static_cast<const std::size_t&>(buffers_.total_consumed()));
0264 }
0265 }
0266
0267
0268 typedef boost::asio::detail::consuming_buffers<mutable_buffer,
0269 MutableBufferSequence, MutableBufferIterator> buffers_type;
0270
0271 AsyncRandomAccessReadDevice& device_;
0272 uint64_t offset_;
0273 buffers_type buffers_;
0274 int start_;
0275 ReadHandler handler_;
0276 };
0277
0278 template <typename AsyncRandomAccessReadDevice,
0279 typename MutableBufferSequence, typename MutableBufferIterator,
0280 typename CompletionCondition, typename ReadHandler>
0281 inline bool asio_handler_is_continuation(
0282 read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
0283 MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler)
0284 {
0285 return this_handler->start_ == 0 ? true
0286 : boost_asio_handler_cont_helpers::is_continuation(
0287 this_handler->handler_);
0288 }
0289
0290 template <typename AsyncRandomAccessReadDevice,
0291 typename MutableBufferSequence, typename MutableBufferIterator,
0292 typename CompletionCondition, typename ReadHandler>
0293 inline void start_read_at_op(AsyncRandomAccessReadDevice& d,
0294 uint64_t offset, const MutableBufferSequence& buffers,
0295 const MutableBufferIterator&, CompletionCondition& completion_condition,
0296 ReadHandler& handler)
0297 {
0298 detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
0299 MutableBufferIterator, CompletionCondition, ReadHandler>(
0300 d, offset, buffers, completion_condition, handler)(
0301 boost::system::error_code(), 0, 1);
0302 }
0303
0304 template <typename AsyncRandomAccessReadDevice>
0305 class initiate_async_read_at
0306 {
0307 public:
0308 typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;
0309
0310 explicit initiate_async_read_at(AsyncRandomAccessReadDevice& device)
0311 : device_(device)
0312 {
0313 }
0314
0315 executor_type get_executor() const noexcept
0316 {
0317 return device_.get_executor();
0318 }
0319
0320 template <typename ReadHandler, typename MutableBufferSequence,
0321 typename CompletionCondition>
0322 void operator()(ReadHandler&& handler,
0323 uint64_t offset, const MutableBufferSequence& buffers,
0324 CompletionCondition&& completion_cond) const
0325 {
0326
0327
0328 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
0329
0330 non_const_lvalue<ReadHandler> handler2(handler);
0331 non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
0332 start_read_at_op(device_, offset, buffers,
0333 boost::asio::buffer_sequence_begin(buffers),
0334 completion_cond2.value, handler2.value);
0335 }
0336
0337 private:
0338 AsyncRandomAccessReadDevice& device_;
0339 };
0340 }
0341
0342 #if !defined(GENERATING_DOCUMENTATION)
0343
0344 template <template <typename, typename> class Associator,
0345 typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
0346 typename MutableBufferIterator, typename CompletionCondition,
0347 typename ReadHandler, typename DefaultCandidate>
0348 struct associator<Associator,
0349 detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
0350 MutableBufferIterator, CompletionCondition, ReadHandler>,
0351 DefaultCandidate>
0352 : Associator<ReadHandler, DefaultCandidate>
0353 {
0354 static typename Associator<ReadHandler, DefaultCandidate>::type get(
0355 const detail::read_at_op<AsyncRandomAccessReadDevice,
0356 MutableBufferSequence, MutableBufferIterator,
0357 CompletionCondition, ReadHandler>& h) noexcept
0358 {
0359 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
0360 }
0361
0362 static auto get(
0363 const detail::read_at_op<AsyncRandomAccessReadDevice,
0364 MutableBufferSequence, MutableBufferIterator,
0365 CompletionCondition, ReadHandler>& h,
0366 const DefaultCandidate& c) noexcept
0367 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
0368 {
0369 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
0370 }
0371 };
0372
0373 #endif
0374
0375 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
0376 #if !defined(BOOST_ASIO_NO_IOSTREAM)
0377
0378 namespace detail
0379 {
0380 template <typename AsyncRandomAccessReadDevice, typename Allocator,
0381 typename CompletionCondition, typename ReadHandler>
0382 class read_at_streambuf_op
0383 : public base_from_cancellation_state<ReadHandler>,
0384 base_from_completion_cond<CompletionCondition>
0385 {
0386 public:
0387 read_at_streambuf_op(AsyncRandomAccessReadDevice& device,
0388 uint64_t offset, basic_streambuf<Allocator>& streambuf,
0389 CompletionCondition& completion_condition, ReadHandler& handler)
0390 : base_from_cancellation_state<ReadHandler>(
0391 handler, enable_partial_cancellation()),
0392 base_from_completion_cond<CompletionCondition>(completion_condition),
0393 device_(device),
0394 offset_(offset),
0395 streambuf_(streambuf),
0396 start_(0),
0397 total_transferred_(0),
0398 handler_(static_cast<ReadHandler&&>(handler))
0399 {
0400 }
0401
0402 read_at_streambuf_op(const read_at_streambuf_op& other)
0403 : base_from_cancellation_state<ReadHandler>(other),
0404 base_from_completion_cond<CompletionCondition>(other),
0405 device_(other.device_),
0406 offset_(other.offset_),
0407 streambuf_(other.streambuf_),
0408 start_(other.start_),
0409 total_transferred_(other.total_transferred_),
0410 handler_(other.handler_)
0411 {
0412 }
0413
0414 read_at_streambuf_op(read_at_streambuf_op&& other)
0415 : base_from_cancellation_state<ReadHandler>(
0416 static_cast<base_from_cancellation_state<ReadHandler>&&>(other)),
0417 base_from_completion_cond<CompletionCondition>(
0418 static_cast<base_from_completion_cond<CompletionCondition>&&>(other)),
0419 device_(other.device_),
0420 offset_(other.offset_),
0421 streambuf_(other.streambuf_),
0422 start_(other.start_),
0423 total_transferred_(other.total_transferred_),
0424 handler_(static_cast<ReadHandler&&>(other.handler_))
0425 {
0426 }
0427
0428 void operator()(boost::system::error_code ec,
0429 std::size_t bytes_transferred, int start = 0)
0430 {
0431 std::size_t max_size, bytes_available;
0432 switch (start_ = start)
0433 {
0434 case 1:
0435 max_size = this->check_for_completion(ec, total_transferred_);
0436 bytes_available = read_size_helper(streambuf_, max_size);
0437 for (;;)
0438 {
0439 {
0440 BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at"));
0441 device_.async_read_some_at(offset_ + total_transferred_,
0442 streambuf_.prepare(bytes_available),
0443 static_cast<read_at_streambuf_op&&>(*this));
0444 }
0445 return; default:
0446 total_transferred_ += bytes_transferred;
0447 streambuf_.commit(bytes_transferred);
0448 max_size = this->check_for_completion(ec, total_transferred_);
0449 bytes_available = read_size_helper(streambuf_, max_size);
0450 if ((!ec && bytes_transferred == 0) || bytes_available == 0)
0451 break;
0452 if (this->cancelled() != cancellation_type::none)
0453 {
0454 ec = boost::asio::error::operation_aborted;
0455 break;
0456 }
0457 }
0458
0459 static_cast<ReadHandler&&>(handler_)(
0460 static_cast<const boost::system::error_code&>(ec),
0461 static_cast<const std::size_t&>(total_transferred_));
0462 }
0463 }
0464
0465
0466 AsyncRandomAccessReadDevice& device_;
0467 uint64_t offset_;
0468 boost::asio::basic_streambuf<Allocator>& streambuf_;
0469 int start_;
0470 std::size_t total_transferred_;
0471 ReadHandler handler_;
0472 };
0473
0474 template <typename AsyncRandomAccessReadDevice, typename Allocator,
0475 typename CompletionCondition, typename ReadHandler>
0476 inline bool asio_handler_is_continuation(
0477 read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
0478 CompletionCondition, ReadHandler>* this_handler)
0479 {
0480 return this_handler->start_ == 0 ? true
0481 : boost_asio_handler_cont_helpers::is_continuation(
0482 this_handler->handler_);
0483 }
0484
0485 template <typename AsyncRandomAccessReadDevice>
0486 class initiate_async_read_at_streambuf
0487 {
0488 public:
0489 typedef typename AsyncRandomAccessReadDevice::executor_type executor_type;
0490
0491 explicit initiate_async_read_at_streambuf(
0492 AsyncRandomAccessReadDevice& device)
0493 : device_(device)
0494 {
0495 }
0496
0497 executor_type get_executor() const noexcept
0498 {
0499 return device_.get_executor();
0500 }
0501
0502 template <typename ReadHandler,
0503 typename Allocator, typename CompletionCondition>
0504 void operator()(ReadHandler&& handler,
0505 uint64_t offset, basic_streambuf<Allocator>* b,
0506 CompletionCondition&& completion_cond) const
0507 {
0508
0509
0510 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
0511
0512 non_const_lvalue<ReadHandler> handler2(handler);
0513 non_const_lvalue<CompletionCondition> completion_cond2(completion_cond);
0514 read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
0515 CompletionCondition, decay_t<ReadHandler>>(
0516 device_, offset, *b, completion_cond2.value, handler2.value)(
0517 boost::system::error_code(), 0, 1);
0518 }
0519
0520 private:
0521 AsyncRandomAccessReadDevice& device_;
0522 };
0523 }
0524
0525 #if !defined(GENERATING_DOCUMENTATION)
0526
0527 template <template <typename, typename> class Associator,
0528 typename AsyncRandomAccessReadDevice, typename Executor,
0529 typename CompletionCondition, typename ReadHandler,
0530 typename DefaultCandidate>
0531 struct associator<Associator,
0532 detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
0533 Executor, CompletionCondition, ReadHandler>,
0534 DefaultCandidate>
0535 : Associator<ReadHandler, DefaultCandidate>
0536 {
0537 static typename Associator<ReadHandler, DefaultCandidate>::type get(
0538 const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
0539 Executor, CompletionCondition, ReadHandler>& h) noexcept
0540 {
0541 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_);
0542 }
0543
0544 static auto get(
0545 const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
0546 Executor, CompletionCondition, ReadHandler>& h,
0547 const DefaultCandidate& c) noexcept
0548 -> decltype(Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c))
0549 {
0550 return Associator<ReadHandler, DefaultCandidate>::get(h.handler_, c);
0551 }
0552 };
0553
0554 #endif
0555
0556 #endif
0557 #endif
0558
0559 }
0560 }
0561
0562 #include <boost/asio/detail/pop_options.hpp>
0563
0564 #endif