Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / asio / coroutine.hpp
1 //
2 // coroutine.hpp
3 // ~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2017 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
11 #ifndef BOOST_ASIO_COROUTINE_HPP
12 #define BOOST_ASIO_COROUTINE_HPP
13
14 namespace boost {
15 namespace asio {
16 namespace detail {
17
18 class coroutine_ref;
19
20 } // namespace detail
21
22 /// Provides support for implementing stackless coroutines.
23 /**
24  * The @c coroutine class may be used to implement stackless coroutines. The
25  * class itself is used to store the current state of the coroutine.
26  *
27  * Coroutines are copy-constructible and assignable, and the space overhead is
28  * a single int. They can be used as a base class:
29  *
30  * @code class session : coroutine
31  * {
32  *   ...
33  * }; @endcode
34  *
35  * or as a data member:
36  *
37  * @code class session
38  * {
39  *   ...
40  *   coroutine coro_;
41  * }; @endcode
42  *
43  * or even bound in as a function argument using lambdas or @c bind(). The
44  * important thing is that as the application maintains a copy of the object
45  * for as long as the coroutine must be kept alive.
46  *
47  * @par Pseudo-keywords
48  *
49  * A coroutine is used in conjunction with certain "pseudo-keywords", which
50  * are implemented as macros. These macros are defined by a header file:
51  *
52  * @code #include <boost/asio/yield.hpp>@endcode
53  *
54  * and may conversely be undefined as follows:
55  *
56  * @code #include <boost/asio/unyield.hpp>@endcode
57  *
58  * <b>reenter</b>
59  *
60  * The @c reenter macro is used to define the body of a coroutine. It takes a
61  * single argument: a pointer or reference to a coroutine object. For example,
62  * if the base class is a coroutine object you may write:
63  *
64  * @code reenter (this)
65  * {
66  *   ... coroutine body ...
67  * } @endcode
68  *
69  * and if a data member or other variable you can write:
70  *
71  * @code reenter (coro_)
72  * {
73  *   ... coroutine body ...
74  * } @endcode
75  *
76  * When @c reenter is executed at runtime, control jumps to the location of the
77  * last @c yield or @c fork.
78  *
79  * The coroutine body may also be a single statement, such as:
80  *
81  * @code reenter (this) for (;;)
82  * {
83  *   ...
84  * } @endcode
85  *
86  * @b Limitation: The @c reenter macro is implemented using a switch. This
87  * means that you must take care when using local variables within the
88  * coroutine body. The local variable is not allowed in a position where
89  * reentering the coroutine could bypass the variable definition.
90  *
91  * <b>yield <em>statement</em></b>
92  *
93  * This form of the @c yield keyword is often used with asynchronous operations:
94  *
95  * @code yield socket_->async_read_some(buffer(*buffer_), *this); @endcode
96  *
97  * This divides into four logical steps:
98  *
99  * @li @c yield saves the current state of the coroutine.
100  * @li The statement initiates the asynchronous operation.
101  * @li The resume point is defined immediately following the statement.
102  * @li Control is transferred to the end of the coroutine body.
103  *
104  * When the asynchronous operation completes, the function object is invoked
105  * and @c reenter causes control to transfer to the resume point. It is
106  * important to remember to carry the coroutine state forward with the
107  * asynchronous operation. In the above snippet, the current class is a
108  * function object object with a coroutine object as base class or data member.
109  *
110  * The statement may also be a compound statement, and this permits us to
111  * define local variables with limited scope:
112  *
113  * @code yield
114  * {
115  *   mutable_buffers_1 b = buffer(*buffer_);
116  *   socket_->async_read_some(b, *this);
117  * } @endcode
118  *
119  * <b>yield return <em>expression</em> ;</b>
120  *
121  * This form of @c yield is often used in generators or coroutine-based parsers.
122  * For example, the function object:
123  *
124  * @code struct interleave : coroutine
125  * {
126  *   istream& is1;
127  *   istream& is2;
128  *   char operator()(char c)
129  *   {
130  *     reenter (this) for (;;)
131  *     {
132  *       yield return is1.get();
133  *       yield return is2.get();
134  *     }
135  *   }
136  * }; @endcode
137  *
138  * defines a trivial coroutine that interleaves the characters from two input
139  * streams.
140  *
141  * This type of @c yield divides into three logical steps:
142  *
143  * @li @c yield saves the current state of the coroutine.
144  * @li The resume point is defined immediately following the semicolon.
145  * @li The value of the expression is returned from the function.
146  *
147  * <b>yield ;</b>
148  *
149  * This form of @c yield is equivalent to the following steps:
150  *
151  * @li @c yield saves the current state of the coroutine.
152  * @li The resume point is defined immediately following the semicolon.
153  * @li Control is transferred to the end of the coroutine body.
154  *
155  * This form might be applied when coroutines are used for cooperative
156  * threading and scheduling is explicitly managed. For example:
157  *
158  * @code struct task : coroutine
159  * {
160  *   ...
161  *   void operator()()
162  *   {
163  *     reenter (this)
164  *     {
165  *       while (... not finished ...)
166  *       {
167  *         ... do something ...
168  *         yield;
169  *         ... do some more ...
170  *         yield;
171  *       }
172  *     }
173  *   }
174  *   ...
175  * };
176  * ...
177  * task t1, t2;
178  * for (;;)
179  * {
180  *   t1();
181  *   t2();
182  * } @endcode
183  *
184  * <b>yield break ;</b>
185  *
186  * The final form of @c yield is used to explicitly terminate the coroutine.
187  * This form is comprised of two steps:
188  *
189  * @li @c yield sets the coroutine state to indicate termination.
190  * @li Control is transferred to the end of the coroutine body.
191  *
192  * Once terminated, calls to is_complete() return true and the coroutine cannot
193  * be reentered.
194  *
195  * Note that a coroutine may also be implicitly terminated if the coroutine
196  * body is exited without a yield, e.g. by return, throw or by running to the
197  * end of the body.
198  *
199  * <b>fork <em>statement</em></b>
200  *
201  * The @c fork pseudo-keyword is used when "forking" a coroutine, i.e. splitting
202  * it into two (or more) copies. One use of @c fork is in a server, where a new
203  * coroutine is created to handle each client connection:
204  * 
205  * @code reenter (this)
206  * {
207  *   do
208  *   {
209  *     socket_.reset(new tcp::socket(io_service_));
210  *     yield acceptor->async_accept(*socket_, *this);
211  *     fork server(*this)();
212  *   } while (is_parent());
213  *   ... client-specific handling follows ...
214  * } @endcode
215  * 
216  * The logical steps involved in a @c fork are:
217  * 
218  * @li @c fork saves the current state of the coroutine.
219  * @li The statement creates a copy of the coroutine and either executes it
220  *     immediately or schedules it for later execution.
221  * @li The resume point is defined immediately following the semicolon.
222  * @li For the "parent", control immediately continues from the next line.
223  *
224  * The functions is_parent() and is_child() can be used to differentiate
225  * between parent and child. You would use these functions to alter subsequent
226  * control flow.
227  *
228  * Note that @c fork doesn't do the actual forking by itself. It is the
229  * application's responsibility to create a clone of the coroutine and call it.
230  * The clone can be called immediately, as above, or scheduled for delayed
231  * execution using something like io_service::post().
232  *
233  * @par Alternate macro names
234  *
235  * If preferred, an application can use macro names that follow a more typical
236  * naming convention, rather than the pseudo-keywords. These are:
237  *
238  * @li @c BOOST_ASIO_CORO_REENTER instead of @c reenter
239  * @li @c BOOST_ASIO_CORO_YIELD instead of @c yield
240  * @li @c BOOST_ASIO_CORO_FORK instead of @c fork
241  */
242 class coroutine
243 {
244 public:
245   /// Constructs a coroutine in its initial state.
246   coroutine() : value_(0) {}
247
248   /// Returns true if the coroutine is the child of a fork.
249   bool is_child() const { return value_ < 0; }
250
251   /// Returns true if the coroutine is the parent of a fork.
252   bool is_parent() const { return !is_child(); }
253
254   /// Returns true if the coroutine has reached its terminal state.
255   bool is_complete() const { return value_ == -1; }
256
257 private:
258   friend class detail::coroutine_ref;
259   int value_;
260 };
261
262
263 namespace detail {
264
265 class coroutine_ref
266 {
267 public:
268   coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
269   coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
270   ~coroutine_ref() { if (!modified_) value_ = -1; }
271   operator int() const { return value_; }
272   int& operator=(int v) { modified_ = true; return value_ = v; }
273 private:
274   void operator=(const coroutine_ref&);
275   int& value_;
276   bool modified_;
277 };
278
279 } // namespace detail
280 } // namespace asio
281 } // namespace boost
282
283 #define BOOST_ASIO_CORO_REENTER(c) \
284   switch (::boost::asio::detail::coroutine_ref _coro_value = c) \
285     case -1: if (_coro_value) \
286     { \
287       goto terminate_coroutine; \
288       terminate_coroutine: \
289       _coro_value = -1; \
290       goto bail_out_of_coroutine; \
291       bail_out_of_coroutine: \
292       break; \
293     } \
294     else case 0:
295
296 #define BOOST_ASIO_CORO_YIELD_IMPL(n) \
297   for (_coro_value = (n);;) \
298     if (_coro_value == 0) \
299     { \
300       case (n): ; \
301       break; \
302     } \
303     else \
304       switch (_coro_value ? 0 : 1) \
305         for (;;) \
306           case -1: if (_coro_value) \
307             goto terminate_coroutine; \
308           else for (;;) \
309             case 1: if (_coro_value) \
310               goto bail_out_of_coroutine; \
311             else case 0:
312
313 #define BOOST_ASIO_CORO_FORK_IMPL(n) \
314   for (_coro_value = -(n);; _coro_value = (n)) \
315     if (_coro_value == (n)) \
316     { \
317       case -(n): ; \
318       break; \
319     } \
320     else
321
322 #if defined(_MSC_VER)
323 # define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__COUNTER__ + 1)
324 # define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__COUNTER__ + 1)
325 #else // defined(_MSC_VER)
326 # define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__LINE__)
327 # define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__LINE__)
328 #endif // defined(_MSC_VER)
329
330 #endif // BOOST_ASIO_COROUTINE_HPP