1 
2 //          Copyright Oliver Kowalke 2009.
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_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H
8 #define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H
9 
10 #include <boost/assert.hpp>
11 #include <boost/config.hpp>
12 #include <boost/move/move.hpp>
13 #include <boost/utility/explicit_operator_bool.hpp>
14 
15 #include <boost/coroutine/attributes.hpp>
16 #include <boost/coroutine/detail/config.hpp>
17 #include <boost/coroutine/detail/preallocated.hpp>
18 #include <boost/coroutine/detail/symmetric_coroutine_impl.hpp>
19 #include <boost/coroutine/detail/symmetric_coroutine_object.hpp>
20 #include <boost/coroutine/detail/symmetric_coroutine_yield.hpp>
21 #include <boost/coroutine/stack_allocator.hpp>
22 #include <boost/coroutine/stack_context.hpp>
23 
24 #ifdef BOOST_HAS_ABI_HEADERS
25 #  include BOOST_ABI_PREFIX
26 #endif
27 
28 namespace boost {
29 namespace coroutines {
30 namespace detail {
31 
32 template< typename Arg >
33 class symmetric_coroutine_call
34 {
35 private:
36     template< typename X >
37     friend class symmetric_coroutine_yield;
38 
39     typedef symmetric_coroutine_impl< Arg >   impl_type;
40 
41     BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call)
42 
43     struct dummy {};
44 
45     impl_type       *   impl_;
46 
47 public:
48     typedef Arg                                value_type;
49     typedef symmetric_coroutine_yield< Arg >   yield_type;
50 
symmetric_coroutine_call()51     symmetric_coroutine_call() BOOST_NOEXCEPT :
52         impl_( 0)
53     {}
54 
55 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
56 # ifdef BOOST_MSVC
57     typedef void ( * coroutine_fn)( yield_type &);
58 
symmetric_coroutine_call(coroutine_fn fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())59     explicit symmetric_coroutine_call( coroutine_fn fn,
60                                        attributes const& attrs = attributes(),
61                                        stack_allocator stack_alloc = stack_allocator() ) :
62         impl_( 0)
63     {
64         // create a stack-context
65         stack_context stack_ctx;
66         // allocate the coroutine-stack
67         stack_alloc.allocate( stack_ctx, attrs.size);
68         BOOST_ASSERT( 0 != stack_ctx.sp);
69         // typedef of internal coroutine-type
70         typedef symmetric_coroutine_object< Arg, coroutine_fn, stack_allocator > object_t;
71         // reserve space on top of coroutine-stack for internal coroutine-type
72         std::size_t size = stack_ctx.size - sizeof( object_t);
73         BOOST_ASSERT( 0 != size);
74         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
75         BOOST_ASSERT( 0 != sp);
76         // placement new for internal coroutine
77         impl_ = new ( sp) object_t(
78                     boost::forward< coroutine_fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
79         BOOST_ASSERT( impl_);
80     }
81 
82     template< typename StackAllocator >
symmetric_coroutine_call(coroutine_fn fn,attributes const & attrs,StackAllocator stack_alloc)83     explicit symmetric_coroutine_call( coroutine_fn fn,
84                                        attributes const& attrs,
85                                        StackAllocator stack_alloc) :
86         impl_( 0)
87     {
88         // create a stack-context
89         stack_context stack_ctx;
90         // allocate the coroutine-stack
91         stack_alloc.allocate( stack_ctx, attrs.size);
92         BOOST_ASSERT( 0 != stack_ctx.sp);
93         // typedef of internal coroutine-type
94         typedef symmetric_coroutine_object< Arg, coroutine_fn, StackAllocator > object_t;
95         // reserve space on top of coroutine-stack for internal coroutine-type
96         std::size_t size = stack_ctx.size - sizeof( object_t);
97         BOOST_ASSERT( 0 != size);
98         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
99         BOOST_ASSERT( 0 != sp);
100         // placement new for internal coroutine
101         impl_ = new ( sp) object_t(
102                     boost::forward< coroutine_fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
103         BOOST_ASSERT( impl_);
104     }
105 # endif
106     template< typename Fn >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())107     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
108                                        attributes const& attrs = attributes(),
109                                        stack_allocator stack_alloc = stack_allocator() ) :
110         impl_( 0)
111     {
112         // create a stack-context
113         stack_context stack_ctx;
114         // allocate the coroutine-stack
115         stack_alloc.allocate( stack_ctx, attrs.size);
116         BOOST_ASSERT( 0 != stack_ctx.sp);
117         // typedef of internal coroutine-type
118         typedef symmetric_coroutine_object< Arg, Fn, stack_allocator > object_t;
119         // reserve space on top of coroutine-stack for internal coroutine-type
120         std::size_t size = stack_ctx.size - sizeof( object_t);
121         BOOST_ASSERT( 0 != size);
122         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
123         BOOST_ASSERT( 0 != sp);
124         // placement new for internal coroutine
125         impl_ = new ( sp) object_t(
126                     boost::forward< Fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
127         BOOST_ASSERT( impl_);
128     }
129 
130     template< typename Fn, typename StackAllocator >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs,StackAllocator stack_alloc)131     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
132                                        attributes const& attrs,
133                                        StackAllocator stack_alloc) :
134         impl_( 0)
135     {
136         // create a stack-context
137         stack_context stack_ctx;
138         // allocate the coroutine-stack
139         stack_alloc.allocate( stack_ctx, attrs.size);
140         BOOST_ASSERT( 0 != stack_ctx.sp);
141         // typedef of internal coroutine-type
142         typedef symmetric_coroutine_object< Arg, Fn, StackAllocator > object_t;
143         // reserve space on top of coroutine-stack for internal coroutine-type
144         std::size_t size = stack_ctx.size - sizeof( object_t);
145         BOOST_ASSERT( 0 != size);
146         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
147         BOOST_ASSERT( 0 != sp);
148         // placement new for internal coroutine
149         impl_ = new ( sp) object_t(
150                     boost::forward< Fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
151         BOOST_ASSERT( impl_);
152     }
153 #else
154     template< typename Fn >
symmetric_coroutine_call(Fn fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())155     explicit symmetric_coroutine_call( Fn fn,
156                                        attributes const& attrs = attributes(),
157                                        stack_allocator stack_alloc = stack_allocator() ) :
158         impl_( 0)
159     {
160         // create a stack-context
161         stack_context stack_ctx;
162         // allocate the coroutine-stack
163         stack_alloc.allocate( stack_ctx, attrs.size);
164         BOOST_ASSERT( 0 != stack_ctx.sp);
165         // typedef of internal coroutine-type
166         typedef symmetric_coroutine_object< Arg, Fn, stack_allocator > object_t;
167         // reserve space on top of coroutine-stack for internal coroutine-type
168         std::size_t size = stack_ctx.size - sizeof( object_t);
169         BOOST_ASSERT( 0 != size);
170         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
171         BOOST_ASSERT( 0 != sp);
172         // placement new for internal coroutine
173         impl_ = new ( sp) object_t(
174                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
175         BOOST_ASSERT( impl_);
176     }
177 
178     template< typename Fn, typename StackAllocator >
symmetric_coroutine_call(Fn fn,attributes const & attrs,StackAllocator stack_alloc)179     explicit symmetric_coroutine_call( Fn fn,
180                                        attributes const& attrs,
181                                        StackAllocator stack_alloc) :
182         impl_( 0)
183     {
184         // create a stack-context
185         stack_context stack_ctx;
186         // allocate the coroutine-stack
187         stack_alloc.allocate( stack_ctx, attrs.size);
188         BOOST_ASSERT( 0 != stack_ctx.sp);
189         // typedef of internal coroutine-type
190         typedef symmetric_coroutine_object< Arg, Fn, StackAllocator > object_t;
191         // reserve space on top of coroutine-stack for internal coroutine-type
192         std::size_t size = stack_ctx.size - sizeof( object_t);
193         BOOST_ASSERT( 0 != size);
194         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
195         BOOST_ASSERT( 0 != sp);
196         // placement new for internal coroutine
197         impl_ = new ( sp) object_t(
198                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
199         BOOST_ASSERT( impl_);
200     }
201 
202     template< typename Fn >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())203     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
204                                        attributes const& attrs = attributes(),
205                                        stack_allocator stack_alloc = stack_allocator() ) :
206         impl_( 0)
207     {
208         // create a stack-context
209         stack_context stack_ctx;
210         // allocate the coroutine-stack
211         stack_alloc.allocate( stack_ctx, attrs.size);
212         BOOST_ASSERT( 0 != stack_ctx.sp);
213         // typedef of internal coroutine-type
214         typedef symmetric_coroutine_object< Arg, Fn, stack_allocator > object_t;
215         // reserve space on top of coroutine-stack for internal coroutine-type
216         std::size_t size = stack_ctx.size - sizeof( object_t);
217         BOOST_ASSERT( 0 != size);
218         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
219         BOOST_ASSERT( 0 != sp);
220         // placement new for internal coroutine
221         impl_ = new ( sp) object_t(
222                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
223         BOOST_ASSERT( impl_);
224     }
225 
226     template< typename Fn, typename StackAllocator >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs,StackAllocator stack_alloc)227     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
228                                        attributes const& attrs,
229                                        StackAllocator stack_alloc) :
230         impl_( 0)
231     {
232         // create a stack-context
233         stack_context stack_ctx;
234         // allocate the coroutine-stack
235         stack_alloc.allocate( stack_ctx, attrs.size);
236         BOOST_ASSERT( 0 != stack_ctx.sp);
237         // typedef of internal coroutine-type
238         typedef symmetric_coroutine_object< Arg, Fn, StackAllocator > object_t;
239         // reserve space on top of coroutine-stack for internal coroutine-type
240         std::size_t size = stack_ctx.size - sizeof( object_t);
241         BOOST_ASSERT( 0 != size);
242         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
243         BOOST_ASSERT( 0 != sp);
244         // placement new for internal coroutine
245         impl_ = new ( sp) object_t(
246                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
247         BOOST_ASSERT( impl_);
248     }
249 #endif
250 
~symmetric_coroutine_call()251     ~symmetric_coroutine_call()
252     {
253         if ( 0 != impl_)
254         {
255             impl_->destroy();
256             impl_ = 0;
257         }
258     }
259 
symmetric_coroutine_call(BOOST_RV_REF (symmetric_coroutine_call)other)260     symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT :
261         impl_( 0)
262     { swap( other); }
263 
operator =(BOOST_RV_REF (symmetric_coroutine_call)other)264     symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT
265     {
266         symmetric_coroutine_call tmp( boost::move( other) );
267         swap( tmp);
268         return * this;
269     }
270 
271     BOOST_EXPLICIT_OPERATOR_BOOL();
272 
operator !() const273     bool operator!() const BOOST_NOEXCEPT
274     { return 0 == impl_ || impl_->is_complete() || impl_->is_running(); }
275 
swap(symmetric_coroutine_call & other)276     void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT
277     { std::swap( impl_, other.impl_); }
278 
operator ()(Arg arg)279     symmetric_coroutine_call & operator()( Arg arg) BOOST_NOEXCEPT
280     {
281         BOOST_ASSERT( * this);
282 
283         impl_->resume( arg);
284         return * this;
285     }
286 };
287 
288 template< typename Arg >
289 class symmetric_coroutine_call< Arg & >
290 {
291 private:
292     template< typename X >
293     friend class symmetric_coroutine_yield;
294 
295     typedef symmetric_coroutine_impl< Arg & >     impl_type;
296 
297     BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call)
298 
299     struct dummy {};
300 
301     impl_type       *   impl_;
302 
303 public:
304     typedef Arg                                    value_type;
305     typedef symmetric_coroutine_yield< Arg & >     yield_type;
306 
symmetric_coroutine_call()307     symmetric_coroutine_call() BOOST_NOEXCEPT :
308         impl_( 0)
309     {}
310 
311 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
312 # ifdef BOOST_MSVC
313     typedef void ( * coroutine_fn)( yield_type &);
314 
symmetric_coroutine_call(coroutine_fn fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())315     explicit symmetric_coroutine_call( coroutine_fn fn,
316                                        attributes const& attrs = attributes(),
317                                        stack_allocator stack_alloc = stack_allocator() ) :
318         impl_( 0)
319     {
320         // create a stack-context
321         stack_context stack_ctx;
322         // allocate the coroutine-stack
323         stack_alloc.allocate( stack_ctx, attrs.size);
324         BOOST_ASSERT( 0 != stack_ctx.sp);
325         // typedef of internal coroutine-type
326         typedef symmetric_coroutine_object< Arg &, coroutine_fn, stack_allocator > object_t;
327         // reserve space on top of coroutine-stack for internal coroutine-type
328         std::size_t size = stack_ctx.size - sizeof( object_t);
329         BOOST_ASSERT( 0 != size);
330         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
331         BOOST_ASSERT( 0 != sp);
332         // placement new for internal coroutine
333         impl_ = new ( sp) object_t(
334                     boost::forward< coroutine_fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
335         BOOST_ASSERT( impl_);
336     }
337 
338     template< typename StackAllocator >
symmetric_coroutine_call(coroutine_fn fn,attributes const & attrs,StackAllocator stack_alloc)339     explicit symmetric_coroutine_call( coroutine_fn fn,
340                                        attributes const& attrs,
341                                        StackAllocator stack_alloc) :
342         impl_( 0)
343     {
344         // create a stack-context
345         stack_context stack_ctx;
346         // allocate the coroutine-stack
347         stack_alloc.allocate( stack_ctx, attrs.size);
348         BOOST_ASSERT( 0 != stack_ctx.sp);
349         // typedef of internal coroutine-type
350         typedef symmetric_coroutine_object< Arg &, coroutine_fn, StackAllocator > object_t;
351         // reserve space on top of coroutine-stack for internal coroutine-type
352         std::size_t size = stack_ctx.size - sizeof( object_t);
353         BOOST_ASSERT( 0 != size);
354         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
355         BOOST_ASSERT( 0 != sp);
356         // placement new for internal coroutine
357         impl_ = new ( sp) object_t(
358                     boost::forward< coroutine_fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
359         BOOST_ASSERT( impl_);
360     }
361 # endif
362     template< typename Fn >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())363     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
364                                        attributes const& attrs = attributes(),
365                                        stack_allocator stack_alloc = stack_allocator() ) :
366         impl_( 0)
367     {
368         // create a stack-context
369         stack_context stack_ctx;
370         // allocate the coroutine-stack
371         stack_alloc.allocate( stack_ctx, attrs.size);
372         BOOST_ASSERT( 0 != stack_ctx.sp);
373         // typedef of internal coroutine-type
374         typedef symmetric_coroutine_object< Arg &, Fn, stack_allocator > object_t;
375         // reserve space on top of coroutine-stack for internal coroutine-type
376         std::size_t size = stack_ctx.size - sizeof( object_t);
377         BOOST_ASSERT( 0 != size);
378         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
379         BOOST_ASSERT( 0 != sp);
380         // placement new for internal coroutine
381         impl_ = new ( sp) object_t(
382                     boost::forward< Fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
383         BOOST_ASSERT( impl_);
384     }
385 
386     template< typename Fn, typename StackAllocator >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs,StackAllocator stack_alloc)387     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
388                                        attributes const& attrs,
389                                        StackAllocator stack_alloc) :
390         impl_( 0)
391     {
392         // create a stack-context
393         stack_context stack_ctx;
394         // allocate the coroutine-stack
395         stack_alloc.allocate( stack_ctx, attrs.size);
396         BOOST_ASSERT( 0 != stack_ctx.sp);
397         // typedef of internal coroutine-type
398         typedef symmetric_coroutine_object< Arg &, Fn, StackAllocator > object_t;
399         // reserve space on top of coroutine-stack for internal coroutine-type
400         std::size_t size = stack_ctx.size - sizeof( object_t);
401         BOOST_ASSERT( 0 != size);
402         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
403         BOOST_ASSERT( 0 != sp);
404         // placement new for internal coroutine
405         impl_ = new ( sp) object_t(
406                     boost::forward< Fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
407         BOOST_ASSERT( impl_);
408     }
409 #else
410     template< typename Fn >
symmetric_coroutine_call(Fn fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())411     explicit symmetric_coroutine_call( Fn fn,
412                                        attributes const& attrs = attributes(),
413                                        stack_allocator stack_alloc = stack_allocator() ) :
414         impl_( 0)
415     {
416         // create a stack-context
417         stack_context stack_ctx;
418         // allocate the coroutine-stack
419         stack_alloc.allocate( stack_ctx, attrs.size);
420         BOOST_ASSERT( 0 != stack_ctx.sp);
421         // typedef of internal coroutine-type
422         typedef symmetric_coroutine_object< Arg &, Fn, stack_allocator > object_t;
423         // reserve space on top of coroutine-stack for internal coroutine-type
424         std::size_t size = stack_ctx.size - sizeof( object_t);
425         BOOST_ASSERT( 0 != size);
426         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
427         BOOST_ASSERT( 0 != sp);
428         // placement new for internal coroutine
429         impl_ = new ( sp) object_t(
430                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
431         BOOST_ASSERT( impl_);
432     }
433 
434     template< typename Fn, typename StackAllocator >
symmetric_coroutine_call(Fn fn,attributes const & attrs,StackAllocator stack_alloc)435     explicit symmetric_coroutine_call( Fn fn,
436                                        attributes const& attrs,
437                                        StackAllocator stack_alloc) :
438         impl_( 0)
439     {
440         // create a stack-context
441         stack_context stack_ctx;
442         // allocate the coroutine-stack
443         stack_alloc.allocate( stack_ctx, attrs.size);
444         BOOST_ASSERT( 0 != stack_ctx.sp);
445         // typedef of internal coroutine-type
446         typedef symmetric_coroutine_object< Arg &, Fn, StackAllocator > object_t;
447         // reserve space on top of coroutine-stack for internal coroutine-type
448         std::size_t size = stack_ctx.size - sizeof( object_t);
449         BOOST_ASSERT( 0 != size);
450         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
451         BOOST_ASSERT( 0 != sp);
452         // placement new for internal coroutine
453         impl_ = new ( sp) object_t(
454                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
455         BOOST_ASSERT( impl_);
456     }
457 
458     template< typename Fn >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())459     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
460                                        attributes const& attrs = attributes(),
461                                        stack_allocator stack_alloc = stack_allocator() ) :
462         impl_( 0)
463     {
464         // create a stack-context
465         stack_context stack_ctx;
466         // allocate the coroutine-stack
467         stack_alloc.allocate( stack_ctx, attrs.size);
468         BOOST_ASSERT( 0 != stack_ctx.sp);
469         // typedef of internal coroutine-type
470         typedef symmetric_coroutine_object< Arg &, Fn, stack_allocator > object_t;
471         // reserve space on top of coroutine-stack for internal coroutine-type
472         std::size_t size = stack_ctx.size - sizeof( object_t);
473         BOOST_ASSERT( 0 != size);
474         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
475         BOOST_ASSERT( 0 != sp);
476         // placement new for internal coroutine
477         impl_ = new ( sp) object_t(
478                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
479         BOOST_ASSERT( impl_);
480     }
481 
482     template< typename Fn, typename StackAllocator >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs,StackAllocator stack_alloc)483     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
484                                        attributes const& attrs,
485                                        StackAllocator stack_alloc) :
486         impl_( 0)
487     {
488         // create a stack-context
489         stack_context stack_ctx;
490         // allocate the coroutine-stack
491         stack_alloc.allocate( stack_ctx, attrs.size);
492         BOOST_ASSERT( 0 != stack_ctx.sp);
493         // typedef of internal coroutine-type
494         typedef symmetric_coroutine_object< Arg &, Fn, StackAllocator > object_t;
495         // reserve space on top of coroutine-stack for internal coroutine-type
496         std::size_t size = stack_ctx.size - sizeof( object_t);
497         BOOST_ASSERT( 0 != size);
498         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
499         BOOST_ASSERT( 0 != sp);
500         // placement new for internal coroutine
501         impl_ = new ( sp) object_t(
502                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
503         BOOST_ASSERT( impl_);
504     }
505 #endif
506 
~symmetric_coroutine_call()507     ~symmetric_coroutine_call()
508     {
509         if ( 0 != impl_)
510         {
511             impl_->destroy();
512             impl_ = 0;
513         }
514     }
515 
symmetric_coroutine_call(BOOST_RV_REF (symmetric_coroutine_call)other)516     symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT :
517         impl_( 0)
518     { swap( other); }
519 
operator =(BOOST_RV_REF (symmetric_coroutine_call)other)520     symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT
521     {
522         symmetric_coroutine_call tmp( boost::move( other) );
523         swap( tmp);
524         return * this;
525     }
526 
527     BOOST_EXPLICIT_OPERATOR_BOOL();
528 
operator !() const529     bool operator!() const BOOST_NOEXCEPT
530     { return 0 == impl_ || impl_->is_complete() || impl_->is_running(); }
531 
swap(symmetric_coroutine_call & other)532     void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT
533     { std::swap( impl_, other.impl_); }
534 
operator ()(Arg & arg)535     symmetric_coroutine_call & operator()( Arg & arg) BOOST_NOEXCEPT
536     {
537         BOOST_ASSERT( * this);
538 
539         impl_->resume( arg);
540         return * this;
541     }
542 };
543 
544 template<>
545 class symmetric_coroutine_call< void >
546 {
547 private:
548     template< typename X >
549     friend class symmetric_coroutine_yield;
550 
551     typedef symmetric_coroutine_impl< void >        impl_type;
552 
553     BOOST_MOVABLE_BUT_NOT_COPYABLE( symmetric_coroutine_call)
554 
555     struct dummy {};
556 
557     impl_type       *   impl_;
558 
559 public:
560     typedef void                                     value_type;
561     typedef symmetric_coroutine_yield< void >        yield_type;
562 
symmetric_coroutine_call()563     symmetric_coroutine_call() BOOST_NOEXCEPT :
564         impl_( 0)
565     {}
566 
567 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
568 # ifdef BOOST_MSVC
569     typedef void ( * coroutine_fn)( yield_type &);
570 
symmetric_coroutine_call(coroutine_fn fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())571     explicit symmetric_coroutine_call( coroutine_fn fn,
572                                        attributes const& attrs = attributes(),
573                                        stack_allocator stack_alloc = stack_allocator() ) :
574         impl_( 0)
575     {
576         // create a stack-context
577         stack_context stack_ctx;
578         // allocate the coroutine-stack
579         stack_alloc.allocate( stack_ctx, attrs.size);
580         BOOST_ASSERT( 0 != stack_ctx.sp);
581         // typedef of internal coroutine-type
582         typedef symmetric_coroutine_object< void, coroutine_fn, stack_allocator > object_t;
583         // reserve space on top of coroutine-stack for internal coroutine-type
584         std::size_t size = stack_ctx.size - sizeof( object_t);
585         BOOST_ASSERT( 0 != size);
586         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
587         BOOST_ASSERT( 0 != sp);
588         // placement new for internal coroutine
589         impl_ = new ( sp) object_t(
590                     boost::forward< coroutine_fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
591         BOOST_ASSERT( impl_);
592     }
593 
594     template< typename StackAllocator >
symmetric_coroutine_call(coroutine_fn fn,attributes const & attrs,StackAllocator stack_alloc)595     explicit symmetric_coroutine_call( coroutine_fn fn,
596                                        attributes const& attrs,
597                                        StackAllocator stack_alloc) :
598         impl_( 0)
599     {
600         // create a stack-context
601         stack_context stack_ctx;
602         // allocate the coroutine-stack
603         stack_alloc.allocate( stack_ctx, attrs.size);
604         BOOST_ASSERT( 0 != stack_ctx.sp);
605         // typedef of internal coroutine-type
606         typedef symmetric_coroutine_object< void, coroutine_fn, StackAllocator > object_t;
607         // reserve space on top of coroutine-stack for internal coroutine-type
608         std::size_t size = stack_ctx.size - sizeof( object_t);
609         BOOST_ASSERT( 0 != size);
610         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
611         BOOST_ASSERT( 0 != sp);
612         // placement new for internal coroutine
613         impl_ = new ( sp) object_t(
614                     boost::forward< coroutine_fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
615         BOOST_ASSERT( impl_);
616     }
617 # endif
618     template< typename Fn >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())619     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
620                                        attributes const& attrs = attributes(),
621                                        stack_allocator stack_alloc = stack_allocator() ) :
622         impl_( 0)
623     {
624         // create a stack-context
625         stack_context stack_ctx;
626         // allocate the coroutine-stack
627         stack_alloc.allocate( stack_ctx, attrs.size);
628         BOOST_ASSERT( 0 != stack_ctx.sp);
629         // typedef of internal coroutine-type
630         typedef symmetric_coroutine_object< void, Fn, stack_allocator > object_t;
631         // reserve space on top of coroutine-stack for internal coroutine-type
632         std::size_t size = stack_ctx.size - sizeof( object_t);
633         BOOST_ASSERT( 0 != size);
634         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
635         BOOST_ASSERT( 0 != sp);
636         // placement new for internal coroutine
637         impl_ = new ( sp) object_t(
638                     boost::forward< Fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
639         BOOST_ASSERT( impl_);
640     }
641 
642     template< typename Fn, typename StackAllocator >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs,StackAllocator stack_alloc)643     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
644                                        attributes const& attrs,
645                                        StackAllocator stack_alloc) :
646         impl_( 0)
647     {
648         // create a stack-context
649         stack_context stack_ctx;
650         // allocate the coroutine-stack
651         stack_alloc.allocate( stack_ctx, attrs.size);
652         BOOST_ASSERT( 0 != stack_ctx.sp);
653         // typedef of internal coroutine-type
654         typedef symmetric_coroutine_object< void, Fn, StackAllocator > object_t;
655         // reserve space on top of coroutine-stack for internal coroutine-type
656         std::size_t size = stack_ctx.size - sizeof( object_t);
657         BOOST_ASSERT( 0 != size);
658         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
659         BOOST_ASSERT( 0 != sp);
660         // placement new for internal coroutine
661         impl_ = new ( sp) object_t(
662                     boost::forward< Fn >( fn), attrs, preallocated( sp, size, stack_ctx), stack_alloc);
663         BOOST_ASSERT( impl_);
664     }
665 #else
666     template< typename Fn >
symmetric_coroutine_call(Fn fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())667     explicit symmetric_coroutine_call( Fn fn,
668                                        attributes const& attrs = attributes(),
669                                        stack_allocator stack_alloc = stack_allocator() ) :
670         impl_( 0)
671     {
672         // create a stack-context
673         stack_context stack_ctx;
674         // allocate the coroutine-stack
675         stack_alloc.allocate( stack_ctx, attrs.size);
676         BOOST_ASSERT( 0 != stack_ctx.sp);
677         // typedef of internal coroutine-type
678         typedef symmetric_coroutine_object< void, Fn, stack_allocator > object_t;
679         // reserve space on top of coroutine-stack for internal coroutine-type
680         std::size_t size = stack_ctx.size - sizeof( object_t);
681         BOOST_ASSERT( 0 != size);
682         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
683         BOOST_ASSERT( 0 != sp);
684         // placement new for internal coroutine
685         impl_ = new ( sp) object_t(
686                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
687         BOOST_ASSERT( impl_);
688     }
689 
690     template< typename Fn, typename StackAllocator >
symmetric_coroutine_call(Fn fn,attributes const & attrs,StackAllocator stack_alloc)691     explicit symmetric_coroutine_call( Fn fn,
692                                        attributes const& attrs,
693                                        StackAllocator stack_alloc) :
694         impl_( 0)
695     {
696         // create a stack-context
697         stack_context stack_ctx;
698         // allocate the coroutine-stack
699         stack_alloc.allocate( stack_ctx, attrs.size);
700         BOOST_ASSERT( 0 != stack_ctx.sp);
701         // typedef of internal coroutine-type
702         typedef symmetric_coroutine_object< void, Fn, StackAllocator > object_t;
703         // reserve space on top of coroutine-stack for internal coroutine-type
704         std::size_t size = stack_ctx.size - sizeof( object_t);
705         BOOST_ASSERT( 0 != size);
706         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
707         BOOST_ASSERT( 0 != sp);
708         // placement new for internal coroutine
709         impl_ = new ( sp) object_t(
710                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
711         BOOST_ASSERT( impl_);
712     }
713 
714     template< typename Fn >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs=attributes (),stack_allocator stack_alloc=stack_allocator ())715     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
716                                        attributes const& attrs = attributes(),
717                                        stack_allocator stack_alloc = stack_allocator() ) :
718         impl_( 0)
719     {
720         // create a stack-context
721         stack_context stack_ctx;
722         // allocate the coroutine-stack
723         stack_alloc.allocate( stack_ctx, attrs.size);
724         BOOST_ASSERT( 0 != stack_ctx.sp);
725         // typedef of internal coroutine-type
726         typedef symmetric_coroutine_object< void, Fn, stack_allocator > object_t;
727         // reserve space on top of coroutine-stack for internal coroutine-type
728         std::size_t size = stack_ctx.size - sizeof( object_t);
729         BOOST_ASSERT( 0 != size);
730         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
731         BOOST_ASSERT( 0 != sp);
732         // placement new for internal coroutine
733         impl_ = new ( sp) object_t(
734                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
735         BOOST_ASSERT( impl_);
736     }
737 
738     template< typename Fn, typename StackAllocator >
symmetric_coroutine_call(BOOST_RV_REF (Fn)fn,attributes const & attrs,StackAllocator stack_alloc)739     explicit symmetric_coroutine_call( BOOST_RV_REF( Fn) fn,
740                                        attributes const& attrs,
741                                        StackAllocator stack_alloc) :
742         impl_( 0)
743     {
744         // create a stack-context
745         stack_context stack_ctx;
746         // allocate the coroutine-stack
747         stack_alloc.allocate( stack_ctx, attrs.size);
748         BOOST_ASSERT( 0 != stack_ctx.sp);
749         // typedef of internal coroutine-type
750         typedef symmetric_coroutine_object< void, Fn, StackAllocator > object_t;
751         // reserve space on top of coroutine-stack for internal coroutine-type
752         std::size_t size = stack_ctx.size - sizeof( object_t);
753         BOOST_ASSERT( 0 != size);
754         void * sp = static_cast< char * >( stack_ctx.sp) - sizeof( object_t);
755         BOOST_ASSERT( 0 != sp);
756         // placement new for internal coroutine
757         impl_ = new ( sp) object_t(
758                     fn, attrs, preallocated( sp, size, stack_ctx), stack_alloc);
759         BOOST_ASSERT( impl_);
760     }
761 #endif
762 
~symmetric_coroutine_call()763     ~symmetric_coroutine_call()
764     {
765         if ( 0 != impl_)
766         {
767             impl_->destroy();
768             impl_ = 0;
769         }
770     }
771 
symmetric_coroutine_call(BOOST_RV_REF (symmetric_coroutine_call)other)772     inline symmetric_coroutine_call( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT :
773         impl_( 0)
774     { swap( other); }
775 
operator =(BOOST_RV_REF (symmetric_coroutine_call)other)776     inline symmetric_coroutine_call & operator=( BOOST_RV_REF( symmetric_coroutine_call) other) BOOST_NOEXCEPT
777     {
778         symmetric_coroutine_call tmp( boost::move( other) );
779         swap( tmp);
780         return * this;
781     }
782 
783     BOOST_EXPLICIT_OPERATOR_BOOL();
784 
operator !() const785     inline bool operator!() const BOOST_NOEXCEPT
786     { return 0 == impl_ || impl_->is_complete() || impl_->is_running(); }
787 
swap(symmetric_coroutine_call & other)788     inline void swap( symmetric_coroutine_call & other) BOOST_NOEXCEPT
789     { std::swap( impl_, other.impl_); }
790 
operator ()()791     inline symmetric_coroutine_call & operator()() BOOST_NOEXCEPT
792     {
793         BOOST_ASSERT( * this);
794 
795         impl_->resume();
796         return * this;
797     }
798 };
799 
800 template< typename Arg >
swap(symmetric_coroutine_call<Arg> & l,symmetric_coroutine_call<Arg> & r)801 void swap( symmetric_coroutine_call< Arg > & l,
802            symmetric_coroutine_call< Arg > & r)
803 { l.swap( r); }
804 
805 }}}
806 
807 #ifdef BOOST_HAS_ABI_HEADERS
808 #  include BOOST_ABI_SUFFIX
809 #endif
810 
811 #endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_CALL_H
812