1 // Copyright 2008 Christophe Henry 2 // henry UNDERSCORE christophe AT hotmail DOT com 3 // This is an extended version of the state machine available in the boost::mpl library 4 // Distributed under the same license as the original. 5 // Copyright for the original version: 6 // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed 7 // under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at 9 // http://www.boost.org/LICENSE_1_0.txt) 10 11 #ifndef BOOST_MSM_BACK_FAVOR_COMPILE_TIME_H 12 #define BOOST_MSM_BACK_FAVOR_COMPILE_TIME_H 13 14 #include <utility> 15 #include <deque> 16 17 #include <boost/mpl/filter_view.hpp> 18 #include <boost/mpl/for_each.hpp> 19 #include <boost/mpl/bool.hpp> 20 21 #include <boost/msm/common.hpp> 22 #include <boost/msm/back/metafunctions.hpp> 23 #include <boost/msm/back/common_types.hpp> 24 #include <boost/msm/back/dispatch_table.hpp> 25 #include <boost/msm/back/any_event.hpp> 26 27 namespace boost { namespace msm { namespace back 28 { 29 30 #define BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(fsmname) \ 31 namespace boost { namespace msm { namespace back{ \ 32 template<class EventType> \ 33 class holder<EventType,fsmname> : public placeholder \ 34 { \ 35 public: \ 36 holder(EventType const& evt, fsmname& fsm): event_(evt),fsm_(fsm){} \ 37 virtual ::boost::msm::back::HandledEnum process_event() const \ 38 {return fsm_.process_event(event_);} \ 39 private: \ 40 EventType const& event_; \ 41 fsmname& fsm_; \ 42 }; \ 43 template<> \ 44 ::boost::msm::back::HandledEnum fsmname::process_any_event( any_event const& evt)const \ 45 { \ 46 return evt.process_event(); \ 47 } \ 48 }}} 49 50 struct favor_compile_time 51 { 52 typedef int compile_policy; 53 typedef ::boost::mpl::false_ add_forwarding_rows; 54 }; 55 56 // Generates a singleton runtime lookup table that maps current state 57 // to a function that makes the SM take its transition on the given 58 // Event type. 59 template <class Fsm,class Stt, class Event> 60 struct dispatch_table < Fsm, Stt, Event, ::boost::msm::back::favor_compile_time> 61 { 62 private: 63 // This is a table of these function pointers. 64 typedef HandledEnum (*cell)(Fsm&, int,int,Event const&); 65 typedef bool (*guard)(Fsm&, Event const&); 66 67 // Compute the maximum state value in the sm so we know how big 68 // to make the table 69 typedef typename generate_state_set<Stt>::type state_list; 70 BOOST_STATIC_CONSTANT(int, max_state = ( ::boost::mpl::size<state_list>::value)); 71 72 struct chain_row 73 { operator ()boost::msm::back::dispatch_table::chain_row74 HandledEnum operator()(Fsm& fsm, int region,int state,Event const& evt) const 75 { 76 HandledEnum res = HANDLED_FALSE; 77 typename std::deque<cell>::const_iterator it = one_state.begin(); 78 while (it != one_state.end() && res != HANDLED_TRUE) 79 { 80 HandledEnum handled = (*it)(fsm,region,state,evt); 81 // reject is considered as erasing an error (HANDLED_FALSE) 82 if ((HANDLED_FALSE==handled) && (HANDLED_GUARD_REJECT==res) ) 83 res = HANDLED_GUARD_REJECT; 84 else 85 res = handled; 86 ++it; 87 } 88 return res; 89 } 90 std::deque<cell> one_state; 91 }; 92 template <class TransitionState> call_submachineboost::msm::back::dispatch_table93 static HandledEnum call_submachine(Fsm& fsm, int region, int state, Event const& evt) 94 { 95 return (fsm.template get_state<TransitionState&>()).process_any_event 96 ( any_event(evt,fsm.template get_state<TransitionState&>()) ); 97 } 98 // A function object for use with mpl::for_each that stuffs 99 // transitions into cells. 100 struct init_cell 101 { init_cellboost::msm::back::dispatch_table::init_cell102 init_cell(dispatch_table* self_) 103 : self(self_) 104 {} 105 // version for transition event not base of our event 106 template <class Transition> init_event_base_caseboost::msm::back::dispatch_table::init_cell107 void init_event_base_case(Transition const&, ::boost::mpl::true_ const &) const 108 { 109 typedef typename create_stt<Fsm>::type stt; 110 BOOST_STATIC_CONSTANT(int, state_id = 111 (get_state_id<stt,typename Transition::current_state_type>::value)); 112 self->entries[state_id].one_state.push_front(reinterpret_cast<cell>(&Transition::execute)); 113 } 114 // version for transition event base of our event 115 template <class Transition> init_event_base_caseboost::msm::back::dispatch_table::init_cell116 void init_event_base_case(Transition const&, ::boost::mpl::false_ const &) const 117 { 118 typedef typename create_stt<Fsm>::type stt; 119 BOOST_STATIC_CONSTANT(int, state_id = 120 (get_state_id<stt,typename Transition::current_state_type>::value)); 121 self->entries[state_id].one_state.push_front(&Transition::execute); 122 } 123 // Cell initializer function object, used with mpl::for_each 124 template <class Transition> 125 typename ::boost::enable_if<typename has_not_real_row_tag<Transition>::type,void >::type operator ()boost::msm::back::dispatch_table::init_cell126 operator()(Transition const&,boost::msm::back::dummy<0> = 0) const 127 { 128 // version for not real rows. No problem because irrelevant for process_event 129 } 130 template <class Transition> 131 typename ::boost::disable_if<typename has_not_real_row_tag<Transition>::type,void >::type operator ()boost::msm::back::dispatch_table::init_cell132 operator()(Transition const& tr,boost::msm::back::dummy<1> = 0) const 133 { 134 //only if the transition event is a base of our event is the reinterpret_case safe 135 init_event_base_case(tr, 136 ::boost::mpl::bool_< 137 ::boost::is_base_of<typename Transition::transition_event,Event>::type::value>() ); 138 } 139 140 dispatch_table* self; 141 }; 142 143 // Cell default-initializer function object, used with mpl::for_each 144 // initializes with call_no_transition, defer_transition or default_eventless_transition 145 // variant for non-anonymous transitions 146 template <class EventType,class Enable=void> 147 struct default_init_cell 148 { default_init_cellboost::msm::back::dispatch_table::default_init_cell149 default_init_cell(dispatch_table* self_,chain_row* tofill_entries_) 150 : self(self_),tofill_entries(tofill_entries_) 151 {} 152 template <bool deferred,bool composite, int some_dummy=0> 153 struct helper 154 {}; 155 template <int some_dummy> struct helper<true,false,some_dummy> 156 { 157 template <class State> executeboost::msm::back::dispatch_table::default_init_cell::helper158 static void execute(boost::msm::wrap<State> const&,chain_row* tofill) 159 { 160 typedef typename create_stt<Fsm>::type stt; 161 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,State>::value)); 162 cell call_no_transition = &Fsm::defer_transition; 163 tofill[state_id].one_state.push_back(call_no_transition); 164 } 165 }; 166 template <int some_dummy> struct helper<true,true,some_dummy> 167 { 168 template <class State> executeboost::msm::back::dispatch_table::default_init_cell::helper169 static void execute(boost::msm::wrap<State> const&,chain_row* tofill) 170 { 171 typedef typename create_stt<Fsm>::type stt; 172 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,State>::value)); 173 cell call_no_transition = &Fsm::defer_transition; 174 tofill[state_id].one_state.push_back(call_no_transition); 175 } 176 }; 177 template <int some_dummy> struct helper<false,true,some_dummy> 178 { 179 template <class State> executeboost::msm::back::dispatch_table::default_init_cell::helper180 static void execute(boost::msm::wrap<State> const&,chain_row* tofill) 181 { 182 typedef typename create_stt<Fsm>::type stt; 183 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,State>::value)); 184 cell call_no_transition = &call_submachine< State >; 185 tofill[state_id].one_state.push_front(call_no_transition); 186 } 187 }; 188 template <int some_dummy> struct helper<false,false,some_dummy> 189 { 190 template <class State> executeboost::msm::back::dispatch_table::default_init_cell::helper191 static void execute(boost::msm::wrap<State> const&,chain_row* tofill) 192 { 193 typedef typename create_stt<Fsm>::type stt; 194 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,State>::value)); 195 cell call_no_transition = &Fsm::call_no_transition; 196 tofill[state_id].one_state.push_back(call_no_transition); 197 } 198 }; 199 template <class State> operator ()boost::msm::back::dispatch_table::default_init_cell200 void operator()(boost::msm::wrap<State> const& s) 201 { 202 helper<has_state_delayed_event<State,Event>::type::value, 203 is_composite_state<State>::type::value>::execute(s,tofill_entries); 204 } 205 dispatch_table* self; 206 chain_row* tofill_entries; 207 }; 208 209 // variant for anonymous transitions 210 template <class EventType> 211 struct default_init_cell<EventType, 212 typename ::boost::enable_if< 213 typename is_completion_event<EventType>::type>::type> 214 { default_init_cellboost::msm::back::dispatch_table::default_init_cell215 default_init_cell(dispatch_table* self_,chain_row* tofill_entries_) 216 : self(self_),tofill_entries(tofill_entries_) 217 {} 218 219 // this event is a compound one (not a real one, just one for use in event-less transitions) 220 // Note this event cannot be used as deferred! 221 template <class State> operator ()boost::msm::back::dispatch_table::default_init_cell222 void operator()(boost::msm::wrap<State> const&) 223 { 224 typedef typename create_stt<Fsm>::type stt; 225 BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<stt,State>::value)); 226 cell call_no_transition = &Fsm::default_eventless_transition; 227 tofill_entries[state_id].one_state.push_back(call_no_transition); 228 } 229 230 dispatch_table* self; 231 chain_row* tofill_entries; 232 }; 233 234 public: 235 // initialize the dispatch table for a given Event and Fsm dispatch_tableboost::msm::back::dispatch_table236 dispatch_table() 237 { 238 // Initialize cells for no transition 239 ::boost::mpl::for_each< 240 ::boost::mpl::filter_view< 241 Stt, ::boost::is_base_of<transition_event< ::boost::mpl::placeholders::_>, Event> > > 242 (init_cell(this)); 243 244 ::boost::mpl::for_each< 245 typename generate_state_set<Stt>::type, 246 boost::msm::wrap< ::boost::mpl::placeholders::_1> > 247 (default_init_cell<Event>(this,entries)); 248 249 } 250 251 // The singleton instance. 252 static const dispatch_table instance; 253 254 public: // data members 255 chain_row entries[max_state]; 256 }; 257 258 template <class Fsm,class Stt, class Event> 259 const boost::msm::back::dispatch_table<Fsm,Stt, Event,favor_compile_time> 260 dispatch_table<Fsm,Stt, Event,favor_compile_time>::instance; 261 262 }}} // boost::msm::back 263 264 #endif //BOOST_MSM_BACK_FAVOR_COMPILE_TIME_H 265