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

source code of boost/libs/msm/include/boost/msm/back/metafunctions.hpp