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