read_at.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. //
  2. // impl/read_at.hpp
  3. // ~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2011 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. #ifndef ASIO_IMPL_READ_AT_HPP
  11. #define ASIO_IMPL_READ_AT_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <algorithm>
  16. #include "asio/buffer.hpp"
  17. #include "asio/completion_condition.hpp"
  18. #include "asio/detail/base_from_completion_cond.hpp"
  19. #include "asio/detail/bind_handler.hpp"
  20. #include "asio/detail/consuming_buffers.hpp"
  21. #include "asio/detail/handler_alloc_helpers.hpp"
  22. #include "asio/detail/handler_invoke_helpers.hpp"
  23. #include "asio/detail/throw_error.hpp"
  24. #include "asio/error.hpp"
  25. #include "asio/detail/push_options.hpp"
  26. namespace asio {
  27. template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
  28. typename CompletionCondition>
  29. std::size_t read_at(SyncRandomAccessReadDevice& d,
  30. boost::uint64_t offset, const MutableBufferSequence& buffers,
  31. CompletionCondition completion_condition, asio::error_code& ec)
  32. {
  33. ec = asio::error_code();
  34. asio::detail::consuming_buffers<
  35. mutable_buffer, MutableBufferSequence> tmp(buffers);
  36. std::size_t total_transferred = 0;
  37. tmp.prepare(detail::adapt_completion_condition_result(
  38. completion_condition(ec, total_transferred)));
  39. while (tmp.begin() != tmp.end())
  40. {
  41. std::size_t bytes_transferred = d.read_some_at(
  42. offset + total_transferred, tmp, ec);
  43. tmp.consume(bytes_transferred);
  44. total_transferred += bytes_transferred;
  45. tmp.prepare(detail::adapt_completion_condition_result(
  46. completion_condition(ec, total_transferred)));
  47. }
  48. return total_transferred;
  49. }
  50. template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence>
  51. inline std::size_t read_at(SyncRandomAccessReadDevice& d,
  52. boost::uint64_t offset, const MutableBufferSequence& buffers)
  53. {
  54. asio::error_code ec;
  55. std::size_t bytes_transferred = read_at(
  56. d, offset, buffers, transfer_all(), ec);
  57. asio::detail::throw_error(ec);
  58. return bytes_transferred;
  59. }
  60. template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence,
  61. typename CompletionCondition>
  62. inline std::size_t read_at(SyncRandomAccessReadDevice& d,
  63. boost::uint64_t offset, const MutableBufferSequence& buffers,
  64. CompletionCondition completion_condition)
  65. {
  66. asio::error_code ec;
  67. std::size_t bytes_transferred = read_at(
  68. d, offset, buffers, completion_condition, ec);
  69. asio::detail::throw_error(ec);
  70. return bytes_transferred;
  71. }
  72. #if !defined(BOOST_NO_IOSTREAM)
  73. template <typename SyncRandomAccessReadDevice, typename Allocator,
  74. typename CompletionCondition>
  75. std::size_t read_at(SyncRandomAccessReadDevice& d,
  76. boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
  77. CompletionCondition completion_condition, asio::error_code& ec)
  78. {
  79. ec = asio::error_code();
  80. std::size_t total_transferred = 0;
  81. std::size_t max_size = detail::adapt_completion_condition_result(
  82. completion_condition(ec, total_transferred));
  83. std::size_t bytes_available = read_size_helper(b, max_size);
  84. while (bytes_available > 0)
  85. {
  86. std::size_t bytes_transferred = d.read_some_at(
  87. offset + total_transferred, b.prepare(bytes_available), ec);
  88. b.commit(bytes_transferred);
  89. total_transferred += bytes_transferred;
  90. max_size = detail::adapt_completion_condition_result(
  91. completion_condition(ec, total_transferred));
  92. bytes_available = read_size_helper(b, max_size);
  93. }
  94. return total_transferred;
  95. }
  96. template <typename SyncRandomAccessReadDevice, typename Allocator>
  97. inline std::size_t read_at(SyncRandomAccessReadDevice& d,
  98. boost::uint64_t offset, asio::basic_streambuf<Allocator>& b)
  99. {
  100. asio::error_code ec;
  101. std::size_t bytes_transferred = read_at(
  102. d, offset, b, transfer_all(), ec);
  103. asio::detail::throw_error(ec);
  104. return bytes_transferred;
  105. }
  106. template <typename SyncRandomAccessReadDevice, typename Allocator,
  107. typename CompletionCondition>
  108. inline std::size_t read_at(SyncRandomAccessReadDevice& d,
  109. boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
  110. CompletionCondition completion_condition)
  111. {
  112. asio::error_code ec;
  113. std::size_t bytes_transferred = read_at(
  114. d, offset, b, completion_condition, ec);
  115. asio::detail::throw_error(ec);
  116. return bytes_transferred;
  117. }
  118. #endif // !defined(BOOST_NO_IOSTREAM)
  119. namespace detail
  120. {
  121. template <typename AsyncRandomAccessReadDevice,
  122. typename MutableBufferSequence, typename CompletionCondition,
  123. typename ReadHandler>
  124. class read_at_op
  125. : detail::base_from_completion_cond<CompletionCondition>
  126. {
  127. public:
  128. read_at_op(AsyncRandomAccessReadDevice& device,
  129. boost::uint64_t offset, const MutableBufferSequence& buffers,
  130. CompletionCondition completion_condition, ReadHandler handler)
  131. : detail::base_from_completion_cond<
  132. CompletionCondition>(completion_condition),
  133. device_(device),
  134. offset_(offset),
  135. buffers_(buffers),
  136. total_transferred_(0),
  137. handler_(handler)
  138. {
  139. }
  140. void operator()(const asio::error_code& ec,
  141. std::size_t bytes_transferred, int start = 0)
  142. {
  143. switch (start)
  144. {
  145. case 1:
  146. buffers_.prepare(this->check_for_completion(ec, total_transferred_));
  147. for (;;)
  148. {
  149. device_.async_read_some_at(
  150. offset_ + total_transferred_, buffers_, *this);
  151. return; default:
  152. total_transferred_ += bytes_transferred;
  153. buffers_.consume(bytes_transferred);
  154. buffers_.prepare(this->check_for_completion(ec, total_transferred_));
  155. if ((!ec && bytes_transferred == 0)
  156. || buffers_.begin() == buffers_.end())
  157. break;
  158. }
  159. handler_(ec, static_cast<const std::size_t&>(total_transferred_));
  160. }
  161. }
  162. //private:
  163. AsyncRandomAccessReadDevice& device_;
  164. boost::uint64_t offset_;
  165. asio::detail::consuming_buffers<
  166. mutable_buffer, MutableBufferSequence> buffers_;
  167. std::size_t total_transferred_;
  168. ReadHandler handler_;
  169. };
  170. template <typename AsyncRandomAccessReadDevice,
  171. typename CompletionCondition, typename ReadHandler>
  172. class read_at_op<AsyncRandomAccessReadDevice,
  173. asio::mutable_buffers_1, CompletionCondition, ReadHandler>
  174. : detail::base_from_completion_cond<CompletionCondition>
  175. {
  176. public:
  177. read_at_op(AsyncRandomAccessReadDevice& device,
  178. boost::uint64_t offset, const asio::mutable_buffers_1& buffers,
  179. CompletionCondition completion_condition, ReadHandler handler)
  180. : detail::base_from_completion_cond<
  181. CompletionCondition>(completion_condition),
  182. device_(device),
  183. offset_(offset),
  184. buffer_(buffers),
  185. total_transferred_(0),
  186. handler_(handler)
  187. {
  188. }
  189. void operator()(const asio::error_code& ec,
  190. std::size_t bytes_transferred, int start = 0)
  191. {
  192. std::size_t n = 0;
  193. switch (start)
  194. {
  195. case 1:
  196. n = this->check_for_completion(ec, total_transferred_);
  197. for (;;)
  198. {
  199. device_.async_read_some_at(offset_ + total_transferred_,
  200. asio::buffer(buffer_ + total_transferred_, n), *this);
  201. return; default:
  202. total_transferred_ += bytes_transferred;
  203. if ((!ec && bytes_transferred == 0)
  204. || (n = this->check_for_completion(ec, total_transferred_)) == 0
  205. || total_transferred_ == asio::buffer_size(buffer_))
  206. break;
  207. }
  208. handler_(ec, static_cast<const std::size_t&>(total_transferred_));
  209. }
  210. }
  211. //private:
  212. AsyncRandomAccessReadDevice& device_;
  213. boost::uint64_t offset_;
  214. asio::mutable_buffer buffer_;
  215. std::size_t total_transferred_;
  216. ReadHandler handler_;
  217. };
  218. template <typename AsyncRandomAccessReadDevice,
  219. typename MutableBufferSequence, typename CompletionCondition,
  220. typename ReadHandler>
  221. inline void* asio_handler_allocate(std::size_t size,
  222. read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
  223. CompletionCondition, ReadHandler>* this_handler)
  224. {
  225. return asio_handler_alloc_helpers::allocate(
  226. size, this_handler->handler_);
  227. }
  228. template <typename AsyncRandomAccessReadDevice,
  229. typename MutableBufferSequence, typename CompletionCondition,
  230. typename ReadHandler>
  231. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  232. read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
  233. CompletionCondition, ReadHandler>* this_handler)
  234. {
  235. asio_handler_alloc_helpers::deallocate(
  236. pointer, size, this_handler->handler_);
  237. }
  238. template <typename Function, typename AsyncRandomAccessReadDevice,
  239. typename MutableBufferSequence, typename CompletionCondition,
  240. typename ReadHandler>
  241. inline void asio_handler_invoke(const Function& function,
  242. read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence,
  243. CompletionCondition, ReadHandler>* this_handler)
  244. {
  245. asio_handler_invoke_helpers::invoke(
  246. function, this_handler->handler_);
  247. }
  248. } // namespace detail
  249. template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
  250. typename CompletionCondition, typename ReadHandler>
  251. inline void async_read_at(AsyncRandomAccessReadDevice& d,
  252. boost::uint64_t offset, const MutableBufferSequence& buffers,
  253. CompletionCondition completion_condition, ReadHandler handler)
  254. {
  255. detail::read_at_op<AsyncRandomAccessReadDevice,
  256. MutableBufferSequence, CompletionCondition, ReadHandler>(
  257. d, offset, buffers, completion_condition, handler)(
  258. asio::error_code(), 0, 1);
  259. }
  260. template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence,
  261. typename ReadHandler>
  262. inline void async_read_at(AsyncRandomAccessReadDevice& d,
  263. boost::uint64_t offset, const MutableBufferSequence& buffers,
  264. ReadHandler handler)
  265. {
  266. async_read_at(d, offset, buffers, transfer_all(), handler);
  267. }
  268. #if !defined(BOOST_NO_IOSTREAM)
  269. namespace detail
  270. {
  271. template <typename AsyncRandomAccessReadDevice, typename Allocator,
  272. typename CompletionCondition, typename ReadHandler>
  273. class read_at_streambuf_op
  274. : detail::base_from_completion_cond<CompletionCondition>
  275. {
  276. public:
  277. read_at_streambuf_op(AsyncRandomAccessReadDevice& device,
  278. boost::uint64_t offset, basic_streambuf<Allocator>& streambuf,
  279. CompletionCondition completion_condition, ReadHandler handler)
  280. : detail::base_from_completion_cond<
  281. CompletionCondition>(completion_condition),
  282. device_(device),
  283. offset_(offset),
  284. streambuf_(streambuf),
  285. total_transferred_(0),
  286. handler_(handler)
  287. {
  288. }
  289. void operator()(const asio::error_code& ec,
  290. std::size_t bytes_transferred, int start = 0)
  291. {
  292. std::size_t max_size, bytes_available;
  293. switch (start)
  294. {
  295. case 1:
  296. max_size = this->check_for_completion(ec, total_transferred_);
  297. bytes_available = read_size_helper(streambuf_, max_size);
  298. for (;;)
  299. {
  300. device_.async_read_some_at(offset_ + total_transferred_,
  301. streambuf_.prepare(bytes_available), *this);
  302. return; default:
  303. total_transferred_ += bytes_transferred;
  304. streambuf_.commit(bytes_transferred);
  305. max_size = this->check_for_completion(ec, total_transferred_);
  306. bytes_available = read_size_helper(streambuf_, max_size);
  307. if ((!ec && bytes_transferred == 0) || bytes_available == 0)
  308. break;
  309. }
  310. handler_(ec, static_cast<const std::size_t&>(total_transferred_));
  311. }
  312. }
  313. //private:
  314. AsyncRandomAccessReadDevice& device_;
  315. boost::uint64_t offset_;
  316. asio::basic_streambuf<Allocator>& streambuf_;
  317. std::size_t total_transferred_;
  318. ReadHandler handler_;
  319. };
  320. template <typename AsyncRandomAccessReadDevice, typename Allocator,
  321. typename CompletionCondition, typename ReadHandler>
  322. inline void* asio_handler_allocate(std::size_t size,
  323. read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
  324. CompletionCondition, ReadHandler>* this_handler)
  325. {
  326. return asio_handler_alloc_helpers::allocate(
  327. size, this_handler->handler_);
  328. }
  329. template <typename AsyncRandomAccessReadDevice, typename Allocator,
  330. typename CompletionCondition, typename ReadHandler>
  331. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  332. read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
  333. CompletionCondition, ReadHandler>* this_handler)
  334. {
  335. asio_handler_alloc_helpers::deallocate(
  336. pointer, size, this_handler->handler_);
  337. }
  338. template <typename Function, typename AsyncRandomAccessReadDevice,
  339. typename Allocator, typename CompletionCondition, typename ReadHandler>
  340. inline void asio_handler_invoke(const Function& function,
  341. read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator,
  342. CompletionCondition, ReadHandler>* this_handler)
  343. {
  344. asio_handler_invoke_helpers::invoke(
  345. function, this_handler->handler_);
  346. }
  347. } // namespace detail
  348. template <typename AsyncRandomAccessReadDevice, typename Allocator,
  349. typename CompletionCondition, typename ReadHandler>
  350. inline void async_read_at(AsyncRandomAccessReadDevice& d,
  351. boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
  352. CompletionCondition completion_condition, ReadHandler handler)
  353. {
  354. detail::read_at_streambuf_op<AsyncRandomAccessReadDevice,
  355. Allocator, CompletionCondition, ReadHandler>(
  356. d, offset, b, completion_condition, handler)(
  357. asio::error_code(), 0, 1);
  358. }
  359. template <typename AsyncRandomAccessReadDevice, typename Allocator,
  360. typename ReadHandler>
  361. inline void async_read_at(AsyncRandomAccessReadDevice& d,
  362. boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
  363. ReadHandler handler)
  364. {
  365. async_read_at(d, offset, b, transfer_all(), handler);
  366. }
  367. #endif // !defined(BOOST_NO_IOSTREAM)
  368. } // namespace asio
  369. #include "asio/detail/pop_options.hpp"
  370. #endif // ASIO_IMPL_READ_AT_HPP