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_OBJECT_H
8 #define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_OBJECT_H
9 
10 #include <boost/assert.hpp>
11 #include <boost/config.hpp>
12 #include <boost/move/move.hpp>
13 
14 #include <boost/coroutine/detail/config.hpp>
15 #include <boost/coroutine/detail/flags.hpp>
16 #include <boost/coroutine/detail/preallocated.hpp>
17 #include <boost/coroutine/detail/symmetric_coroutine_impl.hpp>
18 #include <boost/coroutine/detail/symmetric_coroutine_yield.hpp>
19 #include <boost/coroutine/exceptions.hpp>
20 #include <boost/coroutine/stack_context.hpp>
21 
22 #ifdef BOOST_HAS_ABI_HEADERS
23 #  include BOOST_ABI_PREFIX
24 #endif
25 
26 namespace boost {
27 namespace coroutines {
28 
29 struct stack_context;
30 
31 namespace detail {
32 
33 template< typename R, typename Fn, typename StackAllocator >
34 class symmetric_coroutine_object : public symmetric_coroutine_impl< R >
35 {
36 private:
37     typedef symmetric_coroutine_impl< R >                       impl_t;
38     typedef symmetric_coroutine_object< R, Fn, StackAllocator > obj_t;
39 
40     Fn                  fn_;
41     stack_context       stack_ctx_;
42     StackAllocator      stack_alloc_;
43 
deallocate_(obj_t * obj)44     static void deallocate_( obj_t * obj)
45     {
46         stack_context stack_ctx( obj->stack_ctx_);
47         StackAllocator stack_alloc( obj->stack_alloc_);
48         obj->unwind_stack();
49         obj->~obj_t();
50         stack_alloc.deallocate( stack_ctx);
51     }
52 
53 public:
54 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)55     symmetric_coroutine_object( Fn fn, attributes const& attrs,
56                                 preallocated const& palloc,
57                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
58         impl_t( palloc,
59                 stack_unwind == attrs.do_unwind),
60         fn_( fn),
61         stack_ctx_( palloc.sctx),
62         stack_alloc_( stack_alloc)
63     {}
64 #endif
65 
symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)66     symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
67                                 preallocated const& palloc,
68                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
69         impl_t( palloc,
70                 stack_unwind == attrs.do_unwind),
71 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
72         fn_( fn),
73 #else
74         fn_( boost::forward< Fn >( fn) ),
75 #endif
76         stack_ctx_( palloc.sctx),
77         stack_alloc_( stack_alloc)
78     {}
79 
run(R * r)80     void run( R * r) BOOST_NOEXCEPT
81     {
82         BOOST_ASSERT( ! impl_t::unwind_requested() );
83 
84         impl_t::flags_ |= flag_started;
85         impl_t::flags_ |= flag_running;
86         try
87         {
88             symmetric_coroutine_yield< R > yc( this, r);
89             fn_( yc);
90         }
91         catch ( forced_unwind const&)
92         {}
93         catch (...)
94         { std::terminate(); }
95 
96         impl_t::flags_ |= flag_complete;
97         impl_t::flags_ &= ~flag_running;
98         typename impl_t::param_type to;
99         impl_t::callee_.jump(
100             impl_t::caller_,
101             & to);
102         BOOST_ASSERT_MSG( false, "coroutine is complete");
103     }
104 
destroy()105     void destroy()
106     { deallocate_( this); }
107 };
108 
109 template< typename R, typename Fn, typename StackAllocator >
110 class symmetric_coroutine_object< R &, Fn, StackAllocator > : public symmetric_coroutine_impl< R & >
111 {
112 private:
113     typedef symmetric_coroutine_impl< R & >                         impl_t;
114     typedef symmetric_coroutine_object< R &, Fn, StackAllocator >   obj_t;
115 
116     Fn                  fn_;
117     stack_context       stack_ctx_;
118     StackAllocator      stack_alloc_;
119 
deallocate_(obj_t * obj)120     static void deallocate_( obj_t * obj)
121     {
122         stack_context stack_ctx( obj->stack_ctx_);
123         StackAllocator stack_alloc( obj->stack_alloc_);
124         obj->unwind_stack();
125         obj->~obj_t();
126         stack_alloc.deallocate( stack_ctx);
127     }
128 
129 public:
130 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)131     symmetric_coroutine_object( Fn fn, attributes const& attrs,
132                                 preallocated const& palloc,
133                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
134         impl_t( palloc,
135                 stack_unwind == attrs.do_unwind),
136         fn_( fn),
137         stack_ctx_( palloc.sctx),
138         stack_alloc_( stack_alloc)
139     {}
140 #endif
141 
symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)142     symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
143                                 preallocated const& palloc,
144                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
145         impl_t( palloc,
146                 stack_unwind == attrs.do_unwind),
147 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
148         fn_( fn),
149 #else
150         fn_( boost::forward< Fn >( fn) ),
151 #endif
152         stack_ctx_( palloc.sctx),
153         stack_alloc_( stack_alloc)
154     {}
155 
run(R * r)156     void run( R * r) BOOST_NOEXCEPT
157     {
158         BOOST_ASSERT( ! impl_t::unwind_requested() );
159 
160         impl_t::flags_ |= flag_started;
161         impl_t::flags_ |= flag_running;
162         try
163         {
164             symmetric_coroutine_yield< R & > yc( this, r);
165             fn_( yc);
166         }
167         catch ( forced_unwind const&)
168         {}
169         catch (...)
170         { std::terminate(); }
171 
172         impl_t::flags_ |= flag_complete;
173         impl_t::flags_ &= ~flag_running;
174         typename impl_t::param_type to;
175         impl_t::callee_.jump(
176             impl_t::caller_,
177             & to);
178         BOOST_ASSERT_MSG( false, "coroutine is complete");
179     }
180 
destroy()181     void destroy()
182     { deallocate_( this); }
183 };
184 
185 template< typename Fn, typename StackAllocator >
186 class symmetric_coroutine_object< void, Fn, StackAllocator > : public symmetric_coroutine_impl< void >
187 {
188 private:
189     typedef symmetric_coroutine_impl< void >                        impl_t;
190     typedef symmetric_coroutine_object< void, Fn, StackAllocator >  obj_t;
191 
192     Fn                  fn_;
193     stack_context       stack_ctx_;
194     StackAllocator      stack_alloc_;
195 
deallocate_(obj_t * obj)196     static void deallocate_( obj_t * obj)
197     {
198         stack_context stack_ctx( obj->stack_ctx_);
199         StackAllocator stack_alloc( obj->stack_alloc_);
200         obj->unwind_stack();
201         obj->~obj_t();
202         stack_alloc.deallocate( stack_ctx);
203     }
204 
205 public:
206 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)207     symmetric_coroutine_object( Fn fn, attributes const& attrs,
208                                 preallocated const& palloc,
209                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
210         impl_t( palloc,
211                 stack_unwind == attrs.do_unwind),
212         fn_( fn),
213         stack_ctx_( palloc.sctx),
214         stack_alloc_( stack_alloc)
215     {}
216 #endif
217 
symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)218     symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
219                                 preallocated const& palloc,
220                                 StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
221         impl_t( palloc,
222                 stack_unwind == attrs.do_unwind),
223 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
224         fn_( fn),
225 #else
226         fn_( boost::forward< Fn >( fn) ),
227 #endif
228         stack_ctx_( palloc.sctx),
229         stack_alloc_( stack_alloc)
230     {}
231 
run()232     void run() BOOST_NOEXCEPT
233     {
234         BOOST_ASSERT( ! impl_t::unwind_requested() );
235 
236         impl_t::flags_ |= flag_started;
237         impl_t::flags_ |= flag_running;
238         try
239         {
240             symmetric_coroutine_yield< void > yc( this);
241             fn_( yc);
242         }
243         catch ( forced_unwind const&)
244         {}
245         catch (...)
246         { std::terminate(); }
247 
248         impl_t::flags_ |= flag_complete;
249         impl_t::flags_ &= ~flag_running;
250         typename impl_t::param_type to;
251         impl_t::callee_.jump(
252             impl_t::caller_,
253             & to);
254         BOOST_ASSERT_MSG( false, "coroutine is complete");
255     }
256 
destroy()257     void destroy()
258     { deallocate_( this); }
259 };
260 
261 }}}
262 
263 #ifdef BOOST_HAS_ABI_HEADERS
264 #  include BOOST_ABI_SUFFIX
265 #endif
266 
267 #endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_OBJECT_H
268