state_machine.hpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091
  1. #ifndef BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED
  2. #define BOOST_STATECHART_STATE_MACHINE_HPP_INCLUDED
  3. //////////////////////////////////////////////////////////////////////////////
  4. // Copyright 2002-2010 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.hpp>
  9. #include <boost/statechart/null_exception_translator.hpp>
  10. #include <boost/statechart/result.hpp>
  11. #include <boost/statechart/detail/rtti_policy.hpp>
  12. #include <boost/statechart/detail/state_base.hpp>
  13. #include <boost/statechart/detail/leaf_state.hpp>
  14. #include <boost/statechart/detail/node_state.hpp>
  15. #include <boost/statechart/detail/constructor.hpp>
  16. #include <boost/statechart/detail/avoid_unused_warning.hpp>
  17. #include <boost/mpl/list.hpp>
  18. #include <boost/mpl/clear.hpp>
  19. #include <boost/mpl/if.hpp>
  20. #include <boost/mpl/at.hpp>
  21. #include <boost/mpl/integral_c.hpp>
  22. #include <boost/mpl/minus.hpp>
  23. #include <boost/mpl/equal_to.hpp>
  24. #include <boost/intrusive_ptr.hpp>
  25. #include <boost/type_traits/is_pointer.hpp>
  26. #include <boost/type_traits/remove_reference.hpp>
  27. #include <boost/noncopyable.hpp>
  28. #include <boost/assert.hpp>
  29. #include <boost/static_assert.hpp>
  30. #include <boost/polymorphic_cast.hpp> // boost::polymorphic_downcast
  31. // BOOST_NO_EXCEPTIONS, BOOST_MSVC, BOOST_MSVC_STD_ITERATOR
  32. #include <boost/config.hpp>
  33. #include <boost/detail/allocator_utilities.hpp>
  34. #ifdef BOOST_MSVC
  35. # pragma warning( push )
  36. # pragma warning( disable: 4702 ) // unreachable code (in release mode only)
  37. #endif
  38. #include <map>
  39. #ifdef BOOST_MSVC
  40. # pragma warning( pop )
  41. #endif
  42. #include <memory> // std::allocator
  43. #include <typeinfo> // std::bad_cast
  44. #include <functional> // std::less
  45. #include <iterator>
  46. namespace boost
  47. {
  48. namespace statechart
  49. {
  50. namespace detail
  51. {
  52. //////////////////////////////////////////////////////////////////////////////
  53. template< class StateBaseType, class EventBaseType, class IdType >
  54. class send_function
  55. {
  56. public:
  57. //////////////////////////////////////////////////////////////////////////
  58. send_function(
  59. StateBaseType & toState,
  60. const EventBaseType & evt,
  61. IdType eventType
  62. ) :
  63. toState_( toState ), evt_( evt ), eventType_( eventType )
  64. {
  65. }
  66. result operator()()
  67. {
  68. return detail::result_utility::make_result(
  69. toState_.react_impl( evt_, eventType_ ) );
  70. }
  71. private:
  72. //////////////////////////////////////////////////////////////////////////
  73. // avoids C4512 (assignment operator could not be generated)
  74. send_function & operator=( const send_function & );
  75. StateBaseType & toState_;
  76. const EventBaseType & evt_;
  77. IdType eventType_;
  78. };
  79. //////////////////////////////////////////////////////////////////////////////
  80. struct state_cast_impl_pointer_target
  81. {
  82. public:
  83. //////////////////////////////////////////////////////////////////////////
  84. template< class StateBaseType >
  85. static const StateBaseType * deref_if_necessary(
  86. const StateBaseType * pState )
  87. {
  88. return pState;
  89. }
  90. template< class Target, class IdType >
  91. static IdType type_id()
  92. {
  93. Target p = 0;
  94. return type_id_impl< IdType >( p );
  95. }
  96. static bool found( const void * pFound )
  97. {
  98. return pFound != 0;
  99. }
  100. template< class Target >
  101. static Target not_found()
  102. {
  103. return 0;
  104. }
  105. private:
  106. //////////////////////////////////////////////////////////////////////////
  107. template< class IdType, class Type >
  108. static IdType type_id_impl( const Type * )
  109. {
  110. return Type::static_type();
  111. }
  112. };
  113. struct state_cast_impl_reference_target
  114. {
  115. template< class StateBaseType >
  116. static const StateBaseType & deref_if_necessary(
  117. const StateBaseType * pState )
  118. {
  119. return *pState;
  120. }
  121. template< class Target, class IdType >
  122. static IdType type_id()
  123. {
  124. return remove_reference< Target >::type::static_type();
  125. }
  126. template< class Dummy >
  127. static bool found( const Dummy & )
  128. {
  129. return true;
  130. }
  131. template< class Target >
  132. static Target not_found()
  133. {
  134. throw std::bad_cast();
  135. }
  136. };
  137. template< class Target >
  138. struct state_cast_impl : public mpl::if_<
  139. is_pointer< Target >,
  140. state_cast_impl_pointer_target,
  141. state_cast_impl_reference_target
  142. >::type {};
  143. //////////////////////////////////////////////////////////////////////////////
  144. template< class RttiPolicy >
  145. class history_key
  146. {
  147. public:
  148. //////////////////////////////////////////////////////////////////////////
  149. template< class HistorizedState >
  150. static history_key make_history_key()
  151. {
  152. return history_key(
  153. HistorizedState::context_type::static_type(),
  154. HistorizedState::orthogonal_position::value );
  155. }
  156. typename RttiPolicy::id_type history_context_type() const
  157. {
  158. return historyContextType_;
  159. }
  160. friend bool operator<(
  161. const history_key & left, const history_key & right )
  162. {
  163. return
  164. std::less< typename RttiPolicy::id_type >()(
  165. left.historyContextType_, right.historyContextType_ ) ||
  166. ( ( left.historyContextType_ == right.historyContextType_ ) &&
  167. ( left.historizedOrthogonalRegion_ <
  168. right.historizedOrthogonalRegion_ ) );
  169. }
  170. private:
  171. //////////////////////////////////////////////////////////////////////////
  172. history_key(
  173. typename RttiPolicy::id_type historyContextType,
  174. orthogonal_position_type historizedOrthogonalRegion
  175. ) :
  176. historyContextType_( historyContextType ),
  177. historizedOrthogonalRegion_( historizedOrthogonalRegion )
  178. {
  179. }
  180. // avoids C4512 (assignment operator could not be generated)
  181. history_key & operator=( const history_key & );
  182. const typename RttiPolicy::id_type historyContextType_;
  183. const orthogonal_position_type historizedOrthogonalRegion_;
  184. };
  185. } // namespace detail
  186. //////////////////////////////////////////////////////////////////////////////
  187. template< class MostDerived,
  188. class InitialState,
  189. class Allocator = std::allocator< none >,
  190. class ExceptionTranslator = null_exception_translator >
  191. class state_machine : noncopyable
  192. {
  193. public:
  194. //////////////////////////////////////////////////////////////////////////
  195. typedef Allocator allocator_type;
  196. typedef detail::rtti_policy rtti_policy_type;
  197. typedef event_base event_base_type;
  198. typedef intrusive_ptr< const event_base_type > event_base_ptr_type;
  199. void initiate()
  200. {
  201. terminate();
  202. {
  203. terminator guard( *this, 0 );
  204. detail::result_utility::get_result( translator_(
  205. initial_construct_function( *this ),
  206. exception_event_handler( *this ) ) );
  207. guard.dismiss();
  208. }
  209. process_queued_events();
  210. }
  211. void terminate()
  212. {
  213. terminator guard( *this, 0 );
  214. detail::result_utility::get_result( translator_(
  215. terminate_function( *this ),
  216. exception_event_handler( *this ) ) );
  217. guard.dismiss();
  218. }
  219. bool terminated() const
  220. {
  221. return pOutermostState_ == 0;
  222. }
  223. void process_event( const event_base_type & evt )
  224. {
  225. if ( send_event( evt ) == detail::do_defer_event )
  226. {
  227. deferredEventQueue_.push_back( evt.intrusive_from_this() );
  228. }
  229. process_queued_events();
  230. }
  231. template< class Target >
  232. Target state_cast() const
  233. {
  234. typedef detail::state_cast_impl< Target > impl;
  235. for ( typename state_list_type::const_iterator pCurrentLeafState =
  236. currentStates_.begin();
  237. pCurrentLeafState != currentStatesEnd_;
  238. ++pCurrentLeafState )
  239. {
  240. const state_base_type * pCurrentState(
  241. get_pointer( *pCurrentLeafState ) );
  242. while ( pCurrentState != 0 )
  243. {
  244. // The unnecessary try/catch overhead for pointer targets is
  245. // typically small compared to the cycles dynamic_cast needs
  246. #ifndef BOOST_NO_EXCEPTIONS
  247. try
  248. #endif
  249. {
  250. Target result = dynamic_cast< Target >(
  251. impl::deref_if_necessary( pCurrentState ) );
  252. if ( impl::found( result ) )
  253. {
  254. return result;
  255. }
  256. }
  257. #ifndef BOOST_NO_EXCEPTIONS
  258. // Intentionally swallow std::bad_cast exceptions. We'll throw one
  259. // ourselves when we fail to find a state that can be cast to Target
  260. catch ( const std::bad_cast & ) {}
  261. #endif
  262. pCurrentState = pCurrentState->outer_state_ptr();
  263. }
  264. }
  265. return impl::template not_found< Target >();
  266. }
  267. template< class Target >
  268. Target state_downcast() const
  269. {
  270. typedef detail::state_cast_impl< Target > impl;
  271. typename rtti_policy_type::id_type targetType =
  272. impl::template type_id< Target, rtti_policy_type::id_type >();
  273. for ( typename state_list_type::const_iterator pCurrentLeafState =
  274. currentStates_.begin();
  275. pCurrentLeafState != currentStatesEnd_;
  276. ++pCurrentLeafState )
  277. {
  278. const state_base_type * pCurrentState(
  279. get_pointer( *pCurrentLeafState ) );
  280. while ( pCurrentState != 0 )
  281. {
  282. if ( pCurrentState->dynamic_type() == targetType )
  283. {
  284. return static_cast< Target >(
  285. impl::deref_if_necessary( pCurrentState ) );
  286. }
  287. pCurrentState = pCurrentState->outer_state_ptr();
  288. }
  289. }
  290. return impl::template not_found< Target >();
  291. }
  292. typedef detail::state_base< allocator_type, rtti_policy_type >
  293. state_base_type;
  294. class state_iterator : public std::iterator<
  295. std::forward_iterator_tag,
  296. state_base_type, std::ptrdiff_t
  297. #ifndef BOOST_MSVC_STD_ITERATOR
  298. , const state_base_type *, const state_base_type &
  299. #endif
  300. >
  301. {
  302. public:
  303. //////////////////////////////////////////////////////////////////////
  304. explicit state_iterator(
  305. typename state_base_type::state_list_type::const_iterator
  306. baseIterator
  307. ) : baseIterator_( baseIterator ) {}
  308. const state_base_type & operator*() const { return **baseIterator_; }
  309. const state_base_type * operator->() const
  310. {
  311. return &**baseIterator_;
  312. }
  313. state_iterator & operator++() { ++baseIterator_; return *this; }
  314. state_iterator operator++( int )
  315. {
  316. return state_iterator( baseIterator_++ );
  317. }
  318. bool operator==( const state_iterator & right ) const
  319. {
  320. return baseIterator_ == right.baseIterator_;
  321. }
  322. bool operator!=( const state_iterator & right ) const
  323. {
  324. return !( *this == right );
  325. }
  326. private:
  327. typename state_base_type::state_list_type::const_iterator
  328. baseIterator_;
  329. };
  330. state_iterator state_begin() const
  331. {
  332. return state_iterator( currentStates_.begin() );
  333. }
  334. state_iterator state_end() const
  335. {
  336. return state_iterator( currentStatesEnd_ );
  337. }
  338. void unconsumed_event( const event_base & ) {}
  339. protected:
  340. //////////////////////////////////////////////////////////////////////////
  341. state_machine() :
  342. currentStatesEnd_( currentStates_.end() ),
  343. pOutermostState_( 0 ),
  344. isInnermostCommonOuter_( false ),
  345. performFullExit_( true ),
  346. pTriggeringEvent_( 0 )
  347. {
  348. }
  349. // This destructor was only made virtual so that that
  350. // polymorphic_downcast can be used to cast to MostDerived.
  351. virtual ~state_machine()
  352. {
  353. terminate_impl( false );
  354. }
  355. void post_event( const event_base_ptr_type & pEvent )
  356. {
  357. post_event_impl( pEvent );
  358. }
  359. void post_event( const event_base & evt )
  360. {
  361. post_event_impl( evt );
  362. }
  363. public:
  364. //////////////////////////////////////////////////////////////////////////
  365. // The following declarations should be protected.
  366. // They are only public because many compilers lack template friends.
  367. //////////////////////////////////////////////////////////////////////////
  368. template<
  369. class HistoryContext,
  370. detail::orthogonal_position_type orthogonalPosition >
  371. void clear_shallow_history()
  372. {
  373. // If you receive a
  374. // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'" or
  375. // similar compiler error here then you tried to clear shallow history
  376. // for a state that does not have shallow history. That is, the state
  377. // does not pass either statechart::has_shallow_history or
  378. // statechart::has_full_history to its base class template.
  379. BOOST_STATIC_ASSERT( HistoryContext::shallow_history::value );
  380. typedef typename mpl::at_c<
  381. typename HistoryContext::inner_initial_list,
  382. orthogonalPosition >::type historized_state;
  383. store_history_impl(
  384. shallowHistoryMap_,
  385. history_key_type::make_history_key< historized_state >(),
  386. 0 );
  387. }
  388. template<
  389. class HistoryContext,
  390. detail::orthogonal_position_type orthogonalPosition >
  391. void clear_deep_history()
  392. {
  393. // If you receive a
  394. // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE<x>'" or
  395. // similar compiler error here then you tried to clear deep history for
  396. // a state that does not have deep history. That is, the state does not
  397. // pass either statechart::has_deep_history or
  398. // statechart::has_full_history to its base class template
  399. BOOST_STATIC_ASSERT( HistoryContext::deep_history::value );
  400. typedef typename mpl::at_c<
  401. typename HistoryContext::inner_initial_list,
  402. orthogonalPosition >::type historized_state;
  403. store_history_impl(
  404. deepHistoryMap_,
  405. history_key_type::make_history_key< historized_state >(),
  406. 0 );
  407. }
  408. const event_base_type * triggering_event() const
  409. {
  410. return pTriggeringEvent_;
  411. }
  412. public:
  413. //////////////////////////////////////////////////////////////////////////
  414. // The following declarations should be private.
  415. // They are only public because many compilers lack template friends.
  416. //////////////////////////////////////////////////////////////////////////
  417. typedef MostDerived inner_context_type;
  418. typedef mpl::integral_c< detail::orthogonal_position_type, 0 >
  419. inner_orthogonal_position;
  420. typedef mpl::integral_c< detail::orthogonal_position_type, 1 >
  421. no_of_orthogonal_regions;
  422. typedef MostDerived outermost_context_type;
  423. typedef state_machine outermost_context_base_type;
  424. typedef state_machine * inner_context_ptr_type;
  425. typedef typename state_base_type::node_state_base_ptr_type
  426. node_state_base_ptr_type;
  427. typedef typename state_base_type::leaf_state_ptr_type leaf_state_ptr_type;
  428. typedef typename state_base_type::state_list_type state_list_type;
  429. typedef mpl::clear< mpl::list<> >::type context_type_list;
  430. typedef mpl::bool_< false > shallow_history;
  431. typedef mpl::bool_< false > deep_history;
  432. typedef mpl::bool_< false > inherited_deep_history;
  433. void post_event_impl( const event_base_ptr_type & pEvent )
  434. {
  435. BOOST_ASSERT( get_pointer( pEvent ) != 0 );
  436. eventQueue_.push_back( pEvent );
  437. }
  438. void post_event_impl( const event_base & evt )
  439. {
  440. post_event_impl( evt.intrusive_from_this() );
  441. }
  442. detail::reaction_result react_impl(
  443. const event_base_type &,
  444. typename rtti_policy_type::id_type )
  445. {
  446. return detail::do_forward_event;
  447. }
  448. void exit_impl(
  449. inner_context_ptr_type &,
  450. typename state_base_type::node_state_base_ptr_type &,
  451. bool ) {}
  452. void set_outermost_unstable_state(
  453. typename state_base_type::node_state_base_ptr_type &
  454. pOutermostUnstableState )
  455. {
  456. pOutermostUnstableState = 0;
  457. }
  458. // Returns a reference to the context identified by the template
  459. // parameter. This can either be _this_ object or one of its direct or
  460. // indirect contexts.
  461. template< class Context >
  462. Context & context()
  463. {
  464. // As we are in the outermost context here, only this object can be
  465. // returned.
  466. return *polymorphic_downcast< MostDerived * >( this );
  467. }
  468. template< class Context >
  469. const Context & context() const
  470. {
  471. // As we are in the outermost context here, only this object can be
  472. // returned.
  473. return *polymorphic_downcast< const MostDerived * >( this );
  474. }
  475. outermost_context_type & outermost_context()
  476. {
  477. return *polymorphic_downcast< MostDerived * >( this );
  478. }
  479. const outermost_context_type & outermost_context() const
  480. {
  481. return *polymorphic_downcast< const MostDerived * >( this );
  482. }
  483. outermost_context_base_type & outermost_context_base()
  484. {
  485. return *this;
  486. }
  487. const outermost_context_base_type & outermost_context_base() const
  488. {
  489. return *this;
  490. }
  491. void terminate_as_reaction( state_base_type & theState )
  492. {
  493. terminate_impl( theState, performFullExit_ );
  494. pOutermostUnstableState_ = 0;
  495. }
  496. void terminate_as_part_of_transit( state_base_type & theState )
  497. {
  498. terminate_impl( theState, performFullExit_ );
  499. isInnermostCommonOuter_ = true;
  500. }
  501. void terminate_as_part_of_transit( state_machine & )
  502. {
  503. terminate_impl( *pOutermostState_, performFullExit_ );
  504. isInnermostCommonOuter_ = true;
  505. }
  506. template< class State >
  507. void add( const intrusive_ptr< State > & pState )
  508. {
  509. // The second dummy argument is necessary because the call to the
  510. // overloaded function add_impl would otherwise be ambiguous.
  511. node_state_base_ptr_type pNewOutermostUnstableStateCandidate =
  512. add_impl( pState, *pState );
  513. if ( isInnermostCommonOuter_ ||
  514. ( is_in_highest_orthogonal_region< State >() &&
  515. ( get_pointer( pOutermostUnstableState_ ) ==
  516. pState->State::outer_state_ptr() ) ) )
  517. {
  518. isInnermostCommonOuter_ = false;
  519. pOutermostUnstableState_ = pNewOutermostUnstableStateCandidate;
  520. }
  521. }
  522. void add_inner_state(
  523. detail::orthogonal_position_type position,
  524. state_base_type * pOutermostState )
  525. {
  526. BOOST_ASSERT( position == 0 );
  527. detail::avoid_unused_warning( position );
  528. pOutermostState_ = pOutermostState;
  529. }
  530. void remove_inner_state( detail::orthogonal_position_type position )
  531. {
  532. BOOST_ASSERT( position == 0 );
  533. detail::avoid_unused_warning( position );
  534. pOutermostState_ = 0;
  535. }
  536. void release_events()
  537. {
  538. eventQueue_.splice( eventQueue_.begin(), deferredEventQueue_ );
  539. }
  540. template< class HistorizedState >
  541. void store_shallow_history()
  542. {
  543. // 5.2.10.6 declares that reinterpret_casting a function pointer to a
  544. // different function pointer and back must yield the same value. The
  545. // following reinterpret_cast is the first half of such a sequence.
  546. store_history_impl(
  547. shallowHistoryMap_,
  548. history_key_type::make_history_key< HistorizedState >(),
  549. reinterpret_cast< void (*)() >( &HistorizedState::deep_construct ) );
  550. }
  551. template< class DefaultState >
  552. void construct_with_shallow_history(
  553. const typename DefaultState::context_ptr_type & pContext )
  554. {
  555. construct_with_history_impl< DefaultState >(
  556. shallowHistoryMap_, pContext );
  557. }
  558. template< class HistorizedState, class LeafState >
  559. void store_deep_history()
  560. {
  561. typedef typename detail::make_context_list<
  562. typename HistorizedState::context_type,
  563. LeafState >::type history_context_list;
  564. typedef detail::constructor<
  565. history_context_list, outermost_context_base_type > constructor_type;
  566. // 5.2.10.6 declares that reinterpret_casting a function pointer to a
  567. // different function pointer and back must yield the same value. The
  568. // following reinterpret_cast is the first half of such a sequence.
  569. store_history_impl(
  570. deepHistoryMap_,
  571. history_key_type::make_history_key< HistorizedState >(),
  572. reinterpret_cast< void (*)() >( &constructor_type::construct ) );
  573. }
  574. template< class DefaultState >
  575. void construct_with_deep_history(
  576. const typename DefaultState::context_ptr_type & pContext )
  577. {
  578. construct_with_history_impl< DefaultState >(
  579. deepHistoryMap_, pContext );
  580. }
  581. private: // implementation
  582. //////////////////////////////////////////////////////////////////////////
  583. void initial_construct()
  584. {
  585. InitialState::initial_deep_construct(
  586. *polymorphic_downcast< MostDerived * >( this ) );
  587. }
  588. class initial_construct_function
  589. {
  590. public:
  591. //////////////////////////////////////////////////////////////////////
  592. initial_construct_function( state_machine & machine ) :
  593. machine_( machine )
  594. {
  595. }
  596. result operator()()
  597. {
  598. machine_.initial_construct();
  599. return detail::result_utility::make_result(
  600. detail::do_discard_event ); // there is nothing to be consumed
  601. }
  602. private:
  603. //////////////////////////////////////////////////////////////////////
  604. // avoids C4512 (assignment operator could not be generated)
  605. initial_construct_function & operator=(
  606. const initial_construct_function & );
  607. state_machine & machine_;
  608. };
  609. friend class initial_construct_function;
  610. class terminate_function
  611. {
  612. public:
  613. //////////////////////////////////////////////////////////////////////
  614. terminate_function( state_machine & machine ) : machine_( machine ) {}
  615. result operator()()
  616. {
  617. machine_.terminate_impl( true );
  618. return detail::result_utility::make_result(
  619. detail::do_discard_event ); // there is nothing to be consumed
  620. }
  621. private:
  622. //////////////////////////////////////////////////////////////////////
  623. // avoids C4512 (assignment operator could not be generated)
  624. terminate_function & operator=( const terminate_function & );
  625. state_machine & machine_;
  626. };
  627. friend class terminate_function;
  628. template< class ExceptionEvent >
  629. detail::reaction_result handle_exception_event(
  630. const ExceptionEvent & exceptionEvent,
  631. state_base_type * pCurrentState )
  632. {
  633. if ( terminated() )
  634. {
  635. // there is no state that could handle the exception -> bail out
  636. throw;
  637. }
  638. // If we are stable, an event handler has thrown.
  639. // Otherwise, either a state constructor, a transition action or an exit
  640. // function has thrown and the state machine is now in an invalid state.
  641. // This situation can be resolved by the exception event handler
  642. // function by orderly transiting to another state or terminating.
  643. // As a result of this, the machine must not be unstable when this
  644. // function is left.
  645. state_base_type * const pOutermostUnstableState =
  646. get_pointer( pOutermostUnstableState_ );
  647. state_base_type * const pHandlingState = pOutermostUnstableState == 0 ?
  648. pCurrentState : pOutermostUnstableState;
  649. BOOST_ASSERT( pHandlingState != 0 );
  650. terminator guard( *this, &exceptionEvent );
  651. // There is another scope guard up the call stack, which will terminate
  652. // the machine. So this guard only sets the triggering event.
  653. guard.dismiss();
  654. // Setting a member variable to a special value for the duration of a
  655. // call surely looks like a kludge (normally it should be a parameter of
  656. // the call). However, in this case it is unavoidable because the call
  657. // below could result in a call to user code where passing through an
  658. // additional bool parameter is not acceptable.
  659. performFullExit_ = false;
  660. const detail::reaction_result reactionResult = pHandlingState->react_impl(
  661. exceptionEvent, exceptionEvent.dynamic_type() );
  662. // If the above call throws then performFullExit_ will obviously not be
  663. // set back to true. In this case the termination triggered by the
  664. // scope guard further up in the call stack will take care of this.
  665. performFullExit_ = true;
  666. if ( ( reactionResult != detail::do_discard_event ) ||
  667. ( get_pointer( pOutermostUnstableState_ ) != 0 ) )
  668. {
  669. throw;
  670. }
  671. return detail::do_discard_event;
  672. }
  673. class exception_event_handler
  674. {
  675. public:
  676. //////////////////////////////////////////////////////////////////////
  677. exception_event_handler(
  678. state_machine & machine,
  679. state_base_type * pCurrentState = 0
  680. ) :
  681. machine_( machine ),
  682. pCurrentState_( pCurrentState )
  683. {
  684. }
  685. template< class ExceptionEvent >
  686. result operator()(
  687. const ExceptionEvent & exceptionEvent )
  688. {
  689. return detail::result_utility::make_result(
  690. machine_.handle_exception_event(
  691. exceptionEvent, pCurrentState_ ) );
  692. }
  693. private:
  694. //////////////////////////////////////////////////////////////////////
  695. // avoids C4512 (assignment operator could not be generated)
  696. exception_event_handler & operator=(
  697. const exception_event_handler & );
  698. state_machine & machine_;
  699. state_base_type * pCurrentState_;
  700. };
  701. friend class exception_event_handler;
  702. class terminator
  703. {
  704. public:
  705. //////////////////////////////////////////////////////////////////////
  706. terminator(
  707. state_machine & machine, const event_base * pNewTriggeringEvent ) :
  708. machine_( machine ),
  709. pOldTriggeringEvent_(machine_.pTriggeringEvent_),
  710. dismissed_( false )
  711. {
  712. machine_.pTriggeringEvent_ = pNewTriggeringEvent;
  713. }
  714. ~terminator()
  715. {
  716. if ( !dismissed_ ) { machine_.terminate_impl( false ); }
  717. machine_.pTriggeringEvent_ = pOldTriggeringEvent_;
  718. }
  719. void dismiss() { dismissed_ = true; }
  720. private:
  721. //////////////////////////////////////////////////////////////////////
  722. // avoids C4512 (assignment operator could not be generated)
  723. terminator & operator=( const terminator & );
  724. state_machine & machine_;
  725. const event_base_type * const pOldTriggeringEvent_;
  726. bool dismissed_;
  727. };
  728. friend class terminator;
  729. detail::reaction_result send_event( const event_base_type & evt )
  730. {
  731. terminator guard( *this, &evt );
  732. BOOST_ASSERT( get_pointer( pOutermostUnstableState_ ) == 0 );
  733. const typename rtti_policy_type::id_type eventType = evt.dynamic_type();
  734. detail::reaction_result reactionResult = detail::do_forward_event;
  735. for (
  736. typename state_list_type::iterator pState = currentStates_.begin();
  737. ( reactionResult == detail::do_forward_event ) &&
  738. ( pState != currentStatesEnd_ );
  739. ++pState )
  740. {
  741. // CAUTION: The following statement could modify our state list!
  742. // We must not continue iterating if the event was consumed
  743. reactionResult = detail::result_utility::get_result( translator_(
  744. detail::send_function<
  745. state_base_type, event_base_type, rtti_policy_type::id_type >(
  746. **pState, evt, eventType ),
  747. exception_event_handler( *this, get_pointer( *pState ) ) ) );
  748. }
  749. guard.dismiss();
  750. if ( reactionResult == detail::do_forward_event )
  751. {
  752. polymorphic_downcast< MostDerived * >( this )->unconsumed_event( evt );
  753. }
  754. return reactionResult;
  755. }
  756. void process_queued_events()
  757. {
  758. while ( !eventQueue_.empty() )
  759. {
  760. event_base_ptr_type pEvent = eventQueue_.front();
  761. eventQueue_.pop_front();
  762. if ( send_event( *pEvent ) == detail::do_defer_event )
  763. {
  764. deferredEventQueue_.push_back( pEvent );
  765. }
  766. }
  767. }
  768. void terminate_impl( bool performFullExit )
  769. {
  770. performFullExit_ = true;
  771. if ( !terminated() )
  772. {
  773. terminate_impl( *pOutermostState_, performFullExit );
  774. }
  775. eventQueue_.clear();
  776. deferredEventQueue_.clear();
  777. shallowHistoryMap_.clear();
  778. deepHistoryMap_.clear();
  779. }
  780. void terminate_impl( state_base_type & theState, bool performFullExit )
  781. {
  782. isInnermostCommonOuter_ = false;
  783. // If pOutermostUnstableState_ == 0, we know for sure that
  784. // currentStates_.size() > 0, otherwise theState couldn't be alive any
  785. // more
  786. if ( get_pointer( pOutermostUnstableState_ ) != 0 )
  787. {
  788. theState.remove_from_state_list(
  789. currentStatesEnd_, pOutermostUnstableState_, performFullExit );
  790. }
  791. // Optimization: We want to find out whether currentStates_ has size 1
  792. // and if yes use the optimized implementation below. Since
  793. // list<>::size() is implemented quite inefficiently in some std libs
  794. // it is best to just decrement the currentStatesEnd_ here and
  795. // increment it again, if the test failed.
  796. else if ( currentStates_.begin() == --currentStatesEnd_ )
  797. {
  798. // The machine is stable and there is exactly one innermost state.
  799. // The following optimization is only correct for a stable machine
  800. // without orthogonal regions.
  801. leaf_state_ptr_type & pState = *currentStatesEnd_;
  802. pState->exit_impl(
  803. pState, pOutermostUnstableState_, performFullExit );
  804. }
  805. else
  806. {
  807. BOOST_ASSERT( currentStates_.size() > 1 );
  808. // The machine is stable and there are multiple innermost states
  809. theState.remove_from_state_list(
  810. ++currentStatesEnd_, pOutermostUnstableState_, performFullExit );
  811. }
  812. }
  813. node_state_base_ptr_type add_impl(
  814. const leaf_state_ptr_type & pState,
  815. detail::leaf_state< allocator_type, rtti_policy_type > & )
  816. {
  817. if ( currentStatesEnd_ == currentStates_.end() )
  818. {
  819. pState->set_list_position(
  820. currentStates_.insert( currentStatesEnd_, pState ) );
  821. }
  822. else
  823. {
  824. *currentStatesEnd_ = pState;
  825. pState->set_list_position( currentStatesEnd_ );
  826. ++currentStatesEnd_;
  827. }
  828. return 0;
  829. }
  830. node_state_base_ptr_type add_impl(
  831. const node_state_base_ptr_type & pState,
  832. state_base_type & )
  833. {
  834. return pState;
  835. }
  836. template< class State >
  837. static bool is_in_highest_orthogonal_region()
  838. {
  839. return mpl::equal_to<
  840. typename State::orthogonal_position,
  841. mpl::minus<
  842. typename State::context_type::no_of_orthogonal_regions,
  843. mpl::integral_c< detail::orthogonal_position_type, 1 > >
  844. >::value;
  845. }
  846. typedef detail::history_key< rtti_policy_type > history_key_type;
  847. typedef std::map<
  848. history_key_type, void (*)(),
  849. std::less< history_key_type >,
  850. typename boost::detail::allocator::rebind_to<
  851. allocator_type, std::pair< const history_key_type, void (*)() >
  852. >::type
  853. > history_map_type;
  854. void store_history_impl(
  855. history_map_type & historyMap,
  856. const history_key_type & historyId,
  857. void (*pConstructFunction)() )
  858. {
  859. historyMap[ historyId ] = pConstructFunction;
  860. }
  861. template< class DefaultState >
  862. void construct_with_history_impl(
  863. history_map_type & historyMap,
  864. const typename DefaultState::context_ptr_type & pContext )
  865. {
  866. typename history_map_type::iterator pFoundSlot = historyMap.find(
  867. history_key_type::make_history_key< DefaultState >() );
  868. if ( ( pFoundSlot == historyMap.end() ) || ( pFoundSlot->second == 0 ) )
  869. {
  870. // We have never entered this state before or history was cleared
  871. DefaultState::deep_construct(
  872. pContext, *polymorphic_downcast< MostDerived * >( this ) );
  873. }
  874. else
  875. {
  876. typedef void construct_function(
  877. const typename DefaultState::context_ptr_type &,
  878. typename DefaultState::outermost_context_base_type & );
  879. // 5.2.10.6 declares that reinterpret_casting a function pointer to a
  880. // different function pointer and back must yield the same value. The
  881. // following reinterpret_cast is the second half of such a sequence.
  882. construct_function * const pConstructFunction =
  883. reinterpret_cast< construct_function * >( pFoundSlot->second );
  884. (*pConstructFunction)(
  885. pContext, *polymorphic_downcast< MostDerived * >( this ) );
  886. }
  887. }
  888. typedef std::list<
  889. event_base_ptr_type,
  890. typename boost::detail::allocator::rebind_to<
  891. allocator_type, event_base_ptr_type >::type
  892. > event_queue_type;
  893. typedef std::map<
  894. const state_base_type *, event_queue_type,
  895. std::less< const state_base_type * >,
  896. typename boost::detail::allocator::rebind_to<
  897. allocator_type,
  898. std::pair< const state_base_type * const, event_queue_type >
  899. >::type
  900. > deferred_map_type;
  901. event_queue_type eventQueue_;
  902. event_queue_type deferredEventQueue_;
  903. state_list_type currentStates_;
  904. typename state_list_type::iterator currentStatesEnd_;
  905. state_base_type * pOutermostState_;
  906. bool isInnermostCommonOuter_;
  907. node_state_base_ptr_type pOutermostUnstableState_;
  908. ExceptionTranslator translator_;
  909. bool performFullExit_;
  910. history_map_type shallowHistoryMap_;
  911. history_map_type deepHistoryMap_;
  912. const event_base_type * pTriggeringEvent_;
  913. };
  914. } // namespace statechart
  915. } // namespace boost
  916. #endif