Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

431 lines
13KB

  1. //
  2. // impl/buffered_write_stream.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 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_BUFFERED_WRITE_STREAM_HPP
  11. #define ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include "asio/associated_allocator.hpp"
  16. #include "asio/associated_executor.hpp"
  17. #include "asio/detail/handler_alloc_helpers.hpp"
  18. #include "asio/detail/handler_cont_helpers.hpp"
  19. #include "asio/detail/handler_invoke_helpers.hpp"
  20. #include "asio/detail/handler_type_requirements.hpp"
  21. #include "asio/detail/non_const_lvalue.hpp"
  22. #include "asio/detail/push_options.hpp"
  23. namespace asio {
  24. template <typename Stream>
  25. std::size_t buffered_write_stream<Stream>::flush()
  26. {
  27. std::size_t bytes_written = write(next_layer_,
  28. buffer(storage_.data(), storage_.size()));
  29. storage_.consume(bytes_written);
  30. return bytes_written;
  31. }
  32. template <typename Stream>
  33. std::size_t buffered_write_stream<Stream>::flush(asio::error_code& ec)
  34. {
  35. std::size_t bytes_written = write(next_layer_,
  36. buffer(storage_.data(), storage_.size()),
  37. transfer_all(), ec);
  38. storage_.consume(bytes_written);
  39. return bytes_written;
  40. }
  41. namespace detail
  42. {
  43. template <typename WriteHandler>
  44. class buffered_flush_handler
  45. {
  46. public:
  47. buffered_flush_handler(detail::buffered_stream_storage& storage,
  48. WriteHandler& handler)
  49. : storage_(storage),
  50. handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
  51. {
  52. }
  53. #if defined(ASIO_HAS_MOVE)
  54. buffered_flush_handler(const buffered_flush_handler& other)
  55. : storage_(other.storage_),
  56. handler_(other.handler_)
  57. {
  58. }
  59. buffered_flush_handler(buffered_flush_handler&& other)
  60. : storage_(other.storage_),
  61. handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
  62. {
  63. }
  64. #endif // defined(ASIO_HAS_MOVE)
  65. void operator()(const asio::error_code& ec,
  66. const std::size_t bytes_written)
  67. {
  68. storage_.consume(bytes_written);
  69. handler_(ec, bytes_written);
  70. }
  71. //private:
  72. detail::buffered_stream_storage& storage_;
  73. WriteHandler handler_;
  74. };
  75. template <typename WriteHandler>
  76. inline void* asio_handler_allocate(std::size_t size,
  77. buffered_flush_handler<WriteHandler>* this_handler)
  78. {
  79. return asio_handler_alloc_helpers::allocate(
  80. size, this_handler->handler_);
  81. }
  82. template <typename WriteHandler>
  83. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  84. buffered_flush_handler<WriteHandler>* this_handler)
  85. {
  86. asio_handler_alloc_helpers::deallocate(
  87. pointer, size, this_handler->handler_);
  88. }
  89. template <typename WriteHandler>
  90. inline bool asio_handler_is_continuation(
  91. buffered_flush_handler<WriteHandler>* this_handler)
  92. {
  93. return asio_handler_cont_helpers::is_continuation(
  94. this_handler->handler_);
  95. }
  96. template <typename Function, typename WriteHandler>
  97. inline void asio_handler_invoke(Function& function,
  98. buffered_flush_handler<WriteHandler>* this_handler)
  99. {
  100. asio_handler_invoke_helpers::invoke(
  101. function, this_handler->handler_);
  102. }
  103. template <typename Function, typename WriteHandler>
  104. inline void asio_handler_invoke(const Function& function,
  105. buffered_flush_handler<WriteHandler>* this_handler)
  106. {
  107. asio_handler_invoke_helpers::invoke(
  108. function, this_handler->handler_);
  109. }
  110. struct initiate_async_buffered_flush
  111. {
  112. template <typename WriteHandler, typename Stream>
  113. void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
  114. buffered_stream_storage* storage, Stream* next_layer) const
  115. {
  116. // If you get an error on the following line it means that your handler
  117. // does not meet the documented type requirements for a WriteHandler.
  118. ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  119. non_const_lvalue<WriteHandler> handler2(handler);
  120. async_write(*next_layer, buffer(storage->data(), storage->size()),
  121. buffered_flush_handler<typename decay<WriteHandler>::type>(
  122. *storage, handler2.value));
  123. }
  124. };
  125. } // namespace detail
  126. #if !defined(GENERATING_DOCUMENTATION)
  127. template <typename WriteHandler, typename Allocator>
  128. struct associated_allocator<
  129. detail::buffered_flush_handler<WriteHandler>, Allocator>
  130. {
  131. typedef typename associated_allocator<WriteHandler, Allocator>::type type;
  132. static type get(const detail::buffered_flush_handler<WriteHandler>& h,
  133. const Allocator& a = Allocator()) ASIO_NOEXCEPT
  134. {
  135. return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
  136. }
  137. };
  138. template <typename WriteHandler, typename Executor>
  139. struct associated_executor<
  140. detail::buffered_flush_handler<WriteHandler>, Executor>
  141. {
  142. typedef typename associated_executor<WriteHandler, Executor>::type type;
  143. static type get(const detail::buffered_flush_handler<WriteHandler>& h,
  144. const Executor& ex = Executor()) ASIO_NOEXCEPT
  145. {
  146. return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
  147. }
  148. };
  149. #endif // !defined(GENERATING_DOCUMENTATION)
  150. template <typename Stream>
  151. template <typename WriteHandler>
  152. ASIO_INITFN_RESULT_TYPE(WriteHandler,
  153. void (asio::error_code, std::size_t))
  154. buffered_write_stream<Stream>::async_flush(
  155. ASIO_MOVE_ARG(WriteHandler) handler)
  156. {
  157. return async_initiate<WriteHandler,
  158. void (asio::error_code, std::size_t)>(
  159. detail::initiate_async_buffered_flush(),
  160. handler, &storage_, &next_layer_);
  161. }
  162. template <typename Stream>
  163. template <typename ConstBufferSequence>
  164. std::size_t buffered_write_stream<Stream>::write_some(
  165. const ConstBufferSequence& buffers)
  166. {
  167. using asio::buffer_size;
  168. if (buffer_size(buffers) == 0)
  169. return 0;
  170. if (storage_.size() == storage_.capacity())
  171. this->flush();
  172. return this->copy(buffers);
  173. }
  174. template <typename Stream>
  175. template <typename ConstBufferSequence>
  176. std::size_t buffered_write_stream<Stream>::write_some(
  177. const ConstBufferSequence& buffers, asio::error_code& ec)
  178. {
  179. ec = asio::error_code();
  180. using asio::buffer_size;
  181. if (buffer_size(buffers) == 0)
  182. return 0;
  183. if (storage_.size() == storage_.capacity() && !flush(ec))
  184. return 0;
  185. return this->copy(buffers);
  186. }
  187. namespace detail
  188. {
  189. template <typename ConstBufferSequence, typename WriteHandler>
  190. class buffered_write_some_handler
  191. {
  192. public:
  193. buffered_write_some_handler(detail::buffered_stream_storage& storage,
  194. const ConstBufferSequence& buffers, WriteHandler& handler)
  195. : storage_(storage),
  196. buffers_(buffers),
  197. handler_(ASIO_MOVE_CAST(WriteHandler)(handler))
  198. {
  199. }
  200. #if defined(ASIO_HAS_MOVE)
  201. buffered_write_some_handler(const buffered_write_some_handler& other)
  202. : storage_(other.storage_),
  203. buffers_(other.buffers_),
  204. handler_(other.handler_)
  205. {
  206. }
  207. buffered_write_some_handler(buffered_write_some_handler&& other)
  208. : storage_(other.storage_),
  209. buffers_(other.buffers_),
  210. handler_(ASIO_MOVE_CAST(WriteHandler)(other.handler_))
  211. {
  212. }
  213. #endif // defined(ASIO_HAS_MOVE)
  214. void operator()(const asio::error_code& ec, std::size_t)
  215. {
  216. if (ec)
  217. {
  218. const std::size_t length = 0;
  219. handler_(ec, length);
  220. }
  221. else
  222. {
  223. using asio::buffer_size;
  224. std::size_t orig_size = storage_.size();
  225. std::size_t space_avail = storage_.capacity() - orig_size;
  226. std::size_t bytes_avail = buffer_size(buffers_);
  227. std::size_t length = bytes_avail < space_avail
  228. ? bytes_avail : space_avail;
  229. storage_.resize(orig_size + length);
  230. const std::size_t bytes_copied = asio::buffer_copy(
  231. storage_.data() + orig_size, buffers_, length);
  232. handler_(ec, bytes_copied);
  233. }
  234. }
  235. //private:
  236. detail::buffered_stream_storage& storage_;
  237. ConstBufferSequence buffers_;
  238. WriteHandler handler_;
  239. };
  240. template <typename ConstBufferSequence, typename WriteHandler>
  241. inline void* asio_handler_allocate(std::size_t size,
  242. buffered_write_some_handler<
  243. ConstBufferSequence, WriteHandler>* this_handler)
  244. {
  245. return asio_handler_alloc_helpers::allocate(
  246. size, this_handler->handler_);
  247. }
  248. template <typename ConstBufferSequence, typename WriteHandler>
  249. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  250. buffered_write_some_handler<
  251. ConstBufferSequence, WriteHandler>* this_handler)
  252. {
  253. asio_handler_alloc_helpers::deallocate(
  254. pointer, size, this_handler->handler_);
  255. }
  256. template <typename ConstBufferSequence, typename WriteHandler>
  257. inline bool asio_handler_is_continuation(
  258. buffered_write_some_handler<
  259. ConstBufferSequence, WriteHandler>* this_handler)
  260. {
  261. return asio_handler_cont_helpers::is_continuation(
  262. this_handler->handler_);
  263. }
  264. template <typename Function, typename ConstBufferSequence,
  265. typename WriteHandler>
  266. inline void asio_handler_invoke(Function& function,
  267. buffered_write_some_handler<
  268. ConstBufferSequence, WriteHandler>* this_handler)
  269. {
  270. asio_handler_invoke_helpers::invoke(
  271. function, this_handler->handler_);
  272. }
  273. template <typename Function, typename ConstBufferSequence,
  274. typename WriteHandler>
  275. inline void asio_handler_invoke(const Function& function,
  276. buffered_write_some_handler<
  277. ConstBufferSequence, WriteHandler>* this_handler)
  278. {
  279. asio_handler_invoke_helpers::invoke(
  280. function, this_handler->handler_);
  281. }
  282. struct initiate_async_buffered_write_some
  283. {
  284. template <typename WriteHandler, typename Stream,
  285. typename ConstBufferSequence>
  286. void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
  287. buffered_stream_storage* storage, Stream* next_layer,
  288. const ConstBufferSequence& buffers) const
  289. {
  290. // If you get an error on the following line it means that your handler
  291. // does not meet the documented type requirements for a WriteHandler.
  292. ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
  293. using asio::buffer_size;
  294. non_const_lvalue<WriteHandler> handler2(handler);
  295. if (buffer_size(buffers) == 0 || storage->size() < storage->capacity())
  296. {
  297. next_layer->async_write_some(ASIO_CONST_BUFFER(0, 0),
  298. buffered_write_some_handler<ConstBufferSequence,
  299. typename decay<WriteHandler>::type>(
  300. *storage, buffers, handler2.value));
  301. }
  302. else
  303. {
  304. initiate_async_buffered_flush()(
  305. buffered_write_some_handler<ConstBufferSequence,
  306. typename decay<WriteHandler>::type>(
  307. *storage, buffers, handler2.value),
  308. storage, next_layer);
  309. }
  310. }
  311. };
  312. } // namespace detail
  313. #if !defined(GENERATING_DOCUMENTATION)
  314. template <typename ConstBufferSequence,
  315. typename WriteHandler, typename Allocator>
  316. struct associated_allocator<
  317. detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
  318. Allocator>
  319. {
  320. typedef typename associated_allocator<WriteHandler, Allocator>::type type;
  321. static type get(
  322. const detail::buffered_write_some_handler<
  323. ConstBufferSequence, WriteHandler>& h,
  324. const Allocator& a = Allocator()) ASIO_NOEXCEPT
  325. {
  326. return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a);
  327. }
  328. };
  329. template <typename ConstBufferSequence,
  330. typename WriteHandler, typename Executor>
  331. struct associated_executor<
  332. detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>,
  333. Executor>
  334. {
  335. typedef typename associated_executor<WriteHandler, Executor>::type type;
  336. static type get(
  337. const detail::buffered_write_some_handler<
  338. ConstBufferSequence, WriteHandler>& h,
  339. const Executor& ex = Executor()) ASIO_NOEXCEPT
  340. {
  341. return associated_executor<WriteHandler, Executor>::get(h.handler_, ex);
  342. }
  343. };
  344. #endif // !defined(GENERATING_DOCUMENTATION)
  345. template <typename Stream>
  346. template <typename ConstBufferSequence, typename WriteHandler>
  347. ASIO_INITFN_RESULT_TYPE(WriteHandler,
  348. void (asio::error_code, std::size_t))
  349. buffered_write_stream<Stream>::async_write_some(
  350. const ConstBufferSequence& buffers,
  351. ASIO_MOVE_ARG(WriteHandler) handler)
  352. {
  353. return async_initiate<WriteHandler,
  354. void (asio::error_code, std::size_t)>(
  355. detail::initiate_async_buffered_write_some(),
  356. handler, &storage_, &next_layer_, buffers);
  357. }
  358. template <typename Stream>
  359. template <typename ConstBufferSequence>
  360. std::size_t buffered_write_stream<Stream>::copy(
  361. const ConstBufferSequence& buffers)
  362. {
  363. using asio::buffer_size;
  364. std::size_t orig_size = storage_.size();
  365. std::size_t space_avail = storage_.capacity() - orig_size;
  366. std::size_t bytes_avail = buffer_size(buffers);
  367. std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail;
  368. storage_.resize(orig_size + length);
  369. return asio::buffer_copy(
  370. storage_.data() + orig_size, buffers, length);
  371. }
  372. } // namespace asio
  373. #include "asio/detail/pop_options.hpp"
  374. #endif // ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP