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)
7 #ifndef BOOST_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H
8 #define BOOST_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H
10 #include <boost/assert.hpp>
11 #include <boost/config.hpp>
12 #include <boost/exception_ptr.hpp>
13 #include <boost/throw_exception.hpp>
14 #include <boost/utility.hpp>
16 #include <boost/coroutine/detail/config.hpp>
17 #include <boost/coroutine/detail/coroutine_context.hpp>
18 #include <boost/coroutine/detail/flags.hpp>
19 #include <boost/coroutine/detail/parameters.hpp>
20 #include <boost/coroutine/detail/trampoline_pull.hpp>
21 #include <boost/coroutine/exceptions.hpp>
23 #ifdef BOOST_HAS_ABI_HEADERS
24 # include BOOST_ABI_PREFIX
28 namespace coroutines {
34 template< typename R >
35 class pull_coroutine_impl : private noncopyable
39 exception_ptr except_;
40 coroutine_context * caller_;
41 coroutine_context * callee_;
45 typedef parameters< R > param_type;
47 pull_coroutine_impl( coroutine_context * caller,
48 coroutine_context * callee,
56 if ( unwind) flags_ |= flag_force_unwind;
59 pull_coroutine_impl( coroutine_context * caller,
60 coroutine_context * callee,
69 if ( unwind) flags_ |= flag_force_unwind;
72 virtual ~pull_coroutine_impl() {}
74 bool force_unwind() const BOOST_NOEXCEPT
75 { return 0 != ( flags_ & flag_force_unwind); }
77 bool unwind_requested() const BOOST_NOEXCEPT
78 { return 0 != ( flags_ & flag_unwind_stack); }
80 bool is_started() const BOOST_NOEXCEPT
81 { return 0 != ( flags_ & flag_started); }
83 bool is_running() const BOOST_NOEXCEPT
84 { return 0 != ( flags_ & flag_running); }
86 bool is_complete() const BOOST_NOEXCEPT
87 { return 0 != ( flags_ & flag_complete); }
89 void unwind_stack() BOOST_NOEXCEPT
91 if ( is_started() && ! is_complete() && force_unwind() )
93 flags_ |= flag_unwind_stack;
94 param_type to( unwind_t::force_unwind);
98 flags_ &= ~flag_unwind_stack;
100 BOOST_ASSERT( is_complete() );
106 BOOST_ASSERT( ! is_running() );
107 BOOST_ASSERT( ! is_complete() );
109 flags_ |= flag_running;
110 param_type to( this);
112 static_cast< param_type * >(
116 flags_ &= ~flag_running;
117 result_ = from->data;
118 if ( from->do_unwind) throw forced_unwind();
119 if ( except_) rethrow_exception( except_);
122 bool has_result() const
123 { return 0 != result_; }
127 if ( ! has_result() )
128 boost::throw_exception(
133 R * get_pointer() const
135 if ( ! has_result() )
136 boost::throw_exception(
141 virtual void destroy() = 0;
144 template< typename R >
145 class pull_coroutine_impl< R & > : private noncopyable
149 exception_ptr except_;
150 coroutine_context * caller_;
151 coroutine_context * callee_;
155 typedef parameters< R & > param_type;
157 pull_coroutine_impl( coroutine_context * caller,
158 coroutine_context * callee,
166 if ( unwind) flags_ |= flag_force_unwind;
169 pull_coroutine_impl( coroutine_context * caller,
170 coroutine_context * callee,
179 if ( unwind) flags_ |= flag_force_unwind;
182 virtual ~pull_coroutine_impl() {}
184 bool force_unwind() const BOOST_NOEXCEPT
185 { return 0 != ( flags_ & flag_force_unwind); }
187 bool unwind_requested() const BOOST_NOEXCEPT
188 { return 0 != ( flags_ & flag_unwind_stack); }
190 bool is_started() const BOOST_NOEXCEPT
191 { return 0 != ( flags_ & flag_started); }
193 bool is_running() const BOOST_NOEXCEPT
194 { return 0 != ( flags_ & flag_running); }
196 bool is_complete() const BOOST_NOEXCEPT
197 { return 0 != ( flags_ & flag_complete); }
199 void unwind_stack() BOOST_NOEXCEPT
201 if ( is_started() && ! is_complete() && force_unwind() )
203 flags_ |= flag_unwind_stack;
204 param_type to( unwind_t::force_unwind);
208 flags_ &= ~flag_unwind_stack;
210 BOOST_ASSERT( is_complete() );
216 BOOST_ASSERT( ! is_running() );
217 BOOST_ASSERT( ! is_complete() );
219 flags_ |= flag_running;
220 param_type to( this);
222 static_cast< param_type * >(
226 flags_ &= ~flag_running;
227 result_ = from->data;
228 if ( from->do_unwind) throw forced_unwind();
229 if ( except_) rethrow_exception( except_);
232 bool has_result() const
233 { return 0 != result_; }
237 if ( ! has_result() )
238 boost::throw_exception(
243 R * get_pointer() const
245 if ( ! has_result() )
246 boost::throw_exception(
251 virtual void destroy() = 0;
255 class pull_coroutine_impl< void > : private noncopyable
259 exception_ptr except_;
260 coroutine_context * caller_;
261 coroutine_context * callee_;
264 typedef parameters< void > param_type;
266 pull_coroutine_impl( coroutine_context * caller,
267 coroutine_context * callee,
274 if ( unwind) flags_ |= flag_force_unwind;
277 virtual ~pull_coroutine_impl() {}
279 inline bool force_unwind() const BOOST_NOEXCEPT
280 { return 0 != ( flags_ & flag_force_unwind); }
282 inline bool unwind_requested() const BOOST_NOEXCEPT
283 { return 0 != ( flags_ & flag_unwind_stack); }
285 inline bool is_started() const BOOST_NOEXCEPT
286 { return 0 != ( flags_ & flag_started); }
288 inline bool is_running() const BOOST_NOEXCEPT
289 { return 0 != ( flags_ & flag_running); }
291 inline bool is_complete() const BOOST_NOEXCEPT
292 { return 0 != ( flags_ & flag_complete); }
294 inline void unwind_stack() BOOST_NOEXCEPT
296 if ( is_started() && ! is_complete() && force_unwind() )
298 flags_ |= flag_unwind_stack;
299 param_type to( unwind_t::force_unwind);
303 flags_ &= ~flag_unwind_stack;
305 BOOST_ASSERT( is_complete() );
311 BOOST_ASSERT( ! is_running() );
312 BOOST_ASSERT( ! is_complete() );
314 flags_ |= flag_running;
315 param_type to( this);
317 static_cast< param_type * >(
321 flags_ &= ~flag_running;
322 if ( from->do_unwind) throw forced_unwind();
323 if ( except_) rethrow_exception( except_);
326 virtual void destroy() = 0;
331 #ifdef BOOST_HAS_ABI_HEADERS
332 # include BOOST_ABI_SUFFIX
335 #endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H