Imported Upstream version 1.63.0
[platform/upstream/boost.git] / boost / coroutine2 / detail / push_control_block_ecv2.ipp
1
2 //          Copyright Oliver Kowalke 2014.
3 // Distributed under the Boost Software License, Version 1.0.
4 //    (See accompanying file LICENSE_1_0.txt or copy at
5 //          http://www.boost.org/LICENSE_1_0.txt)
6
7 #ifndef BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
8 #define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP
9
10 #include <algorithm>
11 #include <exception>
12 #include <memory>
13
14 #include <boost/assert.hpp>
15 #include <boost/config.hpp>
16
17 #include <boost/context/execution_context.hpp>
18
19 #include <boost/coroutine2/detail/config.hpp>
20 #include <boost/coroutine2/detail/forced_unwind.hpp>
21
22 #ifdef BOOST_HAS_ABI_HEADERS
23 #  include BOOST_ABI_PREFIX
24 #endif
25
26 namespace boost {
27 namespace coroutines2 {
28 namespace detail {
29
30 // push_coroutine< T >
31
32 template< typename T >
33 void
34 push_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
35     boost::context::execution_context< T * > ctx = std::move( cb->ctx);
36     // destroy control structure
37     cb->~control_block();
38     // destroy coroutine's stack
39     cb->state |= state_t::destroy;
40     ctx( nullptr);
41 }
42
43 template< typename T >
44 template< typename StackAllocator, typename Fn >
45 push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
46                                                    Fn && fn) :
47 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
48     ctx{ std::allocator_arg, palloc, salloc,
49         std::move( 
50          std::bind(
51              [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< T * > && ctx, T * data) mutable {
52                 // create synthesized pull_coroutine< T >
53                 typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
54                 pull_coroutine< T > synthesized{ & synthesized_cb };
55                 other = & synthesized_cb;
56                 // set transferred value
57                 synthesized_cb.set( data);
58                 if ( state_t::none == ( state & state_t::destroy) ) {
59                     try {
60                         auto fn = std::move( fn_);
61                         // call coroutine-fn with synthesized pull_coroutine as argument
62                         fn( synthesized);
63                     } catch ( boost::context::detail::forced_unwind const&) {
64                         throw;
65                     } catch (...) {
66                         // store other exceptions in exception-pointer
67                         except = std::current_exception();
68                     }
69                 }
70                 // set termination flags
71                 state |= state_t::complete;
72                 // jump back to ctx
73                 auto result = other->ctx( nullptr);
74                 other->ctx = std::move( std::get< 0 >( result) );
75                 return std::move( other->ctx);
76              },
77              std::forward< Fn >( fn),
78              std::placeholders::_1,
79              std::placeholders::_2))},
80 #else
81     ctx{ std::allocator_arg, palloc, salloc,
82          [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< T * > && ctx, T * data) mutable {
83             // create synthesized pull_coroutine< T >
84             typename pull_coroutine< T >::control_block synthesized_cb{ this, ctx };
85             pull_coroutine< T > synthesized{ & synthesized_cb };
86             other = & synthesized_cb;
87             // set transferred value
88             synthesized_cb.set( data);
89             if ( state_t::none == ( state & state_t::destroy) ) {
90                 try {
91                     auto fn = std::move( fn_);
92                     // call coroutine-fn with synthesized pull_coroutine as argument
93                     fn( synthesized);
94                 } catch ( boost::context::detail::forced_unwind const&) {
95                     throw;
96                 } catch (...) {
97                     // store other exceptions in exception-pointer
98                     except = std::current_exception();
99                 }
100             }
101             // set termination flags
102             state |= state_t::complete;
103             // jump back to ctx
104             auto result = other->ctx( nullptr);
105             other->ctx = std::move( std::get< 0 >( result) );
106             return std::move( other->ctx);
107          }},
108 #endif
109     other{ nullptr },
110     state{ state_t::unwind },
111     except{} {
112 }
113
114 template< typename T >
115 push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb,
116                                                    boost::context::execution_context< T * > & ctx_) noexcept :
117     ctx{ std::move( ctx_) },
118     other{ cb },
119     state{ state_t::none },
120     except{} {
121 }
122
123 template< typename T >
124 void
125 push_coroutine< T >::control_block::deallocate() noexcept {
126     if ( state_t::none != ( state & state_t::unwind) ) {
127         destroy( this);
128     }
129 }
130
131 template< typename T >
132 void
133 push_coroutine< T >::control_block::resume( T const& data) {
134     // pass an pointer to other context
135     auto result = ctx( const_cast< T * >( & data) );
136     ctx = std::move( std::get< 0 >( result) );
137     if ( except) {
138         std::rethrow_exception( except);
139     }
140 }
141
142 template< typename T >
143 void
144 push_coroutine< T >::control_block::resume( T && data) {
145     // pass an pointer to other context
146     auto result = ctx( std::addressof( data) );
147     ctx = std::move( std::get< 0 >( result) );
148     if ( except) {
149         std::rethrow_exception( except);
150     }
151 }
152
153 template< typename T >
154 bool
155 push_coroutine< T >::control_block::valid() const noexcept {
156     return state_t::none == ( state & state_t::complete );
157 }
158
159
160 // push_coroutine< T & >
161
162 template< typename T >
163 void
164 push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
165     boost::context::execution_context< T * > ctx = std::move( cb->ctx);
166     // destroy control structure
167     cb->~control_block();
168     // destroy coroutine's stack
169     cb->state |= state_t::destroy;
170     ctx( nullptr);
171 }
172
173 template< typename T >
174 template< typename StackAllocator, typename Fn >
175 push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
176                                                      Fn && fn) :
177 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
178     ctx{ std::allocator_arg, palloc, salloc,
179         std::move( 
180          std::bind(
181              [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< T * > && ctx, T * data) mutable {
182                 // create synthesized pull_coroutine< T & >
183                 typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
184                 pull_coroutine< T & > synthesized{ & synthesized_cb };
185                 other = & synthesized_cb;
186                 // set transferred value
187                 synthesized_cb.t = data;
188                 if ( state_t::none == ( state & state_t::destroy) ) {
189                     try {
190                         auto fn = std::move( fn_);
191                         // call coroutine-fn with synthesized pull_coroutine as argument
192                         fn( synthesized);
193                     } catch ( boost::context::detail::forced_unwind const&) {
194                         throw;
195                     } catch (...) {
196                         // store other exceptions in exception-pointer
197                         except = std::current_exception();
198                     }
199                 }
200                 // set termination flags
201                 state |= state_t::complete;
202                 // jump back to ctx
203                 auto result = other->ctx( nullptr);
204                 other->ctx = std::move( std::get< 0 >( result) );
205                 return std::move( other->ctx);
206              },
207              std::forward< Fn >( fn),
208              std::placeholders::_1,
209              std::placeholders::_2))},
210 #else
211     ctx{ std::allocator_arg, palloc, salloc,
212          [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< T * > && ctx, T * data) mutable {
213             // create synthesized pull_coroutine< T & >
214             typename pull_coroutine< T & >::control_block synthesized_cb{ this, ctx };
215             pull_coroutine< T & > synthesized{ & synthesized_cb };
216             other = & synthesized_cb;
217             // set transferred value
218             synthesized_cb.t = data;
219             if ( state_t::none == ( state & state_t::destroy) ) {
220                 try {
221                     auto fn = std::move( fn_);
222                     // call coroutine-fn with synthesized pull_coroutine as argument
223                     fn( synthesized);
224                 } catch ( boost::context::detail::forced_unwind const&) {
225                     throw;
226                 } catch (...) {
227                     // store other exceptions in exception-pointer
228                     except = std::current_exception();
229                 }
230             }
231             // set termination flags
232             state |= state_t::complete;
233             // jump back to ctx
234             auto result = other->ctx( nullptr);
235             other->ctx = std::move( std::get< 0 >( result) );
236             return std::move( other->ctx);
237          }},
238 #endif
239     other{ nullptr },
240     state{ state_t::unwind },
241     except{} {
242 }
243
244 template< typename T >
245 push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb,
246                                                      boost::context::execution_context< T * > & ctx_) noexcept :
247     ctx{ std::move( ctx_) },
248     other{ cb },
249     state{ state_t::none },
250     except{} {
251 }
252
253 template< typename T >
254 void
255 push_coroutine< T & >::control_block::deallocate() noexcept {
256     if ( state_t::none != ( state & state_t::unwind) ) {
257         destroy( this);
258     }
259 }
260
261 template< typename T >
262 void
263 push_coroutine< T & >::control_block::resume( T & t) {
264     // pass an pointer to other context
265     auto result = ctx( const_cast< typename std::remove_const< T >::type * >( std::addressof( t) ) );
266     ctx = std::move( std::get< 0 >( result) );
267     if ( except) {
268         std::rethrow_exception( except);
269     }
270 }
271
272 template< typename T >
273 bool
274 push_coroutine< T & >::control_block::valid() const noexcept {
275     return state_t::none == ( state & state_t::complete );
276 }
277
278
279 // push_coroutine< void >
280
281 inline
282 void
283 push_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
284     boost::context::execution_context< void > ctx = std::move( cb->ctx);
285     // destroy control structure
286     cb->~control_block();
287     // destroy coroutine's stack
288     cb->state |= state_t::destroy;
289     ctx();
290 }
291
292 template< typename StackAllocator, typename Fn >
293 push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, Fn && fn) :
294 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
295     ctx{ std::allocator_arg, palloc, salloc,
296         std::move( 
297          std::bind(
298              [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context< void > && ctx) mutable {
299                 // create synthesized pull_coroutine< void >
300                 typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx };
301                 pull_coroutine< void > synthesized{ & synthesized_cb };
302                 other = & synthesized_cb;
303                 if ( state_t::none == ( state & state_t::destroy) ) {
304                     try {
305                         auto fn = std::move( fn_);
306                         // call coroutine-fn with synthesized pull_coroutine as argument
307                         fn( synthesized);
308                     } catch ( boost::context::detail::forced_unwind const&) {
309                         throw;
310                     } catch (...) {
311                         // store other exceptions in exception-pointer
312                         except = std::current_exception();
313                     }
314                 }
315                 // set termination flags
316                 state |= state_t::complete;
317                 // jump back to ctx
318                 other->ctx = other->ctx();
319                 return std::move( other->ctx);
320              },
321              std::forward< Fn >( fn),
322              std::placeholders::_1))},
323 #else
324     ctx{ std::allocator_arg, palloc, salloc,
325          [this,fn_=std::forward< Fn >( fn)]( boost::context::execution_context< void > && ctx) mutable {
326             // create synthesized pull_coroutine< void >
327             typename pull_coroutine< void >::control_block synthesized_cb{ this, ctx};
328             pull_coroutine< void > synthesized{ & synthesized_cb };
329             other = & synthesized_cb;
330             if ( state_t::none == ( state & state_t::destroy) ) {
331                 try {
332                     auto fn = std::move( fn_);
333                     // call coroutine-fn with synthesized pull_coroutine as argument
334                     fn( synthesized);
335                 } catch ( boost::context::detail::forced_unwind const&) {
336                     throw;
337                 } catch (...) {
338                     // store other exceptions in exception-pointer
339                     except = std::current_exception();
340                 }
341             }
342             // set termination flags
343             state |= state_t::complete;
344             // jump back to ctx
345             other->ctx = other->ctx();
346             return std::move( other->ctx);
347          }},
348 #endif
349     other{ nullptr },
350     state{ state_t::unwind },
351     except{} {
352 }
353
354 inline
355 push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb,
356                                                       boost::context::execution_context< void > & ctx_) noexcept :
357     ctx{ std::move( ctx_) },
358     other{ cb },
359     state{ state_t::none },
360     except{} {
361 }
362
363 inline
364 void
365 push_coroutine< void >::control_block::deallocate() noexcept {
366     if ( state_t::none != ( state & state_t::unwind) ) {
367         destroy( this);
368     }
369 }
370
371 inline
372 void
373 push_coroutine< void >::control_block::resume() {
374     ctx = ctx();
375     if ( except) {
376         std::rethrow_exception( except);
377     }
378 }
379
380 inline
381 bool
382 push_coroutine< void >::control_block::valid() const noexcept {
383     return state_t::none == ( state & state_t::complete );
384 }
385
386 }}}
387
388 #ifdef BOOST_HAS_ABI_HEADERS
389 #  include BOOST_ABI_SUFFIX
390 #endif
391
392 #endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP