• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
4<title>Echo ��</title>
5<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css">
6<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
7<link rel="home" href="../../../index.html" title="Chapter 1. Boost.Beast">
8<link rel="up" href="../writing_composed_operations.html" title="Writing Composed Operations">
9<link rel="prev" href="../writing_composed_operations.html" title="Writing Composed Operations">
10<link rel="next" href="detect_ssl.html" title="Detect SSL ��">
11</head>
12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
13<table cellpadding="2" width="100%"><tr>
14<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td>
15<td align="center"><a href="../../../../../../../index.html">Home</a></td>
16<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td>
17<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
18<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
19<td align="center"><a href="../../../../../../../more/index.htm">More</a></td>
20</tr></table>
21<hr>
22<div class="spirit-nav">
23<a accesskey="p" href="../writing_composed_operations.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../writing_composed_operations.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="detect_ssl.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
24</div>
25<div class="section">
26<div class="titlepage"><div><div><h4 class="title">
27<a name="beast.using_io.writing_composed_operations.echo"></a><a class="link" href="echo.html" title="Echo ��">Echo
28        ��</a>
29</h4></div></div></div>
30<p>
31          This example develops an initiating function called <span class="bold"><strong>echo</strong></span>.
32          The operation will read up to the first newline on a stream, and then write
33          the same line including the newline back on the stream. First we define
34          the input parameters and results, then declare our initiation function.
35          For our echo operation the only inputs are the stream and the completion
36          token. The output is the error code which is usually included in all completion
37          handler signatures.
38        </p>
39<pre class="programlisting"><span class="comment">/** Asynchronously read a line and echo it back.
40
41    This function is used to asynchronously read a line ending
42    in a newline (`"\n"`) from the stream, and then write
43    it back.
44
45    This call always returns immediately. The asynchronous operation
46    will continue until one of the following conditions is true:
47
48    @li A line was read in and written back on the stream
49
50    @li An error occurs.
51
52    The algorithm, known as a &lt;em&gt;composed asynchronous operation&lt;/em&gt;,
53    is implemented in terms of calls to the stream's `async_read_some`
54    and `async_write_some` function. The program must ensure that no
55    other reads or writes are performed until this operation completes.
56
57    Since the length of the line is not known ahead of time, the
58    implementation may read additional characters that lie past the
59    first line. These characters are stored in the dynamic buffer_.
60    The same dynamic buffer must be presented again in each call,
61    to provide the implementation with any leftover bytes.
62
63    @param stream The stream to operate on. The type must meet the
64    requirements of &lt;em&gt;AsyncReadStream&lt;/em&gt; and @AsyncWriteStream
65
66    @param buffer A dynamic buffer to hold implementation-defined
67    temporary data. Ownership is not transferred; the caller is
68    responsible for ensuring that the lifetime of this object is
69    extended least until the completion handler is invoked.
70
71    @param token The handler to be called when the operation completes.
72    The implementation takes ownership of the handler by performing a decay-copy.
73    The handler must be invocable with this signature:
74    @code
75    void handler(
76        beast::error_code error      // Result of operation.
77    );
78    @endcode
79
80    Regardless of whether the asynchronous operation completes immediately or
81    not, the handler will not be invoked from within this function. Invocation
82    of the handler will be performed in a manner equivalent to using
83    `net::post`.
84*/</span>
85<span class="keyword">template</span><span class="special">&lt;</span>
86    <span class="keyword">class</span> <span class="identifier">AsyncStream</span><span class="special">,</span>
87    <span class="keyword">class</span> <span class="identifier">DynamicBuffer</span><span class="special">,</span>
88    <span class="keyword">class</span> <span class="identifier">CompletionToken</span><span class="special">&gt;</span>
89<span class="keyword">auto</span>
90<span class="identifier">async_echo</span> <span class="special">(</span>
91    <span class="identifier">AsyncStream</span><span class="special">&amp;</span> <span class="identifier">stream</span><span class="special">,</span>
92    <span class="identifier">DynamicBuffer</span><span class="special">&amp;</span> <span class="identifier">buffer</span><span class="special">,</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c0" href="echo.html#beast.using_io.writing_composed_operations.echo.c1"><img src="../../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a>
93    <span class="identifier">CompletionToken</span><span class="special">&amp;&amp;</span> <span class="identifier">token</span><span class="special">)</span> <span class="special">-&gt;</span>
94        <span class="keyword">typename</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_result</span><span class="special">&lt;</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c2" href="echo.html#beast.using_io.writing_composed_operations.echo.c3"><img src="../../../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a>
95            <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">decay</span><span class="special">&lt;</span><span class="identifier">CompletionToken</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">,</span>
96            <span class="keyword">void</span><span class="special">(</span><span class="identifier">beast</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">)</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c4" href="echo.html#beast.using_io.writing_composed_operations.echo.c5"><img src="../../../../../../../doc/src/images/callouts/3.png" alt="3" border="0"></a>
97                <span class="special">&gt;::</span><span class="identifier">return_type</span><span class="special">;</span>
98</pre>
99<div class="calloutlist"><table border="0" summary="Callout list">
100<tr>
101<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c1"></a><a href="#beast.using_io.writing_composed_operations.echo.c0"><img src="../../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> </p></td>
102<td valign="top" align="left"><p>
103              Unlike Asio, we pass by non-const reference instead of rvalue-ref
104            </p></td>
105</tr>
106<tr>
107<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c3"></a><a href="#beast.using_io.writing_composed_operations.echo.c2"><img src="../../../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a> </p></td>
108<td valign="top" align="left"><p>
109              <code class="computeroutput"><span class="identifier">async_result</span></code> deduces
110              the return type from the completion handler
111            </p></td>
112</tr>
113<tr>
114<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c5"></a><a href="#beast.using_io.writing_composed_operations.echo.c4"><img src="../../../../../../../doc/src/images/callouts/3.png" alt="3" border="0"></a> </p></td>
115<td valign="top" align="left"><p>
116              The completion handler signature goes here
117            </p></td>
118</tr>
119</table></div>
120<p>
121          Now that we have a declaration, we will define the body of the function.
122          We want to achieve the following goals: perform static type checking on
123          the input parameters, set up the return value as per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3747.pdf" target="_top"><span class="bold"><strong>N3747</strong></span></a>, and launch the composed operation
124          by constructing an intermediate, stateful completion handler and invoking
125          it.
126        </p>
127<p>
128          The initiating function contains a few relatively simple parts. There is
129          the customization of the return value type, static type checking, building
130          the return value type using the helper, and creating and launching the
131          <code class="computeroutput"><span class="identifier">echo_op</span></code> composed operation
132          object.
133        </p>
134<p>
135          The implementation strategy is to make the composed object meet the requirements
136          of a completion handler by being movable, and by making it invocable so
137          it can be used as a continuation for the asynchronous operations it launches.
138          Rather than using <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">bind</span></code> or <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bind</span></code>,
139          which destroys the type information and therefore breaks the allocation
140          and invocation hooks, we will simply pass <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(*</span><span class="keyword">this</span><span class="special">)</span></code>
141          as the completion handler parameter for any operations that we initiate.
142          For the move to work correctly, care must be taken to ensure that no access
143          to data members are made after the move takes place. Here is the complete
144          implementation of our composed operation:
145        </p>
146<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">AsyncStream</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Handler</span><span class="special">&gt;</span>
147<span class="keyword">class</span> <span class="identifier">echo_op</span><span class="special">;</span>
148
149<span class="comment">// This example uses the Asio's stackless "fauxroutines", implemented</span>
150<span class="comment">// using a macro-based solution. It makes the code easier to write and</span>
151<span class="comment">// easier to read. This include file defines the necessary macros and types.</span>
152<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">asio</span><span class="special">/</span><span class="identifier">yield</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
153
154<span class="comment">// Read a line and echo it back</span>
155<span class="comment">//</span>
156<span class="keyword">template</span><span class="special">&lt;</span>
157    <span class="keyword">class</span> <span class="identifier">AsyncStream</span><span class="special">,</span>
158    <span class="keyword">class</span> <span class="identifier">DynamicBuffer</span><span class="special">,</span>
159    <span class="keyword">class</span> <span class="identifier">CompletionToken</span><span class="special">&gt;</span>
160<span class="keyword">auto</span>
161<span class="identifier">async_echo</span><span class="special">(</span>
162    <span class="identifier">AsyncStream</span><span class="special">&amp;</span> <span class="identifier">stream</span><span class="special">,</span>
163    <span class="identifier">DynamicBuffer</span><span class="special">&amp;</span> <span class="identifier">buffer</span><span class="special">,</span>
164    <span class="identifier">CompletionToken</span><span class="special">&amp;&amp;</span> <span class="identifier">token</span><span class="special">)</span> <span class="special">-&gt;</span>
165        <span class="keyword">typename</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_result</span><span class="special">&lt;</span>
166            <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">decay</span><span class="special">&lt;</span><span class="identifier">CompletionToken</span><span class="special">&gt;::</span><span class="identifier">type</span><span class="special">,</span>
167            <span class="keyword">void</span><span class="special">(</span><span class="identifier">beast</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">)&gt;::</span><span class="identifier">return_type</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c6" href="echo.html#beast.using_io.writing_composed_operations.echo.c7"><img src="../../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a>
168<span class="special">{</span>
169    <span class="comment">// Perform some type checks using static assert, this helps</span>
170    <span class="comment">// with more friendly error messages when passing the wrong types.</span>
171    <span class="keyword">static_assert</span><span class="special">(</span>
172        <span class="identifier">beast</span><span class="special">::</span><span class="identifier">is_async_stream</span><span class="special">&lt;</span><span class="identifier">AsyncStream</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span>
173        <span class="string">"AsyncStream type requirements not met"</span><span class="special">);</span>
174    <span class="keyword">static_assert</span><span class="special">(</span>
175        <span class="identifier">net</span><span class="special">::</span><span class="identifier">is_dynamic_buffer</span><span class="special">&lt;</span><span class="identifier">DynamicBuffer</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span>
176        <span class="string">"DynamicBuffer type requirements not met"</span><span class="special">);</span>
177
178    <span class="comment">// This class template deduces the actual handler type from a</span>
179    <span class="comment">// CompletionToken, captures a local reference to the handler,</span>
180    <span class="comment">// and creates the `async_result` object which becomes the</span>
181    <span class="comment">// return value of this initiating function.</span>
182
183    <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_completion</span><span class="special">&lt;</span><span class="identifier">CompletionToken</span><span class="special">,</span> <span class="keyword">void</span><span class="special">(</span><span class="identifier">beast</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">)&gt;</span> <span class="identifier">init</span><span class="special">(</span><span class="identifier">token</span><span class="special">);</span>
184
185    <span class="comment">// The helper macro BOOST_ASIO_HANDLER_TYPE converts the completion</span>
186    <span class="comment">// token type into a concrete handler type of the correct signature.</span>
187
188    <span class="keyword">using</span> <span class="identifier">handler_type</span> <span class="special">=</span> <span class="identifier">BOOST_ASIO_HANDLER_TYPE</span><span class="special">(</span><span class="identifier">CompletionToken</span><span class="special">,</span> <span class="keyword">void</span><span class="special">(</span><span class="identifier">beast</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">));</span>
189
190    <span class="comment">// The class template `async_base` holds the caller's completion</span>
191    <span class="comment">// handler for us, and provides all of the boilerplate for forwarding</span>
192    <span class="comment">// the associated allocator and associated executor from the caller's</span>
193    <span class="comment">// handler to our operation. It also maintains a `net::executor_work_guard`</span>
194    <span class="comment">// for the executor associated with the stream. This work guard is</span>
195    <span class="comment">// inexpensive, and prevents the execution context from running out</span>
196    <span class="comment">// of work. It is usually necessary although rarely it can be skipped</span>
197    <span class="comment">// depending on the operation (this echo example needs it because it</span>
198    <span class="comment">// performs more than one asynchronous operation in a row).</span>
199    <span class="comment">// We declare this type alias to make the code easier to read.</span>
200
201    <span class="keyword">using</span> <span class="identifier">base_type</span> <span class="special">=</span> <span class="identifier">beast</span><span class="special">::</span><span class="identifier">async_base</span><span class="special">&lt;</span>
202        <span class="identifier">handler_type</span><span class="special">,</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c8" href="echo.html#beast.using_io.writing_composed_operations.echo.c9"><img src="../../../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a>
203        <span class="identifier">beast</span><span class="special">::</span><span class="identifier">executor_type</span><span class="special">&lt;</span><span class="identifier">AsyncStream</span><span class="special">&gt;</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c10" href="echo.html#beast.using_io.writing_composed_operations.echo.c11"><img src="../../../../../../../doc/src/images/callouts/3.png" alt="3" border="0"></a>
204    <span class="special">&gt;;</span>
205
206    <span class="comment">// This nested class implements the echo composed operation as a</span>
207    <span class="comment">// stateful completion handler. We derive from `async_base` to</span>
208    <span class="comment">// take care of boilerplate and we derived from asio::coroutine to</span>
209    <span class="comment">// allow the reenter and yield keywords to work.</span>
210
211    <span class="keyword">struct</span> <span class="identifier">echo_op</span> <span class="special">:</span> <span class="identifier">base_type</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">coroutine</span>
212    <span class="special">{</span>
213        <span class="identifier">AsyncStream</span><span class="special">&amp;</span> <span class="identifier">stream_</span><span class="special">;</span>
214        <span class="identifier">DynamicBuffer</span><span class="special">&amp;</span> <span class="identifier">buffer_</span><span class="special">;</span>
215
216        <span class="identifier">echo_op</span><span class="special">(</span>
217            <span class="identifier">AsyncStream</span><span class="special">&amp;</span> <span class="identifier">stream</span><span class="special">,</span>
218            <span class="identifier">DynamicBuffer</span><span class="special">&amp;</span> <span class="identifier">buffer</span><span class="special">,</span>
219            <span class="identifier">handler_type</span><span class="special">&amp;&amp;</span> <span class="identifier">handler</span><span class="special">)</span>
220            <span class="special">:</span> <span class="identifier">base_type</span><span class="special">(</span>
221                <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">handler</span><span class="special">),</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c12" href="echo.html#beast.using_io.writing_composed_operations.echo.c13"><img src="../../../../../../../doc/src/images/callouts/4.png" alt="4" border="0"></a>
222                <span class="identifier">stream</span><span class="special">.</span><span class="identifier">get_executor</span><span class="special">())</span> <a class="co" name="beast.using_io.writing_composed_operations.echo.c14" href="echo.html#beast.using_io.writing_composed_operations.echo.c15"><img src="../../../../../../../doc/src/images/callouts/5.png" alt="5" border="0"></a>
223            <span class="special">,</span> <span class="identifier">stream_</span><span class="special">(</span><span class="identifier">stream</span><span class="special">)</span>
224            <span class="special">,</span> <span class="identifier">buffer_</span><span class="special">(</span><span class="identifier">buffer</span><span class="special">)</span>
225        <span class="special">{</span>
226            <span class="comment">// Launch the operation directly from the constructor. We</span>
227            <span class="comment">// pass `false` for `cont` to indicate that the calling</span>
228            <span class="comment">// thread does not represent a continuation of our</span>
229            <span class="comment">// asynchronous control flow.</span>
230            <span class="special">(*</span><span class="keyword">this</span><span class="special">)({},</span> <span class="number">0</span><span class="special">,</span> <span class="keyword">false</span><span class="special">);</span>
231        <span class="special">}</span>
232
233        <span class="comment">// If a newline is present in the buffer sequence, this function returns</span>
234        <span class="comment">// the number of characters from the beginning of the buffer up to the</span>
235        <span class="comment">// newline, including the newline character. Otherwise it returns zero.</span>
236
237        <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
238        <span class="identifier">find_newline</span><span class="special">(</span><span class="keyword">typename</span> <span class="identifier">DynamicBuffer</span><span class="special">::</span><span class="identifier">const_buffers_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">buffers</span><span class="special">)</span>
239        <span class="special">{</span>
240            <span class="comment">// The `buffers_iterator` class template provides random-access</span>
241            <span class="comment">// iterators into a buffer sequence. Use the standard algorithm</span>
242            <span class="comment">// to look for the new line if it exists.</span>
243
244            <span class="keyword">auto</span> <span class="identifier">begin</span> <span class="special">=</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">buffers_iterator</span><span class="special">&lt;</span>
245                <span class="keyword">typename</span> <span class="identifier">DynamicBuffer</span><span class="special">::</span><span class="identifier">const_buffers_type</span><span class="special">&gt;::</span><span class="identifier">begin</span><span class="special">(</span><span class="identifier">buffers</span><span class="special">);</span>
246            <span class="keyword">auto</span> <span class="identifier">end</span> <span class="special">=</span>   <span class="identifier">net</span><span class="special">::</span><span class="identifier">buffers_iterator</span><span class="special">&lt;</span>
247                <span class="keyword">typename</span> <span class="identifier">DynamicBuffer</span><span class="special">::</span><span class="identifier">const_buffers_type</span><span class="special">&gt;::</span><span class="identifier">end</span><span class="special">(</span><span class="identifier">buffers</span><span class="special">);</span>
248            <span class="keyword">auto</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">find</span><span class="special">(</span><span class="identifier">begin</span><span class="special">,</span> <span class="identifier">end</span><span class="special">,</span> <span class="char">'\n'</span><span class="special">);</span>
249
250            <span class="keyword">if</span><span class="special">(</span><span class="identifier">result</span> <span class="special">==</span> <span class="identifier">end</span><span class="special">)</span>
251                <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> <span class="comment">// not found</span>
252
253            <span class="keyword">return</span> <span class="identifier">result</span> <span class="special">+</span> <span class="number">1</span> <span class="special">-</span> <span class="identifier">begin</span><span class="special">;</span>
254        <span class="special">}</span>
255
256        <span class="comment">// This is the entry point of our completion handler. Every time an</span>
257        <span class="comment">// asynchronous operation completes, this function will be invoked.</span>
258
259        <span class="keyword">void</span>
260        <span class="keyword">operator</span><span class="special">()(</span>
261            <span class="identifier">beast</span><span class="special">::</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span>
262            <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">bytes_transferred</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span>
263            <span class="keyword">bool</span> <span class="identifier">cont</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">)</span> <span class="comment">/*&lt; Second and subsequent invocations will seee `cont=true`. */</span>
264        <span class="special">{</span>
265            <span class="comment">// The `reenter` keyword transfers control to the last</span>
266            <span class="comment">// yield point, or to the beginning of the scope if</span>
267            <span class="comment">// this is the first time.</span>
268
269            <span class="identifier">reenter</span><span class="special">(*</span><span class="keyword">this</span><span class="special">)</span>
270            <span class="special">{</span>
271                <span class="keyword">for</span><span class="special">(;;)</span>
272                <span class="special">{</span>
273                    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">pos</span><span class="special">;</span>
274
275                    <span class="comment">// Search for a newline in the readable bytes of the buffer</span>
276                    <span class="identifier">pos</span> <span class="special">=</span> <span class="identifier">find_newline</span><span class="special">(</span><span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">data</span><span class="special">());</span>
277
278                    <span class="comment">// If we don't have the newline, then read more</span>
279                    <span class="keyword">if</span><span class="special">(</span><span class="identifier">pos</span> <span class="special">==</span> <span class="number">0</span><span class="special">)</span>
280                    <span class="special">{</span>
281                        <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">bytes_to_read</span><span class="special">;</span>
282
283                        <span class="comment">// Determine the number of bytes to read,</span>
284                        <span class="comment">// using available capacity in the buffer first.</span>
285
286                        <span class="identifier">bytes_to_read</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">min</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">&gt;(</span>
287                              <span class="identifier">std</span><span class="special">::</span><span class="identifier">max</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">&gt;(</span><span class="number">512</span><span class="special">,</span>                <span class="comment">// under 512 is too little,</span>
288                                  <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">capacity</span><span class="special">()</span> <span class="special">-</span> <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">size</span><span class="special">()),</span>
289                              <span class="identifier">std</span><span class="special">::</span><span class="identifier">min</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">&gt;(</span><span class="number">65536</span><span class="special">,</span>              <span class="comment">// and over 65536 is too much.</span>
290                                  <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">max_size</span><span class="special">()</span> <span class="special">-</span> <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">size</span><span class="special">()));</span>
291
292                        <span class="comment">// Read some data into our dynamic buffer_. We transfer</span>
293                        <span class="comment">// ownership of the composed operation by using the</span>
294                        <span class="comment">// `std::move(*this)` idiom. The `yield` keyword causes</span>
295                        <span class="comment">// the function to return immediately after the initiating</span>
296                        <span class="comment">// function returns.</span>
297
298                        <span class="identifier">yield</span> <span class="identifier">stream_</span><span class="special">.</span><span class="identifier">async_read_some</span><span class="special">(</span>
299                            <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">prepare</span><span class="special">(</span><span class="identifier">bytes_to_read</span><span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(*</span><span class="keyword">this</span><span class="special">));</span>
300
301                        <span class="comment">// After the `async_read_some` completes, control is</span>
302                        <span class="comment">// transferred to this line by the `reenter` keyword.</span>
303
304                        <span class="comment">// Move the bytes read from the writable area to the</span>
305                        <span class="comment">// readable area.</span>
306
307                        <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">commit</span><span class="special">(</span><span class="identifier">bytes_transferred</span><span class="special">);</span>
308
309                        <span class="comment">// If an error occurs, deliver it to the caller's completion handler.</span>
310                        <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
311                            <span class="keyword">break</span><span class="special">;</span>
312
313                        <span class="comment">// Keep looping until we get the newline</span>
314                        <span class="keyword">continue</span><span class="special">;</span>
315                    <span class="special">}</span>
316
317                    <span class="comment">// We have our newline, so send the first `pos` bytes of the</span>
318                    <span class="comment">// buffers. The function `buffers_prefix` returns the front part</span>
319                    <span class="comment">// of the buffers we want.</span>
320
321                    <span class="identifier">yield</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span><span class="identifier">stream_</span><span class="special">,</span>
322                        <span class="identifier">beast</span><span class="special">::</span><span class="identifier">buffers_prefix</span><span class="special">(</span><span class="identifier">pos</span><span class="special">,</span> <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">data</span><span class="special">()),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(*</span><span class="keyword">this</span><span class="special">));</span>
323
324                    <span class="comment">// After the `async_write` completes, our completion handler will</span>
325                    <span class="comment">// be invoked with the error and the number of bytes transferred,</span>
326                    <span class="comment">// and the `reenter` statement above will cause control to jump</span>
327                    <span class="comment">// to the following line. The variable `pos` is no longer valid</span>
328                    <span class="comment">// (remember that we returned from the function using `yield` above)</span>
329                    <span class="comment">// but we can use `bytes_transferred` to know how much of the buffer</span>
330                    <span class="comment">// to consume. With "real" coroutines this will be easier and more</span>
331                    <span class="comment">// natural.</span>
332
333                    <span class="identifier">buffer_</span><span class="special">.</span><span class="identifier">consume</span><span class="special">(</span><span class="identifier">bytes_transferred</span><span class="special">);</span>
334
335                    <span class="comment">// The loop terminates here, and we will either deliver a</span>
336                    <span class="comment">// successful result or an error to the caller's completion handler.</span>
337
338                    <span class="keyword">break</span><span class="special">;</span>
339                <span class="special">}</span>
340
341                <span class="comment">// When a composed operation completes immediately, it must not</span>
342                <span class="comment">// directly invoke the completion handler otherwise it could</span>
343                <span class="comment">// lead to unfairness, starvation, or stack overflow. Therefore,</span>
344                <span class="comment">// if cont == false (meaning, that the call stack still includes</span>
345                <span class="comment">// the frame of the initiating function) then we need to use</span>
346                <span class="comment">// `net::post` to cause us to be called again after the initiating</span>
347                <span class="comment">// function. The function `async_base::invoke` takes care of</span>
348                <span class="comment">// calling the final completion handler, using post if the</span>
349                <span class="comment">// first argument is false, otherwise invoking it directly.</span>
350
351                <span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">complete</span><span class="special">(</span><span class="identifier">cont</span><span class="special">,</span> <span class="identifier">ec</span><span class="special">);</span>
352            <span class="special">}</span>
353        <span class="special">}</span>
354    <span class="special">};</span>
355
356    <span class="comment">// Create the composed operation and launch it. This is a constructor</span>
357    <span class="comment">// call followed by invocation of operator(). We use BOOST_ASIO_HANDLER_TYPE</span>
358    <span class="comment">// to convert the completion token into the correct handler type,</span>
359    <span class="comment">// allowing user-defined specializations of the async_result template</span>
360    <span class="comment">// to be used.</span>
361
362    <span class="identifier">echo_op</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">init</span><span class="special">.</span><span class="identifier">completion_handler</span><span class="special">));</span>
363
364    <span class="comment">// This hook lets the caller see a return value when appropriate.</span>
365    <span class="comment">// For example this might return std::future&lt;error_code&gt; if</span>
366    <span class="comment">// CompletionToken is net::use_future, or this might</span>
367    <span class="comment">// return an error code if CompletionToken specifies a coroutine.</span>
368
369    <span class="keyword">return</span> <span class="identifier">init</span><span class="special">.</span><span class="identifier">result</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
370<span class="special">}</span>
371
372<span class="comment">// Including this file undefines the macros used by the stackless fauxroutines.</span>
373<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">asio</span><span class="special">/</span><span class="identifier">unyield</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
374</pre>
375<div class="calloutlist"><table border="0" summary="Callout list">
376<tr>
377<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c7"></a><a href="#beast.using_io.writing_composed_operations.echo.c6"><img src="../../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> </p></td>
378<td valign="top" align="left"><p>
379              The completion handler signature goes here
380            </p></td>
381</tr>
382<tr>
383<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c9"></a><a href="#beast.using_io.writing_composed_operations.echo.c8"><img src="../../../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a> </p></td>
384<td valign="top" align="left"><p>
385              The type of the completion handler obtained from the token
386            </p></td>
387</tr>
388<tr>
389<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c11"></a><a href="#beast.using_io.writing_composed_operations.echo.c10"><img src="../../../../../../../doc/src/images/callouts/3.png" alt="3" border="0"></a> </p></td>
390<td valign="top" align="left"><p>
391              The type of executor used by the stream to dispatch asynchronous operations
392            </p></td>
393</tr>
394<tr>
395<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c13"></a><a href="#beast.using_io.writing_composed_operations.echo.c12"><img src="../../../../../../../doc/src/images/callouts/4.png" alt="4" border="0"></a> </p></td>
396<td valign="top" align="left"><p>
397              The <code class="computeroutput"><span class="identifier">async_base</span></code> helper
398              takes ownership of the handler,
399            </p></td>
400</tr>
401<tr>
402<td width="5%" valign="top" align="left"><p><a name="beast.using_io.writing_composed_operations.echo.c15"></a><a href="#beast.using_io.writing_composed_operations.echo.c14"><img src="../../../../../../../doc/src/images/callouts/5.png" alt="5" border="0"></a> </p></td>
403<td valign="top" align="left"><p>
404              and also needs to know which executor to use.
405            </p></td>
406</tr>
407</table></div>
408<p>
409          There are some common mistakes that should be avoided when writing composed
410          operations:
411        </p>
412<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
413<li class="listitem">
414              Type erasing the final handler. This will cause undefined behavior.
415            </li>
416<li class="listitem">
417              Forgetting to include a return statement after calling an initiating
418              function.
419            </li>
420<li class="listitem">
421              Calling a synchronous function by accident. In general composed operations
422              should not block for long periods of time, since this ties up a thread
423              running on the <a href="../../../../../../../doc/html/boost_asio/reference/io_context.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">io_context</span></code></a>.
424            </li>
425<li class="listitem">
426              Forgetting to provide <code class="computeroutput"><span class="identifier">executor_type</span></code>
427              and <code class="computeroutput"><span class="identifier">get_executor</span></code> for
428              the composed operation. This will cause undefined behavior. For example,
429              if someone calls the initiating function with a strand-wrapped function
430              object, and there is more than thread running on the <a href="../../../../../../../doc/html/boost_asio/reference/io_context.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">io_context</span></code></a>, the underlying
431              stream may be accessed in a fashion that violates safety guarantees.
432              Beast provides class templates to take care of this boilerplate for
433              you.
434            </li>
435<li class="listitem">
436              Forgetting to create an object of type <a href="../../../../../../../doc/html/boost_asio/reference/executor_work_guard.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">executor_work_guard</span></code></a> with
437              the type of executor returned by the stream's <code class="computeroutput"><span class="identifier">get_executor</span></code>
438              member function.
439            </li>
440<li class="listitem">
441              For operations which complete immediately (i.e. without calling an
442              intermediate initiating function), forgetting to use <a href="../../../../../../../doc/html/boost_asio/reference/post.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">post</span></code></a> to invoke the final
443              handler. This breaks the following initiating function guarantee:
444              <span class="emphasis"><em>Regardless of whether the asynchronous operation completes
445              immediately or not, the handler will not be invoked from within this
446              function. Invocation of the handler will be performed in a manner equivalent
447              to using <a href="../../../../../../../doc/html/boost_asio/reference/post.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">post</span></code></a></em></span>. The function
448              <a class="link" href="../../ref/boost__beast__bind_handler.html" title="bind_handler"><code class="computeroutput"><span class="identifier">bind_handler</span></code></a> is provided for
449              this purpose.
450            </li>
451</ul></div>
452<p>
453          The listing for a complete, runnable version of this example is in <a href="../../../../../example/echo-op/echo_op.cpp" target="_top">echo_op.cpp</a>.
454        </p>
455</div>
456<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
457<td align="left"></td>
458<td align="right"><div class="copyright-footer">Copyright © 2016-2019 Vinnie
459      Falco<p>
460        Distributed under the Boost Software License, Version 1.0. (See accompanying
461        file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
462      </p>
463</div></td>
464</tr></table>
465<hr>
466<div class="spirit-nav">
467<a accesskey="p" href="../writing_composed_operations.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../writing_composed_operations.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="detect_ssl.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a>
468</div>
469</body>
470</html>
471