core_1_refresher.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #include "snippets.hpp"
  10. #include <boost/beast/_experimental/unit_test/suite.hpp>
  11. #include <boost/beast/_experimental/test/stream.hpp>
  12. #include <boost/beast/core/flat_buffer.hpp>
  13. #include <boost/asio/buffer.hpp>
  14. #include <boost/asio/buffers_iterator.hpp>
  15. #include <boost/asio/ip/tcp.hpp>
  16. #include <boost/asio/spawn.hpp>
  17. #include <boost/asio/use_future.hpp>
  18. #include <boost/asio/write.hpp>
  19. #include <algorithm>
  20. #include <assert.h>
  21. namespace boost {
  22. namespace beast {
  23. namespace {
  24. void
  25. snippets()
  26. {
  27. #include "snippets.ipp"
  28. {
  29. //[code_core_1_refresher_1s
  30. net::const_buffer cb("Hello, world!", 13);
  31. assert(string_view(reinterpret_cast<char const*>(
  32. cb.data()), cb.size()) == "Hello, world!");
  33. char storage[13];
  34. net::mutable_buffer mb(storage, sizeof(storage));
  35. std::memcpy(mb.data(), cb.data(), mb.size());
  36. assert(string_view(reinterpret_cast<char const*>(
  37. mb.data()), mb.size()) == "Hello, world!");
  38. //]
  39. }
  40. {
  41. //[code_core_1_refresher_2s
  42. net::const_buffer b1; // a ConstBufferSequence by definition
  43. net::mutable_buffer b2; // a MutableBufferSequence by definition
  44. std::array<net::const_buffer, 3> b3; // A ConstBufferSequence by named requirements
  45. //]
  46. }
  47. {
  48. //[code_core_1_refresher_3s
  49. // initiate an asynchronous write operation
  50. net::async_write(sock, net::const_buffer("Hello, world!", 13),
  51. [](error_code ec, std::size_t bytes_transferred)
  52. {
  53. // this lambda is invoked when the write operation completes
  54. if(! ec)
  55. assert(bytes_transferred == 13);
  56. else
  57. std::cerr << "Error: " << ec.message() << "\n";
  58. });
  59. // meanwhile, the operation is outstanding and execution continues from here
  60. //]
  61. }
  62. {
  63. //[code_core_1_refresher_4s
  64. std::future<std::size_t> f = net::async_write(sock,
  65. net::const_buffer("Hello, world!", 13), net::use_future);
  66. //]
  67. }
  68. {
  69. //[code_core_1_refresher_5s
  70. asio::spawn(
  71. [&sock](net::yield_context yield)
  72. {
  73. std::size_t bytes_transferred = net::async_write(sock,
  74. net::const_buffer("Hello, world!", 13), yield);
  75. (void)bytes_transferred;
  76. });
  77. //]
  78. }
  79. }
  80. //------------------------------------------------------------------------------
  81. //[code_core_1_refresher_1
  82. template <class ConstBufferSequence>
  83. std::string string_from_buffers (ConstBufferSequence const& buffers)
  84. {
  85. // check that the type meets the requirements using the provided type traits
  86. static_assert(
  87. net::is_const_buffer_sequence<ConstBufferSequence>::value,
  88. "ConstBufferSequence type requirements not met");
  89. // optimization: reserve all the space for the string first
  90. std::string result;
  91. result.reserve(beast::buffer_bytes(buffers)); // beast version of net::buffer_size
  92. // iterate over each buffer in the sequence and append it to the string
  93. for(auto it = net::buffer_sequence_begin(buffers); // returns an iterator to beginning of the sequence
  94. it != net::buffer_sequence_end(buffers);) // returns a past-the-end iterator to the sequence
  95. {
  96. // A buffer sequence iterator's value_type is always convertible to net::const_buffer
  97. net::const_buffer buffer = *it++;
  98. // A cast is always required to out-out of type-safety
  99. result.append(static_cast<char const*>(buffer.data()), buffer.size());
  100. }
  101. return result;
  102. }
  103. //]
  104. //------------------------------------------------------------------------------
  105. //[code_core_1_refresher_2
  106. // Read a line ending in '\n' from a socket, returning
  107. // the number of characters up to but not including the newline
  108. template <class DynamicBuffer>
  109. std::size_t read_line(net::ip::tcp::socket& sock, DynamicBuffer& buffer)
  110. {
  111. // this alias keeps things readable
  112. using range = net::buffers_iterator<
  113. typename DynamicBuffer::const_buffers_type>;
  114. for(;;)
  115. {
  116. // get iterators representing the range of characters in the buffer
  117. auto begin = range::begin(buffer.data());
  118. auto end = range::end(buffer.data());
  119. // search for "\n" and return if found
  120. auto pos = std::find(begin, end, '\n');
  121. if(pos != range::end(buffer.data()))
  122. return std::distance(begin, end);
  123. // Determine the number of bytes to read,
  124. // using available capacity in the buffer first.
  125. std::size_t bytes_to_read = std::min<std::size_t>(
  126. std::max<std::size_t>(512, // under 512 is too little,
  127. buffer.capacity() - buffer.size()),
  128. std::min<std::size_t>(65536, // and over 65536 is too much.
  129. buffer.max_size() - buffer.size()));
  130. // Read up to bytes_to_read bytes into the dynamic buffer
  131. buffer.commit(sock.read_some(buffer.prepare(bytes_to_read)));
  132. }
  133. }
  134. //]
  135. //------------------------------------------------------------------------------
  136. //[code_core_1_refresher_3
  137. // Meets the requirements of SyncReadStream
  138. struct sync_read_stream
  139. {
  140. // Returns the number of bytes read upon success, otherwise throws an exception
  141. template <class MutableBufferSequence>
  142. std::size_t read_some(MutableBufferSequence const& buffers);
  143. // Returns the number of bytes read successfully, sets the error code if a failure occurs
  144. template <class MutableBufferSequence>
  145. std::size_t read_some(MutableBufferSequence const& buffers, error_code& ec);
  146. };
  147. // Meets the requirements of SyncWriteStream
  148. struct sync_write_stream
  149. {
  150. // Returns the number of bytes written upon success, otherwise throws an exception
  151. template <class ConstBufferSequence>
  152. std::size_t write_some(ConstBufferSequence const& buffers);
  153. // Returns the number of bytes written successfully, sets the error code if a failure occurs
  154. template <class ConstBufferSequence>
  155. std::size_t write_some(ConstBufferSequence const& buffers, error_code& ec);
  156. };
  157. //]
  158. template<class MutableBufferSequence>
  159. std::size_t sync_read_stream::read_some(MutableBufferSequence const&)
  160. {
  161. return 0;
  162. }
  163. template<class MutableBufferSequence>
  164. std::size_t sync_read_stream::read_some(MutableBufferSequence const&, error_code&)
  165. {
  166. return 0;
  167. }
  168. template<class ConstBufferSequence>
  169. std::size_t sync_write_stream::write_some(ConstBufferSequence const&)
  170. {
  171. return 0;
  172. }
  173. template<class ConstBufferSequence>
  174. std::size_t sync_write_stream::write_some(ConstBufferSequence const&, error_code&)
  175. {
  176. return 0;
  177. }
  178. BOOST_STATIC_ASSERT(is_sync_read_stream<sync_read_stream>::value);
  179. BOOST_STATIC_ASSERT(is_sync_write_stream<sync_write_stream>::value);
  180. //------------------------------------------------------------------------------
  181. //[code_core_1_refresher_4
  182. template <class SyncWriteStream>
  183. void hello (SyncWriteStream& stream)
  184. {
  185. net::const_buffer cb("Hello, world!", 13);
  186. do
  187. {
  188. auto bytes_transferred = stream.write_some(cb); // may throw
  189. cb += bytes_transferred; // adjust the pointer and size
  190. }
  191. while (cb.size() > 0);
  192. }
  193. //]
  194. //------------------------------------------------------------------------------
  195. //[code_core_1_refresher_5
  196. template <class SyncWriteStream>
  197. void hello (SyncWriteStream& stream, error_code& ec)
  198. {
  199. net::const_buffer cb("Hello, world!", 13);
  200. do
  201. {
  202. auto bytes_transferred = stream.write_some(cb, ec);
  203. cb += bytes_transferred; // adjust the pointer and size
  204. }
  205. while (cb.size() > 0 && ! ec);
  206. }
  207. //]
  208. //------------------------------------------------------------------------------
  209. } // (anon)
  210. } // beast
  211. } // boost
  212. //[code_core_1_refresher_6
  213. // The following is a completion handler expressed
  214. // as a function object, with a nested associated
  215. // allocator and a nested associated executor.
  216. struct handler
  217. {
  218. using allocator_type = std::allocator<char>;
  219. allocator_type get_allocator() const noexcept;
  220. using executor_type = boost::asio::io_context::executor_type;
  221. executor_type get_executor() const noexcept;
  222. void operator()(boost::beast::error_code, std::size_t);
  223. };
  224. //]
  225. inline auto handler::get_allocator() const noexcept ->
  226. allocator_type
  227. {
  228. return {};
  229. }
  230. inline auto handler::get_executor() const noexcept ->
  231. executor_type
  232. {
  233. static boost::asio::io_context ioc;
  234. return ioc.get_executor();
  235. }
  236. inline void handler::operator()(
  237. boost::beast::error_code, std::size_t)
  238. {
  239. }
  240. //[code_core_1_refresher_7
  241. namespace boost {
  242. namespace asio {
  243. template<class Allocator>
  244. struct associated_allocator<handler, Allocator>
  245. {
  246. using type = std::allocator<void>;
  247. static
  248. type
  249. get(handler const& h,
  250. Allocator const& alloc = Allocator{}) noexcept;
  251. };
  252. template<class Executor>
  253. struct associated_executor<handler, Executor>
  254. {
  255. using type = boost::asio::executor;
  256. static
  257. type
  258. get(handler const& h,
  259. Executor const& ex = Executor{}) noexcept;
  260. };
  261. } // boost
  262. } // asio
  263. //]
  264. template<class Allocator>
  265. auto
  266. boost::asio::associated_allocator<handler, Allocator>::
  267. get(handler const&, Allocator const&) noexcept -> type
  268. {
  269. return {};
  270. }
  271. template<class Executor>
  272. auto
  273. boost::asio::associated_executor<handler, Executor>::
  274. get(handler const&, Executor const&) noexcept -> type
  275. {
  276. return {};
  277. }
  278. //------------------------------------------------------------------------------
  279. namespace boost {
  280. namespace beast {
  281. namespace {
  282. //------------------------------------------------------------------------------
  283. //[code_core_1_refresher_8
  284. template <class AsyncWriteStream, class WriteHandler>
  285. void async_hello (AsyncWriteStream& stream, WriteHandler&& handler)
  286. {
  287. net::async_write (stream,
  288. net::buffer("Hello, world!", 13),
  289. std::forward<WriteHandler>(handler));
  290. }
  291. //]
  292. //------------------------------------------------------------------------------
  293. //[code_core_1_refresher_9
  294. template<
  295. class AsyncWriteStream,
  296. class ConstBufferSequence,
  297. class CompletionToken>
  298. auto
  299. async_write(
  300. AsyncWriteStream* stream, // references are passed as pointers
  301. ConstBufferSequence const& buffers,
  302. CompletionToken&& token) // a handler, or a special object.
  303. ->
  304. typename net::async_result< // return-type customization point.
  305. typename std::decay<CompletionToken>::type, // type used to specialize async_result.
  306. void(error_code, std::size_t) // underlying completion handler signature.
  307. >::return_type;
  308. //]
  309. struct run_async_write
  310. {
  311. template<class... Args>
  312. void
  313. operator()(Args&&...)
  314. {
  315. }
  316. };
  317. template<
  318. class AsyncWriteStream,
  319. class ConstBufferSequence,
  320. class CompletionToken>
  321. auto
  322. async_write(
  323. AsyncWriteStream& stream,
  324. ConstBufferSequence const& buffers,
  325. CompletionToken&& token) ->
  326. typename net::async_result<
  327. typename std::decay<CompletionToken>::type,
  328. void(error_code, std::size_t)
  329. >::return_type
  330. {
  331. //[code_core_1_refresher_10
  332. return net::async_initiate<
  333. CompletionToken,
  334. void(error_code, std::size_t)>(
  335. run_async_write{}, // The "initiation" object.
  336. token, // Token must come before other arguments.
  337. &stream, // Additional captured arguments are
  338. buffers); // forwarded to the initiation object.
  339. //]
  340. }
  341. //------------------------------------------------------------------------------
  342. } // (anon)
  343. struct core_1_refresher_test
  344. : public beast::unit_test::suite
  345. {
  346. void
  347. run() override
  348. {
  349. BEAST_EXPECT(&snippets);
  350. BEAST_EXPECT((static_cast<
  351. std::string(*)(net::const_buffer const&)>(
  352. &string_from_buffers<net::const_buffer>)));
  353. BEAST_EXPECT(static_cast<
  354. std::size_t(*)(net::ip::tcp::socket&, flat_buffer&)>(
  355. &read_line<flat_buffer>));
  356. BEAST_EXPECT(static_cast<
  357. std::size_t(sync_read_stream::*)(
  358. net::mutable_buffer const&)>(
  359. &sync_read_stream::read_some));
  360. BEAST_EXPECT(static_cast<
  361. std::size_t(sync_read_stream::*)(
  362. net::mutable_buffer const&, error_code&)>(
  363. &sync_read_stream::read_some));
  364. BEAST_EXPECT(static_cast<
  365. std::size_t(sync_write_stream::*)(
  366. net::const_buffer const&)>(
  367. &sync_write_stream::write_some));
  368. BEAST_EXPECT(static_cast<
  369. std::size_t(sync_write_stream::*)(
  370. net::const_buffer const&, error_code&)>(
  371. &sync_write_stream::write_some));
  372. BEAST_EXPECT(static_cast<
  373. void(*)(test::stream&)>(
  374. &hello<test::stream>));
  375. BEAST_EXPECT(static_cast<
  376. void(*)(test::stream&, error_code&)>(
  377. &hello<test::stream>));
  378. handler h;
  379. h.get_allocator();
  380. h.get_executor();
  381. BEAST_EXPECT((&async_hello<test::stream, handler>));
  382. }
  383. };
  384. BEAST_DEFINE_TESTSUITE(beast,doc,core_1_refresher);
  385. } // beast
  386. } // boost