]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/coroutine2/include/boost/coroutine2/detail/pull_control_block_ecv1.ipp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / coroutine2 / include / boost / coroutine2 / detail / pull_control_block_ecv1.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_PULL_CONTROL_BLOCK_IPP
8 #define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
9
10 #include <exception>
11 #include <functional>
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/decay_copy.hpp>
21 #include <boost/coroutine2/detail/forced_unwind.hpp>
22 #include <boost/coroutine2/detail/state.hpp>
23
24 #ifdef BOOST_HAS_ABI_HEADERS
25 # include BOOST_ABI_PREFIX
26 #endif
27
28 namespace boost {
29 namespace coroutines2 {
30 namespace detail {
31
32 // pull_coroutine< T >
33
34 template< typename T >
35 void
36 pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
37 boost::context::execution_context ctx = cb->ctx;
38 // destroy control structure
39 cb->state |= state_t::destroy;
40 cb->~control_block();
41 }
42
43 template< typename T >
44 template< typename StackAllocator, typename Fn >
45 pull_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 & ctx, void *) mutable noexcept {
52 // create synthesized push_coroutine< T >
53 typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
54 push_coroutine< T > synthesized{ & synthesized_cb };
55 other = & synthesized_cb;
56 if ( state_t::none == ( state & state_t::destroy) ) {
57 try {
58 auto fn = std::move( fn_);
59 // call coroutine-fn with synthesized push_coroutine as argument
60 fn( synthesized);
61 } catch ( forced_unwind const&) {
62 // do nothing for unwinding exception
63 } catch (...) {
64 // store other exceptions in exception-pointer
65 except = std::current_exception();
66 }
67 }
68 // set termination flags
69 state |= state_t::complete;
70 // jump back to ctx
71 other->ctx();
72 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
73 },
74 std::forward< Fn >( fn),
75 boost::context::execution_context::current(),
76 std::placeholders::_1))},
77 #else
78 ctx{ std::allocator_arg, palloc, salloc,
79 [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
80 // create synthesized push_coroutine< T >
81 typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
82 push_coroutine< T > synthesized{ & synthesized_cb };
83 other = & synthesized_cb;
84 if ( state_t::none == ( state & state_t::destroy) ) {
85 try {
86 auto fn = std::move( fn_);
87 // call coroutine-fn with synthesized push_coroutine as argument
88 fn( synthesized);
89 } catch ( forced_unwind const&) {
90 // do nothing for unwinding exception
91 } catch (...) {
92 // store other exceptions in exception-pointer
93 except = std::current_exception();
94 }
95 }
96 // set termination flags
97 state |= state_t::complete;
98 // jump back to ctx
99 other->ctx();
100 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
101 }},
102 #endif
103 other{ nullptr },
104 state{ state_t::unwind },
105 except{},
106 bvalid{ false },
107 storage{} {
108 // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
109 set( static_cast< T * >( ctx() ) );
110 }
111
112 template< typename T >
113 pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
114 boost::context::execution_context const& ctx_) noexcept :
115 ctx{ ctx_ },
116 other{ cb },
117 state{ state_t::none },
118 except{},
119 bvalid{ false },
120 storage{} {
121 }
122
123 template< typename T >
124 pull_coroutine< T >::control_block::~control_block() {
125 if ( state_t::none == ( state & state_t::complete) &&
126 state_t::none != ( state & state_t::unwind) ) {
127 // unwind coroutine stack
128 other->ctx = boost::context::execution_context::current();
129 ctx( context::exec_ontop_arg, unwind_coroutine);
130 }
131 // destroy data if it set
132 if ( bvalid) {
133 reinterpret_cast< T * >( std::addressof( storage) )->~T();
134 }
135 }
136
137 template< typename T >
138 void
139 pull_coroutine< T >::control_block::deallocate() noexcept {
140 if ( state_t::none != ( state & state_t::unwind) ) {
141 destroy( this);
142 }
143 }
144
145 template< typename T >
146 void
147 pull_coroutine< T >::control_block::resume() {
148 other->ctx = boost::context::execution_context::current();
149 set( static_cast< T * >( ctx() ) );
150 if ( except) {
151 std::rethrow_exception( except);
152 }
153 }
154
155 template< typename T >
156 void
157 pull_coroutine< T >::control_block::set( T * t) {
158 // destroy data if it set
159 if ( bvalid) {
160 reinterpret_cast< T * >( std::addressof( storage) )->~T();
161 }
162 if ( nullptr != t) {
163 ::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( * t) );
164 bvalid = true;
165 } else {
166 bvalid = false;
167 }
168 }
169
170 template< typename T >
171 T &
172 pull_coroutine< T >::control_block::get() noexcept {
173 return * reinterpret_cast< T * >( std::addressof( storage) );
174 }
175
176 template< typename T >
177 bool
178 pull_coroutine< T >::control_block::valid() const noexcept {
179 return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
180 }
181
182
183 // pull_coroutine< T & >
184
185 template< typename T >
186 void
187 pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
188 boost::context::execution_context ctx = cb->ctx;
189 // destroy control structure
190 cb->state |= state_t::destroy;
191 cb->~control_block();
192 }
193
194 template< typename T >
195 template< typename StackAllocator, typename Fn >
196 pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
197 Fn && fn) :
198 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
199 ctx{ std::allocator_arg, palloc, salloc,
200 std::move(
201 std::bind(
202 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept {
203 // create synthesized push_coroutine< T >
204 typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
205 push_coroutine< T & > synthesized{ & synthesized_cb };
206 other = & synthesized_cb;
207 if ( state_t::none == ( state & state_t::destroy) ) {
208 try {
209 auto fn = std::move( fn_);
210 // call coroutine-fn with synthesized push_coroutine as argument
211 fn( synthesized);
212 } catch ( forced_unwind const&) {
213 // do nothing for unwinding exception
214 } catch (...) {
215 // store other exceptions in exception-pointer
216 except = std::current_exception();
217 }
218 }
219 // set termination flags
220 state |= state_t::complete;
221 // jump back to ctx
222 other->ctx();
223 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
224 },
225 std::forward< Fn >( fn),
226 boost::context::execution_context::current(),
227 std::placeholders::_1))},
228 #else
229 ctx{ std::allocator_arg, palloc, salloc,
230 [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
231 // create synthesized push_coroutine< T >
232 typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
233 push_coroutine< T & > synthesized{ & synthesized_cb };
234 other = & synthesized_cb;
235 if ( state_t::none == ( state & state_t::destroy) ) {
236 try {
237 auto fn = std::move( fn_);
238 // call coroutine-fn with synthesized push_coroutine as argument
239 fn( synthesized);
240 } catch ( forced_unwind const&) {
241 // do nothing for unwinding exception
242 } catch (...) {
243 // store other exceptions in exception-pointer
244 except = std::current_exception();
245 }
246 }
247 // set termination flags
248 state |= state_t::complete;
249 // jump back to ctx
250 other->ctx();
251 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
252 }},
253 #endif
254 other{ nullptr },
255 state{ state_t::unwind },
256 except{},
257 t{ nullptr } {
258 // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
259 t = static_cast< T * >( ctx() );
260 }
261
262 template< typename T >
263 pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
264 boost::context::execution_context const& ctx_) noexcept :
265 ctx{ ctx_ },
266 other{ cb },
267 state{ state_t::none },
268 except{},
269 t( nullptr) {
270 }
271
272 template< typename T >
273 pull_coroutine< T & >::control_block::~control_block() {
274 if ( state_t::none == ( state & state_t::complete) &&
275 state_t::none != ( state & state_t::unwind) ) {
276 // unwind coroutine stack
277 other->ctx = boost::context::execution_context::current();
278 ctx( context::exec_ontop_arg, unwind_coroutine);
279 }
280 }
281
282 template< typename T >
283 void
284 pull_coroutine< T & >::control_block::deallocate() noexcept {
285 if ( state_t::none != ( state & state_t::unwind) ) {
286 destroy( this);
287 }
288 }
289
290 template< typename T >
291 void
292 pull_coroutine< T & >::control_block::resume() {
293 other->ctx = boost::context::execution_context::current();
294 t = static_cast< T * >( ctx() );
295 if ( except) {
296 std::rethrow_exception( except);
297 }
298 }
299
300 template< typename T >
301 T &
302 pull_coroutine< T & >::control_block::get() noexcept {
303 return * static_cast< T * >( t);
304 }
305
306 template< typename T >
307 bool
308 pull_coroutine< T & >::control_block::valid() const noexcept {
309 return nullptr != other && state_t::none == ( state & state_t::complete) && nullptr != t;
310 }
311
312
313 // pull_coroutine< void >
314
315 inline
316 void
317 pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
318 boost::context::execution_context ctx = cb->ctx;
319 // destroy control structure
320 cb->state |= state_t::destroy;
321 cb->~control_block();
322 }
323
324 template< typename StackAllocator, typename Fn >
325 pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
326 Fn && fn) :
327 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
328 ctx{ std::allocator_arg, palloc, salloc,
329 std::move(
330 std::bind(
331 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept {
332 // create synthesized push_coroutine< T >
333 typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
334 push_coroutine< void > synthesized{ & synthesized_cb };
335 other = & synthesized_cb;
336 if ( state_t::none == ( state & state_t::destroy) ) {
337 try {
338 auto fn = std::move( fn_);
339 // call coroutine-fn with synthesized push_coroutine as argument
340 fn( synthesized);
341 } catch ( forced_unwind const&) {
342 // do nothing for unwinding exception
343 } catch (...) {
344 // store other exceptions in exception-pointer
345 except = std::current_exception();
346 }
347 }
348 // set termination flags
349 state |= state_t::complete;
350 // jump back to ctx
351 other->ctx();
352 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
353 },
354 std::forward< Fn >( fn),
355 boost::context::execution_context::current(),
356 std::placeholders::_1))},
357 #else
358 ctx{ std::allocator_arg, palloc, salloc,
359 [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
360 // create synthesized push_coroutine< T >
361 typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
362 push_coroutine< void > synthesized{ & synthesized_cb };
363 other = & synthesized_cb;
364 if ( state_t::none == ( state & state_t::destroy) ) {
365 try {
366 auto fn = std::move( fn_);
367 // call coroutine-fn with synthesized push_coroutine as argument
368 fn( synthesized);
369 } catch ( forced_unwind const&) {
370 // do nothing for unwinding exception
371 } catch (...) {
372 // store other exceptions in exception-pointer
373 except = std::current_exception();
374 }
375 }
376 // set termination flags
377 state |= state_t::complete;
378 // jump back to ctx
379 other->ctx();
380 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
381 }},
382 #endif
383 other{ nullptr },
384 state{ state_t::unwind },
385 except{} {
386 // enter coroutine-fn in order to have first value available after ctor returns
387 ctx();
388 }
389
390 inline
391 pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
392 boost::context::execution_context const& ctx_) noexcept :
393 ctx{ ctx_ },
394 other{ cb },
395 state{ state_t::none },
396 except{} {
397 }
398
399 inline
400 pull_coroutine< void >::control_block::~control_block() {
401 if ( state_t::none == ( state & state_t::complete) &&
402 state_t::none != ( state & state_t::unwind) ) {
403 // unwind coroutine stack
404 other->ctx = boost::context::execution_context::current();
405 ctx( context::exec_ontop_arg, unwind_coroutine);
406 }
407 }
408
409 inline
410 void
411 pull_coroutine< void >::control_block::deallocate() noexcept {
412 if ( state_t::none != ( state & state_t::unwind) ) {
413 destroy( this);
414 }
415 }
416
417 inline
418 void
419 pull_coroutine< void >::control_block::resume() {
420 other->ctx = boost::context::execution_context::current();
421 ctx();
422 if ( except) {
423 std::rethrow_exception( except);
424 }
425 }
426
427 inline
428 bool
429 pull_coroutine< void >::control_block::valid() const noexcept {
430 return nullptr != other && state_t::none == ( state & state_t::complete);
431 }
432
433 }}}
434
435 #ifdef BOOST_HAS_ABI_HEADERS
436 # include BOOST_ABI_SUFFIX
437 #endif
438
439 #endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP