]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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_METAFUNCTIONS_H | |
12 | #define BOOST_MSM_BACK_METAFUNCTIONS_H | |
13 | ||
14 | #include <boost/mpl/set.hpp> | |
15 | #include <boost/mpl/at.hpp> | |
16 | #include <boost/mpl/pair.hpp> | |
17 | #include <boost/mpl/map.hpp> | |
18 | #include <boost/mpl/int.hpp> | |
19 | #include <boost/mpl/has_xxx.hpp> | |
20 | #include <boost/mpl/find.hpp> | |
21 | #include <boost/mpl/count_if.hpp> | |
22 | #include <boost/mpl/fold.hpp> | |
23 | #include <boost/mpl/if.hpp> | |
24 | #include <boost/mpl/has_key.hpp> | |
25 | #include <boost/mpl/insert.hpp> | |
26 | #include <boost/mpl/next_prior.hpp> | |
27 | #include <boost/mpl/map.hpp> | |
28 | #include <boost/mpl/push_back.hpp> | |
29 | #include <boost/mpl/vector.hpp> | |
30 | #include <boost/mpl/is_sequence.hpp> | |
31 | #include <boost/mpl/size.hpp> | |
32 | #include <boost/mpl/transform.hpp> | |
33 | #include <boost/mpl/begin_end.hpp> | |
34 | #include <boost/mpl/bool.hpp> | |
35 | #include <boost/mpl/empty.hpp> | |
36 | #include <boost/mpl/identity.hpp> | |
37 | #include <boost/mpl/eval_if.hpp> | |
38 | #include <boost/mpl/insert_range.hpp> | |
39 | #include <boost/mpl/front.hpp> | |
40 | #include <boost/mpl/logical.hpp> | |
41 | #include <boost/mpl/plus.hpp> | |
42 | #include <boost/mpl/copy_if.hpp> | |
43 | #include <boost/mpl/back_inserter.hpp> | |
44 | #include <boost/mpl/transform.hpp> | |
45 | ||
46 | #include <boost/type_traits/is_same.hpp> | |
47 | #include <boost/utility/enable_if.hpp> | |
48 | ||
49 | #include <boost/msm/row_tags.hpp> | |
50 | ||
51 | // mpl_graph graph implementation and depth first search | |
52 | #include <boost/msm/mpl_graph/incidence_list_graph.hpp> | |
53 | #include <boost/msm/mpl_graph/depth_first_search.hpp> | |
54 | ||
55 | BOOST_MPL_HAS_XXX_TRAIT_DEF(explicit_creation) | |
56 | BOOST_MPL_HAS_XXX_TRAIT_DEF(pseudo_entry) | |
57 | BOOST_MPL_HAS_XXX_TRAIT_DEF(pseudo_exit) | |
58 | BOOST_MPL_HAS_XXX_TRAIT_DEF(concrete_exit_state) | |
59 | BOOST_MPL_HAS_XXX_TRAIT_DEF(composite_tag) | |
60 | BOOST_MPL_HAS_XXX_TRAIT_DEF(not_real_row_tag) | |
61 | BOOST_MPL_HAS_XXX_TRAIT_DEF(event_blocking_flag) | |
62 | BOOST_MPL_HAS_XXX_TRAIT_DEF(explicit_entry_state) | |
63 | BOOST_MPL_HAS_XXX_TRAIT_DEF(completion_event) | |
64 | BOOST_MPL_HAS_XXX_TRAIT_DEF(no_exception_thrown) | |
65 | BOOST_MPL_HAS_XXX_TRAIT_DEF(no_message_queue) | |
66 | BOOST_MPL_HAS_XXX_TRAIT_DEF(activate_deferred_events) | |
67 | BOOST_MPL_HAS_XXX_TRAIT_DEF(wrapped_entry) | |
68 | BOOST_MPL_HAS_XXX_TRAIT_DEF(active_state_switch_policy) | |
69 | ||
70 | namespace boost { namespace msm { namespace back | |
71 | { | |
72 | template <typename Sequence, typename Range> | |
73 | struct set_insert_range | |
74 | { | |
75 | typedef typename ::boost::mpl::fold< | |
76 | Range,Sequence, | |
77 | ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 > | |
78 | >::type type; | |
79 | }; | |
80 | ||
81 | // returns the current state type of a transition | |
82 | template <class Transition> | |
83 | struct transition_source_type | |
84 | { | |
85 | typedef typename Transition::current_state_type type; | |
86 | }; | |
87 | ||
88 | // returns the target state type of a transition | |
89 | template <class Transition> | |
90 | struct transition_target_type | |
91 | { | |
92 | typedef typename Transition::next_state_type type; | |
93 | }; | |
94 | ||
95 | // helper functions for generate_state_ids | |
96 | // create a pair of a state and a passed id for source and target states | |
97 | template <class Id,class Transition> | |
98 | struct make_pair_source_state_id | |
99 | { | |
100 | typedef typename ::boost::mpl::pair<typename Transition::current_state_type,Id> type; | |
101 | }; | |
102 | template <class Id,class Transition> | |
103 | struct make_pair_target_state_id | |
104 | { | |
105 | typedef typename ::boost::mpl::pair<typename Transition::next_state_type,Id> type; | |
106 | }; | |
107 | ||
108 | // iterates through a transition table and automatically generates ids starting at 0 | |
109 | // first the source states, transition up to down | |
110 | // then the target states, up to down | |
111 | template <class stt> | |
112 | struct generate_state_ids | |
113 | { | |
114 | typedef typename | |
115 | ::boost::mpl::fold< | |
116 | stt,::boost::mpl::pair< ::boost::mpl::map< >, ::boost::mpl::int_<0> >, | |
117 | ::boost::mpl::pair< | |
118 | ::boost::mpl::if_< | |
119 | ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>, | |
120 | transition_source_type< ::boost::mpl::placeholders::_2> >, | |
121 | ::boost::mpl::first< ::boost::mpl::placeholders::_1>, | |
122 | ::boost::mpl::insert< ::boost::mpl::first<mpl::placeholders::_1>, | |
123 | make_pair_source_state_id< ::boost::mpl::second< ::boost::mpl::placeholders::_1 >, | |
124 | ::boost::mpl::placeholders::_2> > | |
125 | >, | |
126 | ::boost::mpl::if_< | |
127 | ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>, | |
128 | transition_source_type< ::boost::mpl::placeholders::_2> >, | |
129 | ::boost::mpl::second< ::boost::mpl::placeholders::_1 >, | |
130 | ::boost::mpl::next< ::boost::mpl::second<mpl::placeholders::_1 > > | |
131 | > | |
132 | > //pair | |
133 | >::type source_state_ids; | |
134 | typedef typename ::boost::mpl::first<source_state_ids>::type source_state_map; | |
135 | typedef typename ::boost::mpl::second<source_state_ids>::type highest_state_id; | |
136 | ||
137 | ||
138 | typedef typename | |
139 | ::boost::mpl::fold< | |
140 | stt,::boost::mpl::pair<source_state_map,highest_state_id >, | |
141 | ::boost::mpl::pair< | |
142 | ::boost::mpl::if_< | |
143 | ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>, | |
144 | transition_target_type< ::boost::mpl::placeholders::_2> >, | |
145 | ::boost::mpl::first< ::boost::mpl::placeholders::_1>, | |
146 | ::boost::mpl::insert< ::boost::mpl::first< ::boost::mpl::placeholders::_1>, | |
147 | make_pair_target_state_id< ::boost::mpl::second< ::boost::mpl::placeholders::_1 >, | |
148 | ::boost::mpl::placeholders::_2> > | |
149 | >, | |
150 | ::boost::mpl::if_< | |
151 | ::boost::mpl::has_key< ::boost::mpl::first< ::boost::mpl::placeholders::_1>, | |
152 | transition_target_type< ::boost::mpl::placeholders::_2> >, | |
153 | ::boost::mpl::second< ::boost::mpl::placeholders::_1 >, | |
154 | ::boost::mpl::next< ::boost::mpl::second< ::boost::mpl::placeholders::_1 > > | |
155 | > | |
156 | > //pair | |
157 | >::type all_state_ids; | |
158 | typedef typename ::boost::mpl::first<all_state_ids>::type type; | |
159 | }; | |
160 | ||
161 | template <class Fsm> | |
162 | struct get_active_state_switch_policy_helper | |
163 | { | |
164 | typedef typename Fsm::active_state_switch_policy type; | |
165 | }; | |
166 | template <class Iter> | |
167 | struct get_active_state_switch_policy_helper2 | |
168 | { | |
169 | typedef typename boost::mpl::deref<Iter>::type Fsm; | |
170 | typedef typename Fsm::active_state_switch_policy type; | |
171 | }; | |
172 | // returns the active state switching policy | |
173 | template <class Fsm> | |
174 | struct get_active_state_switch_policy | |
175 | { | |
176 | typedef typename ::boost::mpl::find_if< | |
177 | typename Fsm::configuration, | |
178 | has_active_state_switch_policy< ::boost::mpl::placeholders::_1 > >::type iter; | |
179 | ||
180 | typedef typename ::boost::mpl::eval_if< | |
181 | typename ::boost::is_same< | |
182 | iter, | |
183 | typename ::boost::mpl::end<typename Fsm::configuration>::type | |
184 | >::type, | |
185 | get_active_state_switch_policy_helper<Fsm>, | |
186 | get_active_state_switch_policy_helper2< iter > | |
187 | >::type type; | |
188 | }; | |
189 | ||
190 | // returns the id of a given state | |
191 | template <class stt,class State> | |
192 | struct get_state_id | |
193 | { | |
194 | typedef typename ::boost::mpl::at<typename generate_state_ids<stt>::type,State>::type type; | |
195 | enum {value = type::value}; | |
196 | }; | |
197 | ||
198 | // returns a mpl::vector containing the init states of a state machine | |
199 | template <class States> | |
200 | struct get_initial_states | |
201 | { | |
202 | typedef typename ::boost::mpl::if_< | |
203 | ::boost::mpl::is_sequence<States>, | |
204 | States, | |
205 | typename ::boost::mpl::push_back< ::boost::mpl::vector0<>,States>::type >::type type; | |
206 | }; | |
207 | // returns a mpl::int_ containing the size of a region. If the argument is not a sequence, returns 1 | |
208 | template <class region> | |
209 | struct get_number_of_regions | |
210 | { | |
211 | typedef typename mpl::if_< | |
212 | ::boost::mpl::is_sequence<region>, | |
213 | ::boost::mpl::size<region>, | |
214 | ::boost::mpl::int_<1> >::type type; | |
215 | }; | |
216 | ||
217 | // builds a mpl::vector of initial states | |
218 | //TODO remove duplicate from get_initial_states | |
219 | template <class region> | |
220 | struct get_regions_as_sequence | |
221 | { | |
222 | typedef typename ::boost::mpl::if_< | |
223 | ::boost::mpl::is_sequence<region>, | |
224 | region, | |
225 | typename ::boost::mpl::push_back< ::boost::mpl::vector0<>,region>::type >::type type; | |
226 | }; | |
227 | ||
228 | template <class ToCreateSeq> | |
229 | struct get_explicit_creation_as_sequence | |
230 | { | |
231 | typedef typename ::boost::mpl::if_< | |
232 | ::boost::mpl::is_sequence<ToCreateSeq>, | |
233 | ToCreateSeq, | |
234 | typename ::boost::mpl::push_back< ::boost::mpl::vector0<>,ToCreateSeq>::type >::type type; | |
235 | }; | |
236 | ||
237 | // returns true if 2 transitions have the same source (used to remove duplicates in search of composite states) | |
238 | template <class stt,class Transition1,class Transition2> | |
239 | struct have_same_source | |
240 | { | |
241 | enum {current_state1 = get_state_id<stt,typename Transition1::current_state_type >::type::value}; | |
242 | enum {current_state2 = get_state_id<stt,typename Transition2::current_state_type >::type::value}; | |
243 | enum {value = ((int)current_state1 == (int)current_state2) }; | |
244 | }; | |
245 | ||
246 | ||
247 | // A metafunction that returns the Event associated with a transition. | |
248 | template <class Transition> | |
249 | struct transition_event | |
250 | { | |
251 | typedef typename Transition::transition_event type; | |
252 | }; | |
253 | ||
254 | // returns true for composite states | |
255 | template <class State> | |
256 | struct is_composite_state | |
257 | { | |
258 | enum {value = has_composite_tag<State>::type::value}; | |
259 | typedef typename has_composite_tag<State>::type type; | |
260 | }; | |
261 | ||
262 | // transform a transition table in a container of source states | |
263 | template <class stt> | |
264 | struct keep_source_names | |
265 | { | |
266 | // instead of the rows we want only the names of the states (from source) | |
267 | typedef typename | |
268 | ::boost::mpl::transform< | |
269 | stt,transition_source_type< ::boost::mpl::placeholders::_1> >::type type; | |
270 | }; | |
271 | ||
272 | // transform a transition table in a container of target states | |
273 | template <class stt> | |
274 | struct keep_target_names | |
275 | { | |
276 | // instead of the rows we want only the names of the states (from source) | |
277 | typedef typename | |
278 | ::boost::mpl::transform< | |
279 | stt,transition_target_type< ::boost::mpl::placeholders::_1> >::type type; | |
280 | }; | |
281 | ||
282 | template <class stt> | |
283 | struct generate_state_set | |
284 | { | |
285 | // keep in the original transition table only the source/target state types | |
286 | typedef typename keep_source_names<stt>::type sources; | |
287 | typedef typename keep_target_names<stt>::type targets; | |
288 | typedef typename | |
289 | ::boost::mpl::fold< | |
290 | sources, ::boost::mpl::set<>, | |
291 | ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2> | |
292 | >::type source_set; | |
293 | typedef typename | |
294 | ::boost::mpl::fold< | |
295 | targets,source_set, | |
296 | ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2> | |
297 | >::type type; | |
298 | }; | |
299 | ||
300 | // iterates through the transition table and generate a mpl::set<> containing all the events | |
301 | template <class stt> | |
302 | struct generate_event_set | |
303 | { | |
304 | typedef typename | |
305 | ::boost::mpl::fold< | |
306 | stt, ::boost::mpl::set<>, | |
307 | ::boost::mpl::if_< | |
308 | ::boost::mpl::has_key< ::boost::mpl::placeholders::_1, | |
309 | transition_event< ::boost::mpl::placeholders::_2> >, | |
310 | ::boost::mpl::placeholders::_1, | |
311 | ::boost::mpl::insert< ::boost::mpl::placeholders::_1, | |
312 | transition_event< ::boost::mpl::placeholders::_2> > > | |
313 | >::type type; | |
314 | }; | |
315 | ||
316 | // returns a mpl::bool_<true> if State has Event as deferred event | |
317 | template <class State, class Event> | |
318 | struct has_state_delayed_event | |
319 | { | |
320 | typedef typename ::boost::mpl::find<typename State::deferred_events,Event>::type found; | |
321 | typedef typename ::boost::mpl::if_< | |
322 | ::boost::is_same<found,typename ::boost::mpl::end<typename State::deferred_events>::type >, | |
323 | ::boost::mpl::bool_<false>, | |
324 | ::boost::mpl::bool_<true> >::type type; | |
325 | }; | |
326 | // returns a mpl::bool_<true> if State has any deferred event | |
327 | template <class State> | |
328 | struct has_state_delayed_events | |
329 | { | |
330 | typedef typename ::boost::mpl::if_< | |
331 | ::boost::mpl::empty<typename State::deferred_events>, | |
332 | ::boost::mpl::bool_<false>, | |
333 | ::boost::mpl::bool_<true> >::type type; | |
334 | }; | |
335 | ||
336 | // Template used to create dummy entries for initial states not found in the stt. | |
337 | template< typename T1 > | |
338 | struct not_a_row | |
339 | { | |
340 | typedef int not_real_row_tag; | |
341 | struct dummy_event | |
342 | { | |
343 | }; | |
344 | typedef T1 current_state_type; | |
345 | typedef T1 next_state_type; | |
346 | typedef dummy_event transition_event; | |
347 | }; | |
348 | ||
349 | // metafunctions used to find out if a state is entry, exit or something else | |
350 | template <class State> | |
351 | struct is_pseudo_entry | |
352 | { | |
353 | typedef typename ::boost::mpl::if_< typename has_pseudo_entry<State>::type, | |
354 | ::boost::mpl::bool_<true>,::boost::mpl::bool_<false> | |
355 | >::type type; | |
356 | }; | |
357 | // says if a state is an exit pseudo state | |
358 | template <class State> | |
359 | struct is_pseudo_exit | |
360 | { | |
361 | typedef typename ::boost::mpl::if_< typename has_pseudo_exit<State>::type, | |
362 | ::boost::mpl::bool_<true>, ::boost::mpl::bool_<false> | |
363 | >::type type; | |
364 | }; | |
365 | // says if a state is an entry pseudo state or an explicit entry | |
366 | template <class State> | |
367 | struct is_direct_entry | |
368 | { | |
369 | typedef typename ::boost::mpl::if_< typename has_explicit_entry_state<State>::type, | |
370 | ::boost::mpl::bool_<true>, ::boost::mpl::bool_<false> | |
371 | >::type type; | |
372 | }; | |
373 | ||
374 | //converts a "fake" (simulated in a state_machine_ description )state into one which will really get created | |
375 | template <class StateType,class CompositeType> | |
376 | struct convert_fake_state | |
377 | { | |
378 | // converts a state (explicit entry) into the state we really are going to create (explicit<>) | |
379 | typedef typename ::boost::mpl::if_< | |
380 | typename is_direct_entry<StateType>::type, | |
381 | typename CompositeType::template direct<StateType>, | |
382 | typename ::boost::mpl::identity<StateType>::type | |
383 | >::type type; | |
384 | }; | |
385 | ||
386 | template <class StateType> | |
387 | struct get_explicit_creation | |
388 | { | |
389 | typedef typename StateType::explicit_creation type; | |
390 | }; | |
391 | ||
392 | template <class StateType> | |
393 | struct get_wrapped_entry | |
394 | { | |
395 | typedef typename StateType::wrapped_entry type; | |
396 | }; | |
397 | // used for states created with explicit_creation | |
398 | // if the state is an explicit entry, we reach for the wrapped state | |
399 | // otherwise, this returns the state itself | |
400 | template <class StateType> | |
401 | struct get_wrapped_state | |
402 | { | |
403 | typedef typename ::boost::mpl::eval_if< | |
404 | typename has_wrapped_entry<StateType>::type, | |
405 | get_wrapped_entry<StateType>, | |
406 | ::boost::mpl::identity<StateType> >::type type; | |
407 | }; | |
408 | ||
409 | template <class Derived> | |
410 | struct create_stt | |
411 | { | |
412 | //typedef typename Derived::transition_table stt; | |
413 | typedef typename Derived::real_transition_table Stt; | |
414 | // get the state set | |
415 | typedef typename generate_state_set<Stt>::type states; | |
416 | // transform the initial region(s) in a sequence | |
417 | typedef typename get_regions_as_sequence<typename Derived::initial_state>::type init_states; | |
418 | // iterate through the initial states and add them in the stt if not already there | |
419 | typedef typename | |
420 | ::boost::mpl::fold< | |
421 | init_states,Stt, | |
422 | ::boost::mpl::if_< | |
423 | ::boost::mpl::has_key<states, ::boost::mpl::placeholders::_2>, | |
424 | ::boost::mpl::placeholders::_1, | |
425 | ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::end< ::boost::mpl::placeholders::_1>, | |
426 | not_a_row< get_wrapped_state< ::boost::mpl::placeholders::_2> > > | |
427 | > | |
428 | >::type with_init; | |
429 | // do the same for states marked as explicitly created | |
430 | typedef typename get_explicit_creation_as_sequence< | |
431 | typename ::boost::mpl::eval_if< | |
432 | typename has_explicit_creation<Derived>::type, | |
433 | get_explicit_creation<Derived>, | |
434 | ::boost::mpl::vector0<> >::type | |
435 | >::type fake_explicit_created; | |
436 | ||
437 | typedef typename | |
438 | ::boost::mpl::transform< | |
439 | fake_explicit_created,convert_fake_state< ::boost::mpl::placeholders::_1,Derived> >::type explicit_created; | |
440 | ||
441 | typedef typename | |
442 | ::boost::mpl::fold< | |
443 | explicit_created,with_init, | |
444 | ::boost::mpl::if_< | |
445 | ::boost::mpl::has_key<states, ::boost::mpl::placeholders::_2>, | |
446 | ::boost::mpl::placeholders::_1, | |
447 | ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::end<mpl::placeholders::_1>, | |
448 | not_a_row< get_wrapped_state< ::boost::mpl::placeholders::_2> > > | |
449 | > | |
450 | >::type type; | |
451 | }; | |
452 | ||
453 | // returns the transition table of a Composite state | |
454 | template <class Composite> | |
455 | struct get_transition_table | |
456 | { | |
457 | typedef typename create_stt<Composite>::type type; | |
458 | }; | |
459 | ||
460 | // recursively builds an internal table including those of substates, sub-substates etc. | |
461 | // variant for submachines | |
462 | template <class StateType,class IsComposite> | |
463 | struct recursive_get_internal_transition_table | |
464 | { | |
465 | // get the composite's internal table | |
466 | typedef typename StateType::internal_transition_table composite_table; | |
467 | // and for every substate (state of submachine), recursively get the internal transition table | |
468 | typedef typename generate_state_set<typename StateType::stt>::type composite_states; | |
469 | typedef typename ::boost::mpl::fold< | |
470 | composite_states, composite_table, | |
471 | ::boost::mpl::insert_range< ::boost::mpl::placeholders::_1, ::boost::mpl::end< ::boost::mpl::placeholders::_1>, | |
472 | recursive_get_internal_transition_table< ::boost::mpl::placeholders::_2, is_composite_state< ::boost::mpl::placeholders::_2> > | |
473 | > | |
474 | >::type type; | |
475 | }; | |
476 | // stop iterating on leafs (simple states) | |
477 | template <class StateType> | |
478 | struct recursive_get_internal_transition_table<StateType, ::boost::mpl::false_ > | |
479 | { | |
480 | typedef typename StateType::internal_transition_table type; | |
481 | }; | |
482 | // recursively get a transition table for a given composite state. | |
483 | // returns the transition table for this state + the tables of all composite sub states recursively | |
484 | template <class Composite> | |
485 | struct recursive_get_transition_table | |
486 | { | |
487 | // get the transition table of the state if it's a state machine | |
488 | typedef typename ::boost::mpl::eval_if<typename is_composite_state<Composite>::type, | |
489 | get_transition_table<Composite>, | |
490 | ::boost::mpl::vector0<> | |
491 | >::type org_table; | |
492 | ||
493 | typedef typename generate_state_set<org_table>::type states; | |
494 | ||
495 | // and for every substate, recursively get the transition table if it's a state machine | |
496 | typedef typename ::boost::mpl::fold< | |
497 | states,org_table, | |
498 | ::boost::mpl::insert_range< ::boost::mpl::placeholders::_1, ::boost::mpl::end<mpl::placeholders::_1>, | |
499 | recursive_get_transition_table< ::boost::mpl::placeholders::_2 > > | |
500 | >::type type; | |
501 | ||
502 | }; | |
503 | ||
504 | // metafunction used to say if a SM has pseudo exit states | |
505 | template <class Derived> | |
506 | struct has_fsm_deferred_events | |
507 | { | |
508 | typedef typename create_stt<Derived>::type Stt; | |
509 | typedef typename generate_state_set<Stt>::type state_list; | |
510 | ||
511 | typedef typename ::boost::mpl::or_< | |
512 | typename has_activate_deferred_events<Derived>::type, | |
513 | ::boost::mpl::bool_< ::boost::mpl::count_if< | |
514 | typename Derived::configuration, | |
515 | has_activate_deferred_events< ::boost::mpl::placeholders::_1 > >::value != 0> | |
516 | >::type found_in_fsm; | |
517 | ||
518 | typedef typename ::boost::mpl::or_< | |
519 | found_in_fsm, | |
520 | ::boost::mpl::bool_< ::boost::mpl::count_if< | |
521 | state_list,has_state_delayed_events< | |
522 | ::boost::mpl::placeholders::_1 > >::value != 0> | |
523 | >::type type; | |
524 | }; | |
525 | ||
526 | // returns a mpl::bool_<true> if State has any delayed event | |
527 | template <class Event> | |
528 | struct is_completion_event | |
529 | { | |
530 | typedef typename ::boost::mpl::if_< | |
531 | has_completion_event<Event>, | |
532 | ::boost::mpl::bool_<true>, | |
533 | ::boost::mpl::bool_<false> >::type type; | |
534 | }; | |
535 | // metafunction used to say if a SM has eventless transitions | |
536 | template <class Derived> | |
537 | struct has_fsm_eventless_transition | |
538 | { | |
539 | typedef typename create_stt<Derived>::type Stt; | |
540 | typedef typename generate_event_set<Stt>::type event_list; | |
541 | ||
542 | typedef ::boost::mpl::bool_< ::boost::mpl::count_if< | |
543 | event_list,is_completion_event< ::boost::mpl::placeholders::_1 > >::value != 0> type; | |
544 | }; | |
545 | template <class Derived> | |
546 | struct find_completion_events | |
547 | { | |
548 | typedef typename create_stt<Derived>::type Stt; | |
549 | typedef typename generate_event_set<Stt>::type event_list; | |
550 | ||
551 | typedef typename ::boost::mpl::fold< | |
552 | event_list, ::boost::mpl::set<>, | |
553 | ::boost::mpl::if_< | |
554 | is_completion_event< ::boost::mpl::placeholders::_2>, | |
555 | ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >, | |
556 | ::boost::mpl::placeholders::_1 > | |
557 | >::type type; | |
558 | }; | |
559 | ||
560 | template <class Transition> | |
561 | struct make_vector | |
562 | { | |
563 | typedef ::boost::mpl::vector<Transition> type; | |
564 | }; | |
565 | template< typename Entry > | |
566 | struct get_first_element_pair_second | |
567 | { | |
568 | typedef typename ::boost::mpl::front<typename Entry::second>::type type; | |
569 | }; | |
570 | ||
571 | //returns the owner of an explicit_entry state | |
572 | //which is the containing SM if the transition originates from outside the containing SM | |
573 | //or else the explicit_entry state itself | |
574 | template <class State,class ContainingSM> | |
575 | struct get_owner | |
576 | { | |
577 | typedef typename ::boost::mpl::if_< | |
578 | typename ::boost::mpl::not_<typename ::boost::is_same<typename State::owner, | |
579 | ContainingSM >::type>::type, | |
580 | typename State::owner, | |
581 | State >::type type; | |
582 | }; | |
583 | ||
584 | template <class Sequence,class ContainingSM> | |
585 | struct get_fork_owner | |
586 | { | |
587 | typedef typename ::boost::mpl::front<Sequence>::type seq_front; | |
588 | typedef typename ::boost::mpl::if_< | |
589 | typename ::boost::mpl::not_< | |
590 | typename ::boost::is_same<typename seq_front::owner,ContainingSM>::type>::type, | |
591 | typename seq_front::owner, | |
592 | seq_front >::type type; | |
593 | }; | |
594 | ||
595 | template <class StateType,class ContainingSM> | |
596 | struct make_exit | |
597 | { | |
598 | typedef typename ::boost::mpl::if_< | |
599 | typename is_pseudo_exit<StateType>::type , | |
600 | typename ContainingSM::template exit_pt<StateType>, | |
601 | typename ::boost::mpl::identity<StateType>::type | |
602 | >::type type; | |
603 | }; | |
604 | ||
605 | template <class StateType,class ContainingSM> | |
606 | struct make_entry | |
607 | { | |
608 | typedef typename ::boost::mpl::if_< | |
609 | typename is_pseudo_entry<StateType>::type , | |
610 | typename ContainingSM::template entry_pt<StateType>, | |
611 | typename ::boost::mpl::if_< | |
612 | typename is_direct_entry<StateType>::type, | |
613 | typename ContainingSM::template direct<StateType>, | |
614 | typename ::boost::mpl::identity<StateType>::type | |
615 | >::type | |
616 | >::type type; | |
617 | }; | |
618 | // metafunction used to say if a SM has pseudo exit states | |
619 | template <class StateType> | |
620 | struct has_exit_pseudo_states_helper | |
621 | { | |
622 | typedef typename StateType::stt Stt; | |
623 | typedef typename generate_state_set<Stt>::type state_list; | |
624 | ||
625 | typedef ::boost::mpl::bool_< ::boost::mpl::count_if< | |
626 | state_list,is_pseudo_exit< ::boost::mpl::placeholders::_1> >::value != 0> type; | |
627 | }; | |
628 | template <class StateType> | |
629 | struct has_exit_pseudo_states | |
630 | { | |
631 | typedef typename ::boost::mpl::eval_if<typename is_composite_state<StateType>::type, | |
632 | has_exit_pseudo_states_helper<StateType>, | |
633 | ::boost::mpl::bool_<false> >::type type; | |
634 | }; | |
635 | ||
636 | // builds flags (add internal_flag_list and flag_list). internal_flag_list is used for terminate/interrupt states | |
637 | template <class StateType> | |
638 | struct get_flag_list | |
639 | { | |
640 | typedef typename ::boost::mpl::insert_range< | |
641 | typename StateType::flag_list, | |
642 | typename ::boost::mpl::end< typename StateType::flag_list >::type, | |
643 | typename StateType::internal_flag_list | |
644 | >::type type; | |
645 | }; | |
646 | ||
647 | template <class StateType> | |
648 | struct is_state_blocking | |
649 | { | |
650 | typedef typename ::boost::mpl::fold< | |
651 | typename get_flag_list<StateType>::type, ::boost::mpl::set<>, | |
652 | ::boost::mpl::if_< | |
653 | has_event_blocking_flag< ::boost::mpl::placeholders::_2>, | |
654 | ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >, | |
655 | ::boost::mpl::placeholders::_1 > | |
656 | >::type blocking_flags; | |
657 | ||
658 | typedef typename ::boost::mpl::if_< | |
659 | ::boost::mpl::empty<blocking_flags>, | |
660 | ::boost::mpl::bool_<false>, | |
661 | ::boost::mpl::bool_<true> >::type type; | |
662 | }; | |
663 | // returns a mpl::bool_<true> if fsm has an event blocking flag in one of its substates | |
664 | template <class StateType> | |
665 | struct has_fsm_blocking_states | |
666 | { | |
667 | typedef typename create_stt<StateType>::type Stt; | |
668 | typedef typename generate_state_set<Stt>::type state_list; | |
669 | ||
670 | typedef typename ::boost::mpl::fold< | |
671 | state_list, ::boost::mpl::set<>, | |
672 | ::boost::mpl::if_< | |
673 | is_state_blocking< ::boost::mpl::placeholders::_2>, | |
674 | ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >, | |
675 | ::boost::mpl::placeholders::_1 > | |
676 | >::type blocking_states; | |
677 | ||
678 | typedef typename ::boost::mpl::if_< | |
679 | ::boost::mpl::empty<blocking_states>, | |
680 | ::boost::mpl::bool_<false>, | |
681 | ::boost::mpl::bool_<true> >::type type; | |
682 | }; | |
683 | ||
684 | template <class StateType> | |
685 | struct is_no_exception_thrown | |
686 | { | |
687 | typedef ::boost::mpl::bool_< ::boost::mpl::count_if< | |
688 | typename StateType::configuration, | |
689 | has_no_exception_thrown< ::boost::mpl::placeholders::_1 > >::value != 0> found; | |
690 | ||
691 | typedef typename ::boost::mpl::or_< | |
692 | typename has_no_exception_thrown<StateType>::type, | |
693 | found | |
694 | >::type type; | |
695 | }; | |
696 | ||
697 | template <class StateType> | |
698 | struct is_no_message_queue | |
699 | { | |
700 | typedef ::boost::mpl::bool_< ::boost::mpl::count_if< | |
701 | typename StateType::configuration, | |
702 | has_no_message_queue< ::boost::mpl::placeholders::_1 > >::value != 0> found; | |
703 | ||
704 | typedef typename ::boost::mpl::or_< | |
705 | typename has_no_message_queue<StateType>::type, | |
706 | found | |
707 | >::type type; | |
708 | }; | |
709 | ||
710 | template <class StateType> | |
711 | struct is_active_state_switch_policy | |
712 | { | |
713 | typedef ::boost::mpl::bool_< ::boost::mpl::count_if< | |
714 | typename StateType::configuration, | |
715 | has_active_state_switch_policy< ::boost::mpl::placeholders::_1 > >::value != 0> found; | |
716 | ||
717 | typedef typename ::boost::mpl::or_< | |
718 | typename has_active_state_switch_policy<StateType>::type, | |
719 | found | |
720 | >::type type; | |
721 | }; | |
722 | ||
723 | template <class StateType> | |
724 | struct get_initial_event | |
725 | { | |
726 | typedef typename StateType::initial_event type; | |
727 | }; | |
728 | ||
729 | template <class StateType> | |
730 | struct get_final_event | |
731 | { | |
732 | typedef typename StateType::final_event type; | |
733 | }; | |
734 | ||
735 | template <class TransitionTable, class InitState> | |
736 | struct build_one_orthogonal_region | |
737 | { | |
738 | template<typename Row> | |
739 | struct row_to_incidence : | |
740 | ::boost::mpl::vector< | |
741 | ::boost::mpl::pair< | |
742 | typename Row::next_state_type, | |
743 | typename Row::transition_event>, | |
744 | typename Row::current_state_type, | |
745 | typename Row::next_state_type | |
746 | > {}; | |
747 | ||
748 | template <class Seq, class Elt> | |
749 | struct transition_incidence_list_helper | |
750 | { | |
751 | typedef typename ::boost::mpl::push_back< Seq, row_to_incidence< Elt > >::type type; | |
752 | }; | |
753 | ||
754 | typedef typename ::boost::mpl::fold< | |
755 | TransitionTable, | |
756 | ::boost::mpl::vector<>, | |
757 | transition_incidence_list_helper< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2> | |
758 | >::type transition_incidence_list; | |
759 | ||
760 | typedef ::boost::msm::mpl_graph::incidence_list_graph<transition_incidence_list> | |
761 | transition_graph; | |
762 | ||
763 | struct preordering_dfs_visitor : | |
764 | ::boost::msm::mpl_graph::dfs_default_visitor_operations | |
765 | { | |
766 | template<typename Node, typename Graph, typename State> | |
767 | struct discover_vertex : | |
768 | ::boost::mpl::insert<State, Node> | |
769 | {}; | |
770 | }; | |
771 | ||
772 | typedef typename mpl::first< | |
773 | typename ::boost::msm::mpl_graph::depth_first_search< | |
774 | transition_graph, | |
775 | preordering_dfs_visitor, | |
776 | ::boost::mpl::set<>, | |
777 | InitState | |
778 | >::type | |
779 | >::type type; | |
780 | }; | |
781 | ||
782 | template <class Fsm> | |
783 | struct find_entry_states | |
784 | { | |
785 | typedef typename ::boost::mpl::copy< | |
786 | typename Fsm::substate_list, | |
787 | ::boost::mpl::inserter< | |
788 | ::boost::mpl::set0<>, | |
789 | ::boost::mpl::if_< | |
790 | has_explicit_entry_state< ::boost::mpl::placeholders::_2 >, | |
791 | ::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2>, | |
792 | ::boost::mpl::placeholders::_1 | |
793 | > | |
794 | > | |
795 | >::type type; | |
796 | }; | |
797 | ||
798 | template <class Set1, class Set2> | |
799 | struct is_common_element | |
800 | { | |
801 | typedef typename ::boost::mpl::fold< | |
802 | Set1, ::boost::mpl::false_, | |
803 | ::boost::mpl::if_< | |
804 | ::boost::mpl::has_key< | |
805 | Set2, | |
806 | ::boost::mpl::placeholders::_2 | |
807 | >, | |
808 | ::boost::mpl::true_, | |
809 | ::boost::mpl::placeholders::_1 | |
810 | > | |
811 | >::type type; | |
812 | }; | |
813 | ||
814 | template <class EntryRegion, class AllRegions> | |
815 | struct add_entry_region | |
816 | { | |
817 | typedef typename ::boost::mpl::transform< | |
818 | AllRegions, | |
819 | ::boost::mpl::if_< | |
820 | is_common_element<EntryRegion, ::boost::mpl::placeholders::_1>, | |
821 | set_insert_range< ::boost::mpl::placeholders::_1, EntryRegion>, | |
822 | ::boost::mpl::placeholders::_1 | |
823 | > | |
824 | >::type type; | |
825 | }; | |
826 | ||
827 | // build a vector of regions states (as a set) | |
828 | // one set of states for every region | |
829 | template <class Fsm, class InitStates> | |
830 | struct build_orthogonal_regions | |
831 | { | |
832 | typedef typename | |
833 | ::boost::mpl::fold< | |
834 | InitStates, ::boost::mpl::vector0<>, | |
835 | ::boost::mpl::push_back< | |
836 | ::boost::mpl::placeholders::_1, | |
837 | build_one_orthogonal_region< typename Fsm::stt, ::boost::mpl::placeholders::_2 > > | |
838 | >::type without_entries; | |
839 | ||
840 | typedef typename | |
841 | ::boost::mpl::fold< | |
842 | typename find_entry_states<Fsm>::type, ::boost::mpl::vector0<>, | |
843 | ::boost::mpl::push_back< | |
844 | ::boost::mpl::placeholders::_1, | |
845 | build_one_orthogonal_region< typename Fsm::stt, ::boost::mpl::placeholders::_2 > > | |
846 | >::type only_entries; | |
847 | ||
848 | typedef typename ::boost::mpl::fold< | |
849 | only_entries , without_entries, | |
850 | add_entry_region< ::boost::mpl::placeholders::_2, ::boost::mpl::placeholders::_1> | |
851 | >::type type; | |
852 | }; | |
853 | ||
854 | template <class GraphAsSeqOfSets, class StateType> | |
855 | struct find_region_index | |
856 | { | |
857 | typedef typename | |
858 | ::boost::mpl::fold< | |
859 | GraphAsSeqOfSets, ::boost::mpl::pair< ::boost::mpl::int_< -1 > /*res*/, ::boost::mpl::int_<0> /*counter*/ >, | |
860 | ::boost::mpl::if_< | |
861 | ::boost::mpl::has_key< ::boost::mpl::placeholders::_2, StateType >, | |
862 | ::boost::mpl::pair< | |
863 | ::boost::mpl::second< ::boost::mpl::placeholders::_1 >, | |
864 | ::boost::mpl::next< ::boost::mpl::second< ::boost::mpl::placeholders::_1 > > | |
865 | >, | |
866 | ::boost::mpl::pair< | |
867 | ::boost::mpl::first< ::boost::mpl::placeholders::_1 >, | |
868 | ::boost::mpl::next< ::boost::mpl::second< ::boost::mpl::placeholders::_1 > > | |
869 | > | |
870 | > | |
871 | >::type result_pair; | |
872 | typedef typename ::boost::mpl::first<result_pair>::type type; | |
873 | enum {value = type::value}; | |
874 | }; | |
875 | ||
876 | template <class Fsm> | |
877 | struct check_regions_orthogonality | |
878 | { | |
879 | typedef typename build_orthogonal_regions< Fsm,typename Fsm::initial_states>::type regions; | |
880 | ||
881 | typedef typename ::boost::mpl::fold< | |
882 | regions, ::boost::mpl::int_<0>, | |
883 | ::boost::mpl::plus< ::boost::mpl::placeholders::_1 , ::boost::mpl::size< ::boost::mpl::placeholders::_2> > | |
884 | >::type number_of_states_in_regions; | |
885 | ||
886 | typedef typename ::boost::mpl::fold< | |
887 | regions,mpl::set0<>, | |
888 | set_insert_range< | |
889 | ::boost::mpl::placeholders::_1, | |
890 | ::boost::mpl::placeholders::_2 > | |
891 | >::type one_big_states_set; | |
892 | ||
893 | enum {states_in_regions_raw = number_of_states_in_regions::value}; | |
894 | enum {cumulated_states_in_regions_raw = ::boost::mpl::size<one_big_states_set>::value}; | |
895 | }; | |
896 | ||
897 | template <class Fsm> | |
898 | struct check_no_unreachable_state | |
899 | { | |
900 | typedef typename check_regions_orthogonality<Fsm>::one_big_states_set states_in_regions; | |
901 | ||
902 | typedef typename set_insert_range< | |
903 | states_in_regions, | |
904 | typename ::boost::mpl::eval_if< | |
905 | typename has_explicit_creation<Fsm>::type, | |
906 | get_explicit_creation<Fsm>, | |
907 | ::boost::mpl::vector0<> | |
908 | >::type | |
909 | >::type with_explicit_creation; | |
910 | ||
911 | enum {states_in_fsm = ::boost::mpl::size< typename Fsm::substate_list >::value}; | |
912 | enum {cumulated_states_in_regions = ::boost::mpl::size< with_explicit_creation >::value}; | |
913 | }; | |
914 | ||
915 | // helper to find out if a SM has an active exit state and is therefore waiting for exiting | |
916 | template <class StateType,class OwnerFct,class FSM> | |
917 | inline | |
918 | typename ::boost::enable_if<typename ::boost::mpl::and_<typename is_composite_state<FSM>::type, | |
919 | typename is_pseudo_exit<StateType>::type>,bool >::type | |
920 | is_exit_state_active(FSM& fsm) | |
921 | { | |
922 | typedef typename OwnerFct::type Composite; | |
923 | //typedef typename create_stt<Composite>::type stt; | |
924 | typedef typename Composite::stt stt; | |
925 | int state_id = get_state_id<stt,StateType>::type::value; | |
926 | Composite& comp = fsm.template get_state<Composite&>(); | |
927 | return (std::find(comp.current_state(),comp.current_state()+Composite::nr_regions::value,state_id) | |
928 | !=comp.current_state()+Composite::nr_regions::value); | |
929 | } | |
930 | template <class StateType,class OwnerFct,class FSM> | |
931 | inline | |
932 | typename ::boost::disable_if<typename ::boost::mpl::and_<typename is_composite_state<FSM>::type, | |
933 | typename is_pseudo_exit<StateType>::type>,bool >::type | |
934 | is_exit_state_active(FSM&) | |
935 | { | |
936 | return false; | |
937 | } | |
938 | ||
939 | // transformation metafunction to end interrupt flags | |
940 | template <class Event> | |
941 | struct transform_to_end_interrupt | |
942 | { | |
943 | typedef boost::msm::EndInterruptFlag<Event> type; | |
944 | }; | |
945 | // transform a sequence of events into another one of EndInterruptFlag<Event> | |
946 | template <class Events> | |
947 | struct apply_end_interrupt_flag | |
948 | { | |
949 | typedef typename | |
950 | ::boost::mpl::transform< | |
951 | Events,transform_to_end_interrupt< ::boost::mpl::placeholders::_1> >::type type; | |
952 | }; | |
953 | // returns a mpl vector containing all end interrupt events if sequence, otherwise the same event | |
954 | template <class Event> | |
955 | struct get_interrupt_events | |
956 | { | |
957 | typedef typename ::boost::mpl::eval_if< | |
958 | ::boost::mpl::is_sequence<Event>, | |
959 | boost::msm::back::apply_end_interrupt_flag<Event>, | |
960 | boost::mpl::vector1<boost::msm::EndInterruptFlag<Event> > >::type type; | |
961 | }; | |
962 | ||
963 | template <class Events> | |
964 | struct build_interrupt_state_flag_list | |
965 | { | |
966 | typedef ::boost::mpl::vector<boost::msm::InterruptedFlag> first_part; | |
967 | typedef typename ::boost::mpl::insert_range< | |
968 | first_part, | |
969 | typename ::boost::mpl::end< first_part >::type, | |
970 | Events | |
971 | >::type type; | |
972 | }; | |
973 | ||
974 | } } }//boost::msm::back | |
975 | ||
976 | #endif // BOOST_MSM_BACK_METAFUNCTIONS_H | |
977 |