symmetric_coroutine_object.hpp 7.8 KB

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