read_at.ipp 13 KB

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