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

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