processor_container.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. #ifndef BOOST_STATECHART_PROCESSOR_CONTAINER_HPP_INCLUDED
  2. #define BOOST_STATECHART_PROCESSOR_CONTAINER_HPP_INCLUDED
  3. //////////////////////////////////////////////////////////////////////////////
  4. // Copyright 2002-2008 Andreas Huber Doenni
  5. // Distributed under the Boost Software License, Version 1.0. (See accompany-
  6. // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. //////////////////////////////////////////////////////////////////////////////
  8. #include <boost/statechart/event_base.hpp>
  9. #include <boost/statechart/event_processor.hpp>
  10. #include <boost/assert.hpp>
  11. #include <boost/ref.hpp>
  12. #include <boost/noncopyable.hpp>
  13. #include <boost/intrusive_ptr.hpp>
  14. #include <boost/shared_ptr.hpp>
  15. #include <boost/weak_ptr.hpp>
  16. #include <boost/bind.hpp>
  17. #include <boost/config.hpp> // BOOST_INTEL
  18. #include <boost/detail/workaround.hpp>
  19. #include <boost/detail/allocator_utilities.hpp>
  20. #include <set>
  21. #include <memory> // std::allocator, std::unique_ptr
  22. namespace boost
  23. {
  24. namespace statechart
  25. {
  26. namespace detail
  27. {
  28. template<bool IsReferenceWrapper>
  29. struct unwrap_impl
  30. {
  31. template< typename T >
  32. struct apply { typedef T type; };
  33. };
  34. template<>
  35. struct unwrap_impl<true>
  36. {
  37. template< typename T >
  38. struct apply { typedef typename T::type & type; };
  39. };
  40. template<typename T>
  41. struct unwrap
  42. {
  43. typedef typename unwrap_impl<
  44. is_reference_wrapper< T >::value >::template apply< T >::type type;
  45. };
  46. }
  47. template<
  48. class Scheduler,
  49. class WorkItem,
  50. class Allocator = std::allocator< none > >
  51. class processor_container : noncopyable
  52. {
  53. typedef event_processor< Scheduler > processor_base_type;
  54. #ifdef BOOST_NO_AUTO_PTR
  55. typedef std::unique_ptr< processor_base_type > processor_holder_type;
  56. #else
  57. typedef std::auto_ptr< processor_base_type > processor_holder_type;
  58. #endif
  59. typedef shared_ptr< processor_holder_type > processor_holder_ptr_type;
  60. public:
  61. //////////////////////////////////////////////////////////////////////////
  62. typedef weak_ptr< processor_holder_type > processor_handle;
  63. class processor_context
  64. {
  65. processor_context(
  66. Scheduler & scheduler, const processor_handle & handle
  67. ) :
  68. scheduler_( scheduler ),
  69. handle_( handle )
  70. {
  71. }
  72. #if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) )
  73. public:
  74. // for some reason Intel 8.0 seems to think that the following functions
  75. // are inaccessible from event_processor<>::event_processor
  76. #endif
  77. Scheduler & my_scheduler() const { return scheduler_; }
  78. const processor_handle & my_handle() const { return handle_; }
  79. #if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) )
  80. private:
  81. #endif
  82. // avoids C4512 (assignment operator could not be generated)
  83. processor_context & operator=( const processor_context & );
  84. Scheduler & scheduler_;
  85. const processor_handle handle_;
  86. friend class processor_container;
  87. friend class event_processor< Scheduler >;
  88. };
  89. template< class Processor >
  90. WorkItem create_processor( processor_handle & handle, Scheduler & scheduler )
  91. {
  92. processor_holder_ptr_type pProcessor = make_processor_holder();
  93. handle = pProcessor;
  94. typedef void ( processor_container::*impl_fun_ptr )(
  95. const processor_holder_ptr_type &, const processor_context & );
  96. impl_fun_ptr pImpl =
  97. &processor_container::template create_processor_impl0< Processor >;
  98. return WorkItem(
  99. boost::bind( pImpl, this, pProcessor,
  100. processor_context( scheduler, handle ) ),
  101. Allocator() );
  102. }
  103. template< class Processor, typename Arg1 >
  104. WorkItem create_processor(
  105. processor_handle & handle, Scheduler & scheduler, Arg1 arg1 )
  106. {
  107. processor_holder_ptr_type pProcessor = make_processor_holder();
  108. handle = pProcessor;
  109. typedef typename detail::unwrap< Arg1 >::type arg1_type;
  110. typedef void ( processor_container::*impl_fun_ptr )(
  111. const processor_holder_ptr_type &, const processor_context &,
  112. arg1_type );
  113. impl_fun_ptr pImpl =
  114. &processor_container::template create_processor_impl1<
  115. Processor, arg1_type >;
  116. return WorkItem(
  117. boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
  118. arg1 ),
  119. Allocator() );
  120. }
  121. template< class Processor, typename Arg1, typename Arg2 >
  122. WorkItem create_processor(
  123. processor_handle & handle, Scheduler & scheduler, Arg1 arg1, Arg2 arg2 )
  124. {
  125. processor_holder_ptr_type pProcessor = make_processor_holder();
  126. handle = pProcessor;
  127. typedef typename detail::unwrap< Arg1 >::type arg1_type;
  128. typedef typename detail::unwrap< Arg2 >::type arg2_type;
  129. typedef void ( processor_container::*impl_fun_ptr )(
  130. const processor_holder_ptr_type &, const processor_context &,
  131. arg1_type, arg2_type );
  132. impl_fun_ptr pImpl =
  133. &processor_container::template create_processor_impl2<
  134. Processor, arg1_type, arg2_type >;
  135. return WorkItem(
  136. boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
  137. arg1, arg2 ),
  138. Allocator() );
  139. }
  140. template< class Processor, typename Arg1, typename Arg2, typename Arg3 >
  141. WorkItem create_processor(
  142. processor_handle & handle, Scheduler & scheduler,
  143. Arg1 arg1, Arg2 arg2, Arg3 arg3 )
  144. {
  145. processor_holder_ptr_type pProcessor = make_processor_holder();
  146. handle = pProcessor;
  147. typedef typename detail::unwrap< Arg1 >::type arg1_type;
  148. typedef typename detail::unwrap< Arg2 >::type arg2_type;
  149. typedef typename detail::unwrap< Arg3 >::type arg3_type;
  150. typedef void ( processor_container::*impl_fun_ptr )(
  151. const processor_holder_ptr_type &, const processor_context &,
  152. arg1_type, arg2_type, arg3_type );
  153. impl_fun_ptr pImpl =
  154. &processor_container::template create_processor_impl3<
  155. Processor, arg1_type, arg2_type, arg3_type >;
  156. return WorkItem(
  157. boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
  158. arg1, arg2, arg3 ),
  159. Allocator() );
  160. }
  161. template<
  162. class Processor, typename Arg1, typename Arg2,
  163. typename Arg3, typename Arg4 >
  164. WorkItem create_processor(
  165. processor_handle & handle, Scheduler & scheduler,
  166. Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 )
  167. {
  168. processor_holder_ptr_type pProcessor = make_processor_holder();
  169. handle = pProcessor;
  170. typedef typename detail::unwrap< Arg1 >::type arg1_type;
  171. typedef typename detail::unwrap< Arg2 >::type arg2_type;
  172. typedef typename detail::unwrap< Arg3 >::type arg3_type;
  173. typedef typename detail::unwrap< Arg4 >::type arg4_type;
  174. typedef void ( processor_container::*impl_fun_ptr )(
  175. const processor_holder_ptr_type &, const processor_context &,
  176. arg1_type, arg2_type, arg3_type, arg4_type );
  177. impl_fun_ptr pImpl =
  178. &processor_container::template create_processor_impl4<
  179. Processor, arg1_type, arg2_type, arg3_type, arg4_type >;
  180. return WorkItem(
  181. boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
  182. arg1, arg2, arg3, arg4 ),
  183. Allocator() );
  184. }
  185. template<
  186. class Processor, typename Arg1, typename Arg2,
  187. typename Arg3, typename Arg4, typename Arg5 >
  188. WorkItem create_processor(
  189. processor_handle & handle, Scheduler & scheduler,
  190. Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 )
  191. {
  192. processor_holder_ptr_type pProcessor = make_processor_holder();
  193. handle = pProcessor;
  194. typedef typename detail::unwrap< Arg1 >::type arg1_type;
  195. typedef typename detail::unwrap< Arg2 >::type arg2_type;
  196. typedef typename detail::unwrap< Arg3 >::type arg3_type;
  197. typedef typename detail::unwrap< Arg4 >::type arg4_type;
  198. typedef typename detail::unwrap< Arg5 >::type arg5_type;
  199. typedef void ( processor_container::*impl_fun_ptr )(
  200. const processor_holder_ptr_type &, const processor_context &,
  201. arg1_type, arg2_type, arg3_type, arg4_type, arg5_type );
  202. impl_fun_ptr pImpl =
  203. &processor_container::template create_processor_impl5<
  204. Processor, arg1_type, arg2_type, arg3_type, arg4_type, arg5_type >;
  205. return WorkItem(
  206. boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
  207. arg1, arg2, arg3, arg4, arg5 ),
  208. Allocator() );
  209. }
  210. template<
  211. class Processor, typename Arg1, typename Arg2,
  212. typename Arg3, typename Arg4, typename Arg5, typename Arg6 >
  213. WorkItem create_processor(
  214. processor_handle & handle, Scheduler & scheduler,
  215. Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 )
  216. {
  217. processor_holder_ptr_type pProcessor = make_processor_holder();
  218. handle = pProcessor;
  219. typedef typename detail::unwrap< Arg1 >::type arg1_type;
  220. typedef typename detail::unwrap< Arg2 >::type arg2_type;
  221. typedef typename detail::unwrap< Arg3 >::type arg3_type;
  222. typedef typename detail::unwrap< Arg4 >::type arg4_type;
  223. typedef typename detail::unwrap< Arg5 >::type arg5_type;
  224. typedef typename detail::unwrap< Arg6 >::type arg6_type;
  225. typedef void ( processor_container::*impl_fun_ptr )(
  226. const processor_holder_ptr_type &, const processor_context &,
  227. arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type );
  228. impl_fun_ptr pImpl =
  229. &processor_container::template create_processor_impl6<
  230. Processor,
  231. arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type >;
  232. return WorkItem(
  233. boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ),
  234. arg1, arg2, arg3, arg4, arg5, arg6 ),
  235. Allocator() );
  236. }
  237. WorkItem destroy_processor( const processor_handle & processor )
  238. {
  239. return WorkItem(
  240. boost::bind( &processor_container::destroy_processor_impl, this, processor ),
  241. Allocator() );
  242. }
  243. WorkItem initiate_processor( const processor_handle & processor )
  244. {
  245. return WorkItem(
  246. boost::bind( &processor_container::initiate_processor_impl, this,
  247. processor ),
  248. Allocator() );
  249. }
  250. WorkItem terminate_processor( const processor_handle & processor )
  251. {
  252. return WorkItem(
  253. boost::bind( &processor_container::terminate_processor_impl, this,
  254. processor ),
  255. Allocator() );
  256. }
  257. typedef intrusive_ptr< const event_base > event_ptr_type;
  258. WorkItem queue_event(
  259. const processor_handle & processor, const event_ptr_type & pEvent )
  260. {
  261. BOOST_ASSERT( pEvent.get() != 0 );
  262. return WorkItem(
  263. boost::bind( &processor_container::queue_event_impl, this, processor,
  264. pEvent ),
  265. Allocator() );
  266. }
  267. private:
  268. //////////////////////////////////////////////////////////////////////////
  269. processor_holder_ptr_type make_processor_holder()
  270. {
  271. return processor_holder_ptr_type( new processor_holder_type() );
  272. }
  273. template< class Processor >
  274. void create_processor_impl0(
  275. const processor_holder_ptr_type & pProcessor,
  276. const processor_context & context )
  277. {
  278. processorSet_.insert( pProcessor );
  279. *pProcessor = processor_holder_type( new Processor( context ) );
  280. }
  281. template< class Processor, typename Arg1 >
  282. void create_processor_impl1(
  283. const processor_holder_ptr_type & pProcessor,
  284. const processor_context & context, Arg1 arg1 )
  285. {
  286. processorSet_.insert( pProcessor );
  287. *pProcessor = processor_holder_type( new Processor( context, arg1 ) );
  288. }
  289. template< class Processor, typename Arg1, typename Arg2 >
  290. void create_processor_impl2(
  291. const processor_holder_ptr_type & pProcessor,
  292. const processor_context & context, Arg1 arg1, Arg2 arg2 )
  293. {
  294. processorSet_.insert( pProcessor );
  295. *pProcessor = processor_holder_type( new Processor( context, arg1, arg2 ) );
  296. }
  297. template< class Processor, typename Arg1, typename Arg2, typename Arg3 >
  298. void create_processor_impl3(
  299. const processor_holder_ptr_type & pProcessor,
  300. const processor_context & context, Arg1 arg1, Arg2 arg2, Arg3 arg3 )
  301. {
  302. processorSet_.insert( pProcessor );
  303. *pProcessor = processor_holder_type( new Processor( context, arg1, arg2, arg3 ) );
  304. }
  305. template<
  306. class Processor, typename Arg1, typename Arg2,
  307. typename Arg3, typename Arg4 >
  308. void create_processor_impl4(
  309. const processor_holder_ptr_type & pProcessor,
  310. const processor_context & context,
  311. Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 )
  312. {
  313. processorSet_.insert( pProcessor );
  314. *pProcessor = processor_holder_type( new Processor( context, arg1, arg2, arg3, arg4 ) );
  315. }
  316. template<
  317. class Processor, typename Arg1, typename Arg2,
  318. typename Arg3, typename Arg4, typename Arg5 >
  319. void create_processor_impl5(
  320. const processor_holder_ptr_type & pProcessor,
  321. const processor_context & context,
  322. Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 )
  323. {
  324. processorSet_.insert( pProcessor );
  325. *pProcessor = processor_holder_type( new Processor( context, arg1, arg2, arg3, arg4, arg5 ) );
  326. }
  327. template<
  328. class Processor, typename Arg1, typename Arg2,
  329. typename Arg3, typename Arg4, typename Arg5, typename Arg6 >
  330. void create_processor_impl6(
  331. const processor_holder_ptr_type & pProcessor,
  332. const processor_context & context,
  333. Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 )
  334. {
  335. processorSet_.insert( pProcessor );
  336. *pProcessor = processor_holder_type( new Processor( context, arg1, arg2, arg3, arg4, arg5, arg6 ) );
  337. }
  338. void destroy_processor_impl( const processor_handle & processor )
  339. {
  340. const processor_holder_ptr_type pProcessor = processor.lock();
  341. if ( pProcessor != 0 )
  342. {
  343. processorSet_.erase( pProcessor );
  344. }
  345. }
  346. void initiate_processor_impl( const processor_handle & processor )
  347. {
  348. const processor_holder_ptr_type pProcessor = processor.lock();
  349. if ( pProcessor != 0 )
  350. {
  351. ( *pProcessor )->initiate();
  352. }
  353. }
  354. void terminate_processor_impl( const processor_handle & processor )
  355. {
  356. const processor_holder_ptr_type pProcessor = processor.lock();
  357. if ( pProcessor != 0 )
  358. {
  359. ( *pProcessor )->terminate();
  360. }
  361. }
  362. void queue_event_impl(
  363. const processor_handle & processor, const event_ptr_type & pEvent )
  364. {
  365. const processor_holder_ptr_type pProcessor = processor.lock();
  366. if ( pProcessor != 0 )
  367. {
  368. ( *pProcessor )->process_event( *pEvent );
  369. }
  370. }
  371. typedef std::set<
  372. processor_holder_ptr_type,
  373. std::less< processor_holder_ptr_type >,
  374. typename boost::detail::allocator::rebind_to<
  375. Allocator, processor_holder_ptr_type >::type
  376. > event_processor_set_type;
  377. event_processor_set_type processorSet_;
  378. };
  379. } // namespace statechart
  380. } // namespace boost
  381. #endif