Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-17 08:50:42

0001 // Copyright 2025 Christian Granzin
0002 // Copyright 2008 Christophe Henry
0003 // henry UNDERSCORE christophe AT hotmail DOT com
0004 // This is an extended version of the state machine available in the boost::mpl library
0005 // Distributed under the same license as the original.
0006 // Copyright for the original version:
0007 // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
0008 // under the Boost Software License, Version 1.0. (See accompanying
0009 // file LICENSE_1_0.txt or copy at
0010 // http://www.boost.org/LICENSE_1_0.txt)
0011 
0012 #ifndef BOOST_MSM_BACKMP11_STATE_MACHINE_H
0013 #define BOOST_MSM_BACKMP11_STATE_MACHINE_H
0014 
0015 #include <array>
0016 #include <exception>
0017 #include <functional>
0018 #include <list>
0019 #include <utility>
0020 
0021 #include <boost/core/no_exceptions_support.hpp>
0022 #include <boost/core/ignore_unused.hpp>
0023 
0024 #include <boost/mp11.hpp>
0025 
0026 #include <boost/mpl/eval_if.hpp>
0027 #include <boost/mpl/identity.hpp>
0028 #include <boost/mpl/is_sequence.hpp>
0029 #include <boost/mpl/bool.hpp>
0030 #include <boost/mpl/and.hpp>
0031 
0032 #include <boost/assert.hpp>
0033 #include <boost/ref.hpp>
0034 #include <boost/type_traits/remove_pointer.hpp>
0035 #include <boost/type_traits/add_reference.hpp>
0036 #include <boost/utility/enable_if.hpp>
0037 #include <boost/type_traits/is_convertible.hpp>
0038 
0039 #include <boost/msm/active_state_switching_policies.hpp>
0040 #include <boost/msm/row_tags.hpp>
0041 #include <boost/msm/backmp11/detail/history_impl.hpp>
0042 #include <boost/msm/backmp11/common_types.hpp>
0043 #include <boost/msm/backmp11/detail/favor_runtime_speed.hpp>
0044 #include <boost/msm/backmp11/state_machine_config.hpp>
0045 
0046 namespace boost { namespace msm { namespace backmp11
0047 {
0048 
0049 // Check whether a state is a composite state.
0050 using detail::is_composite;
0051 
0052 namespace detail
0053 {
0054 
0055 constexpr bool is_valid(visit_mode mode) {
0056     constexpr uint8_t state_mask = 0b011;
0057     const uint8_t state_bits = static_cast<uint8_t>(mode) & state_mask;
0058     return state_bits == 0b001 || state_bits == 0b010;
0059 }
0060 
0061 template <
0062     class FrontEnd,
0063     class Config,
0064     class Derived
0065 >
0066 class state_machine_base : public FrontEnd
0067 {
0068     static_assert(
0069         is_composite<FrontEnd>::value,
0070         "FrontEnd must be a composite state");
0071     static_assert(
0072         is_config<Config>::value,
0073         "Config must be an instance of state machine config");
0074 
0075   public:
0076     using config_t = Config;
0077     using root_sm_t = typename config_t::root_sm;
0078     using context_t = typename config_t::context;
0079     using front_end_t = FrontEnd;
0080     using derived_t = Derived;
0081     using events_queue_t = typename config_t::template
0082         queue_container<std::function<process_result()>>;
0083 
0084     // Event that describes the SM is starting.
0085     // Used when the front-end does not define an initial_event.
0086     struct starting {};
0087     // Event that describes the SM is stopping.
0088     // Used when the front-end does not define a final_event.
0089     struct stopping {};
0090 
0091     template <class ExitPoint>
0092     struct exit_pt : public ExitPoint
0093     {
0094         // tags
0095         typedef ExitPoint           wrapped_exit;
0096         typedef int                 pseudo_exit;
0097         typedef derived_t           owner;
0098         typedef int                 no_automatic_create;
0099         typedef typename
0100             ExitPoint::event        Event;
0101         typedef std::function<process_result (Event const&)>
0102                                     forward_function;
0103 
0104         // forward event to the higher-level FSM
0105         template <class ForwardEvent>
0106         void forward_event(ForwardEvent const& incomingEvent)
0107         {
0108             // use helper to forward or not
0109             ForwardHelper< ::boost::is_convertible<ForwardEvent,Event>::value>::helper(incomingEvent,m_forward);
0110         }
0111         void set_forward_fct(forward_function fct)
0112         {
0113             m_forward = fct;
0114         }
0115         exit_pt():m_forward(){}
0116         // by assignments, we keep our forwarding functor unchanged as our containing SM did not change
0117         template <class RHS>
0118         exit_pt(RHS&):m_forward(){}
0119         exit_pt<ExitPoint>& operator= (const exit_pt<ExitPoint>& )
0120         {
0121             return *this;
0122         }
0123 
0124         private:
0125         forward_function          m_forward;
0126 
0127         // using partial specialization instead of enable_if because of VC8 bug
0128         template <bool OwnEvent, int Dummy=0>
0129         struct ForwardHelper
0130         {
0131             template <class ForwardEvent>
0132             static void helper(ForwardEvent const& ,forward_function& )
0133             {
0134                 // Not our event, assert
0135                 BOOST_ASSERT(false);
0136             }
0137         };
0138         template <int Dummy>
0139         struct ForwardHelper<true,Dummy>
0140         {
0141             template <class ForwardEvent>
0142             static void helper(ForwardEvent const& incomingEvent,forward_function& forward_fct)
0143             {
0144                 // call if handler set, if not, this state is simply a terminate state
0145                 if (forward_fct)
0146                     forward_fct(incomingEvent);
0147             }
0148         };
0149     };
0150 
0151     template <class EntryPoint>
0152     struct entry_pt : public EntryPoint
0153     {
0154         // tags
0155         typedef EntryPoint          wrapped_entry;
0156         typedef int                 pseudo_entry;
0157         typedef derived_t           owner;
0158         typedef int                 no_automatic_create;
0159     };
0160     template <class EntryPoint>
0161     struct direct : public EntryPoint
0162     {
0163         // tags
0164         typedef EntryPoint          wrapped_entry;
0165         typedef int                 explicit_entry_state;
0166         typedef derived_t           owner;
0167         typedef int                 no_automatic_create;
0168     };
0169 
0170     struct internal
0171     {
0172         using tag = back_end_tag;
0173 
0174         using initial_states = to_mp_list_t<typename front_end_t::initial_state>;
0175         static constexpr int nr_regions = mp11::mp_size<initial_states>::value;
0176 
0177         template <class State, typename Enable = void>
0178         struct make_entry
0179         {
0180             using type = State;
0181         };
0182         template <class State>
0183         struct make_entry<State, std::enable_if_t<has_pseudo_entry<State>::value>>
0184         {
0185             using type = entry_pt<State>;
0186         };
0187         template <class State>
0188         struct make_entry<State, std::enable_if_t<has_direct_entry<State>::value>>
0189         {
0190             using type = direct<State>;
0191         };
0192 
0193         template <class State, typename Enable = void>
0194         struct make_exit
0195         {
0196             using type = State;
0197         };
0198         template <class State>
0199         struct make_exit<State, std::enable_if_t<has_pseudo_exit<State>::value>>
0200         {
0201             using type = exit_pt<State>;
0202         };
0203 
0204 
0205         template<typename Row, bool HasGuard, typename Event, typename Source, typename Target>
0206         static bool call_guard_or_true(state_machine_base& sm, const Event& event, Source& source, Target& target)
0207         {
0208             if constexpr (HasGuard)
0209             {
0210                 return Row::guard_call(sm.get_fsm_argument(), event, source, target, sm.m_states);
0211             }
0212             else
0213             {
0214                 return true;
0215             }
0216         }
0217         template<typename Row, bool HasAction, typename Event, typename Source, typename Target>
0218         static process_result call_action_or_true(state_machine_base& sm, const Event& event, Source& source, Target& target)
0219         {
0220             if constexpr (HasAction)
0221             {
0222                 return Row::action_call(sm.get_fsm_argument(), event, source, target, sm.m_states);
0223             }
0224             else
0225             {
0226                 return process_result::HANDLED_TRUE;
0227             }
0228         }
0229 
0230         // Template used to create transitions from rows in the transition table
0231         // (normal transitions).
0232         template<typename Row, bool HasAction, bool HasGuard>
0233         struct Transition
0234         {
0235             typedef typename Row::Evt transition_event;
0236             typedef typename make_entry<typename Row::Source>::type T1;
0237             // if the source is an exit pseudo state, then
0238             // current_state_type becomes the result of get_owner
0239             // meaning the containing SM from which the exit occurs
0240             typedef typename ::boost::mpl::eval_if<
0241                     typename has_pseudo_exit<T1>::type,
0242                     get_owner<T1,derived_t>,
0243                     ::boost::mpl::identity<typename Row::Source> >::type current_state_type;
0244 
0245             typedef typename make_exit<typename Row::Target>::type T2;
0246             // if Target is a sequence, then we have a fork and expect a sequence of explicit_entry
0247             // else if Target is an explicit_entry, next_state_type becomes the result of get_owner
0248             // meaning the containing SM if the row is "outside" the containing SM or else the explicit_entry state itself
0249             typedef typename ::boost::mpl::eval_if<
0250                 typename ::boost::mpl::is_sequence<T2>::type,
0251                 get_fork_owner<T2,derived_t>,
0252                 ::boost::mpl::eval_if<
0253                         typename has_no_automatic_create<T2>::type,
0254                         get_owner<T2,derived_t>,
0255                         ::boost::mpl::identity<T2> >
0256             >::type next_state_type;
0257 
0258             // Take the transition action and return the next state.
0259             static process_result execute(state_machine_base& sm, int region_index, int state, transition_event const& event)
0260             {
0261                 BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<current_state_type>()));
0262                 BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<next_state_type>()));
0263                 boost::ignore_unused(state); // Avoid warnings if BOOST_ASSERT expands to nothing.
0264                 BOOST_ASSERT(state == (current_state));
0265                 // if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
0266                 if (has_pseudo_exit<T1>::type::value &&
0267                     !sm.is_exit_state_active<T1, get_owner<T1,derived_t>>())
0268                 {
0269                     return process_result::HANDLED_FALSE;
0270                 }
0271 
0272                 auto& source = sm.get_state<current_state_type>();
0273                 auto& target = sm.get_state<next_state_type>();
0274 
0275                 if (!call_guard_or_true<Row, HasGuard>(sm, event, source, target))
0276                 {
0277                     // guard rejected the event, we stay in the current one
0278                     return process_result::HANDLED_GUARD_REJECT;
0279                 }
0280                 sm.m_active_state_ids[region_index] = active_state_switching::after_guard(current_state,next_state);
0281 
0282                 // first call the exit method of the current state
0283                 source.on_exit(event, sm.get_fsm_argument());
0284                 sm.m_active_state_ids[region_index] = active_state_switching::after_exit(current_state,next_state);
0285 
0286                 // then call the action method
0287                 process_result res = call_action_or_true<Row, HasAction>(sm, event, source, target);
0288                 sm.m_active_state_ids[region_index] = active_state_switching::after_action(current_state,next_state);
0289 
0290                 // and finally the entry method of the new current state
0291                 convert_event_and_execute_entry<T2>(target,event,sm);
0292                 sm.m_active_state_ids[region_index] = active_state_switching::after_entry(current_state,next_state);
0293 
0294                 return res;
0295             }
0296         };
0297 
0298         // Template used to create transitions from rows in the transition table
0299         // (internal transitions).
0300         template<typename Row, bool HasAction, bool HasGuard, typename State = typename Row::Source>
0301         struct InternalTransition
0302         {
0303             typedef typename Row::Evt transition_event;
0304             typedef State current_state_type;
0305             typedef current_state_type next_state_type;
0306 
0307             // Take the transition action and return the next state.
0308             static process_result execute(state_machine_base& sm, int , int state, transition_event const& event)
0309             {
0310 
0311                 BOOST_STATIC_CONSTANT(int, current_state = (get_state_id<current_state_type>()));
0312                 boost::ignore_unused(state, current_state); // Avoid warnings if BOOST_ASSERT expands to nothing.
0313                 BOOST_ASSERT(state == (current_state));
0314 
0315                 auto& source = sm.get_state<current_state_type>();
0316                 auto& target = source;
0317 
0318                 if (!call_guard_or_true<Row, HasGuard>(sm, event, source, target))
0319                 {
0320                     // guard rejected the event, we stay in the current one
0321                     return process_result::HANDLED_GUARD_REJECT;
0322                 }
0323 
0324                 // call the action method
0325                 return call_action_or_true<Row, HasAction>(sm, event, source, target);
0326             }
0327         };
0328 
0329         template <class Tag, class Row,class State>
0330         struct create_backend_stt;
0331         template <class Row,class State>
0332         struct create_backend_stt<g_row_tag,Row,State>
0333         {
0334             using type = Transition<Row, false, true>;
0335         };
0336         template <class Row,class State>
0337         struct create_backend_stt<a_row_tag,Row,State>
0338         {
0339             using type = Transition<Row, true, false>;
0340         };
0341         template <class Row,class State>
0342         struct create_backend_stt<_row_tag,Row,State>
0343         {
0344             using type = Transition<Row, false, false>;
0345         };
0346         template <class Row,class State>
0347         struct create_backend_stt<row_tag,Row,State>
0348         {
0349             using type = Transition<Row, true, true>;
0350         };
0351         template <class Row,class State>
0352         struct create_backend_stt<g_irow_tag,Row,State>
0353         {
0354             using type = InternalTransition<Row, false, true>;
0355         };
0356         template <class Row,class State>
0357         struct create_backend_stt<a_irow_tag,Row,State>
0358         {
0359             using type = InternalTransition<Row, true, false>;
0360         };
0361         template <class Row,class State>
0362         struct create_backend_stt<irow_tag,Row,State>
0363         {
0364             using type = InternalTransition<Row, true, true>;
0365         };
0366         template <class Row,class State>
0367         struct create_backend_stt<_irow_tag,Row,State>
0368         {
0369             using type = InternalTransition<Row, false, false>;
0370         };
0371         template <class Row,class State>
0372         struct create_backend_stt<sm_a_i_row_tag,Row,State>
0373         {
0374             using type = InternalTransition<Row, true, false, State>;
0375         };
0376         template <class Row,class State>
0377         struct create_backend_stt<sm_g_i_row_tag,Row,State>
0378         {
0379             using type = InternalTransition<Row, false, true, State>;
0380         };
0381         template <class Row,class State>
0382         struct create_backend_stt<sm_i_row_tag,Row,State>
0383         {
0384             using type = InternalTransition<Row, true, true, State>;
0385         };
0386         template <class Row,class State>
0387         struct create_backend_stt<sm__i_row_tag,Row,State>
0388         {
0389             using type = InternalTransition<Row, false, false, State>;
0390         };
0391         template <class Row,class State=void>
0392         struct transition_cell
0393         {
0394             using type = typename create_backend_stt<typename Row::row_type_tag,Row,State>::type;
0395         };
0396 
0397         // add to the stt the initial states which could be missing (if not being involved in a transition)
0398         template <class TFrontEnd, class stt_simulated = typename TFrontEnd::transition_table>
0399         struct create_real_stt
0400         {
0401             template<typename T>
0402             using get_transition_cell = typename transition_cell<T, TFrontEnd>::type;
0403             typedef typename boost::mp11::mp_transform<
0404                 get_transition_cell,
0405                 to_mp_list_t<stt_simulated>
0406             > type;
0407         };
0408 
0409         using stt = typename get_transition_table<state_machine_base>::type;
0410         using state_set = typename generate_state_set<stt>::state_set;
0411     };
0412 
0413     typedef mp11::mp_rename<typename internal::state_set, std::tuple> states_t;
0414 
0415   private:
0416     using stt = typename internal::stt;
0417     using state_set = typename internal::state_set;
0418     static constexpr int nr_regions = internal::nr_regions;
0419     using active_state_ids_t = std::array<int, nr_regions>;
0420     using initial_states_identity = mp11::mp_transform<mp11::mp_identity, typename internal::initial_states>;
0421     using compile_policy = typename config_t::compile_policy;
0422     using compile_policy_impl = detail::compile_policy_impl<compile_policy>;
0423     template<class Row, class State>
0424     using transition_cell = typename internal::template transition_cell<Row, State>;
0425     template<class TFrontEnd, class stt_simulated>
0426     using create_real_stt = typename internal::template create_real_stt<TFrontEnd, stt_simulated>;
0427     
0428 
0429     template<typename T>
0430     using get_active_state_switch_policy = typename T::active_state_switch_policy;
0431     using active_state_switching =
0432         boost::mp11::mp_eval_or<active_state_switch_after_entry,
0433                                 get_active_state_switch_policy, front_end_t>;
0434 
0435     typedef bool (*flag_handler)(state_machine_base const &);
0436 
0437     // all state machines are friend with each other to allow embedding any of them in another fsm
0438     template <class, class, class>
0439     friend class state_machine_base;
0440 
0441     template <typename Policy>
0442     friend struct detail::compile_policy_impl;
0443 
0444     // Allow access to private members for serialization.
0445     // WARNING:
0446     // No guarantee is given on the private member layout.
0447     // Future changes may break existing serializer implementations.
0448     template<typename T, typename A0, typename A1, typename A2>
0449     friend void serialize(T&, state_machine_base<A0, A1, A2>&);
0450 
0451     template <typename T>
0452     using get_initial_event = typename T::initial_event;
0453     using fsm_initial_event =
0454         boost::mp11::mp_eval_or<starting, get_initial_event, front_end_t>;
0455 
0456     template <typename T>
0457     using get_final_event = typename T::final_event;
0458     using fsm_final_event =
0459         boost::mp11::mp_eval_or<stopping, get_final_event, front_end_t>;
0460 
0461     // Template used to form forwarding rows in the transition table for every row of a composite SM
0462     template <typename T1, class Evt>
0463     struct frow
0464     {
0465         typedef T1                  current_state_type;
0466         typedef T1                  next_state_type;
0467         typedef Evt                 transition_event;
0468         // tag to find out if a row is a forwarding row
0469         typedef int                 is_frow;
0470 
0471         // Take the transition action and return the next state.
0472         static process_result execute(state_machine_base& sm, int region_index, int , transition_event const& event)
0473         {
0474             // false as second parameter because this event is forwarded from outer fsm
0475             process_result res =
0476                 (sm.get_state<current_state_type>()).process_event_internal(event);
0477             sm.m_active_state_ids[region_index]=get_state_id<T1>();
0478             return res;
0479         }
0480         // helper metafunctions used by dispatch table and give the frow a new event
0481         // (used to avoid double entries in a table because of base events)
0482         template <class NewEvent>
0483         struct replace_event
0484         {
0485             typedef frow<T1,NewEvent> type;
0486         };
0487     };
0488 
0489     template <class Table,class Intermediate,class State>
0490     struct add_forwarding_row_helper
0491     {
0492         typedef typename generate_event_set<Table>::event_set_mp11 all_events;
0493 
0494         template<typename T>
0495         using frow_state_type = frow<State, T>;
0496         typedef mp11::mp_append<
0497             to_mp_list_t<Intermediate>,
0498             mp11::mp_transform<frow_state_type, all_events>
0499             > type;
0500     };
0501     // gets the transition table from a composite and make from it a forwarding row
0502     template <class State,bool IsComposite>
0503     struct get_internal_transition_table
0504     {
0505         // first get the table of a composite
0506         typedef typename recursive_get_transition_table<State>::type original_table;
0507 
0508         // we now look for the events the composite has in its internal transitions
0509         // the internal ones are searched recursively in sub-sub... states
0510         // we go recursively because our states can also have internal tables or substates etc.
0511         typedef typename recursive_get_internal_transition_table<State, true>::type recursive_istt;
0512         template<typename T>
0513         using get_transition_cell = typename transition_cell<T, State>::type;
0514         typedef boost::mp11::mp_transform<
0515             get_transition_cell,
0516             to_mp_list_t<recursive_istt>
0517         > recursive_istt_with_tag;
0518 
0519         typedef boost::mp11::mp_append<original_table, recursive_istt_with_tag> table_with_all_events;
0520 
0521         // and add for every event a forwarding row
0522         typedef typename ::boost::mpl::eval_if<
0523                 typename compile_policy_impl::add_forwarding_rows,
0524                 add_forwarding_row_helper<table_with_all_events,mp11::mp_list<>,State>,
0525                 ::boost::mpl::identity< mp11::mp_list<> >
0526         >::type type;
0527     };
0528     template <class State>
0529     struct get_internal_transition_table<State, false>
0530     {
0531         typedef typename create_real_stt<State, typename State::internal_transition_table >::type type;
0532     };
0533     
0534     typedef typename generate_state_map<state_set>::type state_map_mp11;
0535     typedef typename generate_event_set<stt>::event_set_mp11 event_set_mp11;
0536     typedef history_impl<typename front_end_t::history, nr_regions> concrete_history;
0537     typedef typename generate_event_set<
0538         typename create_real_stt<front_end_t, typename front_end_t::internal_transition_table >::type
0539     >::event_set_mp11 processable_events_internal_table;
0540 
0541     // extends the transition table with rows from composite states
0542     template <class Composite>
0543     struct extend_table
0544     {
0545         // add the init states
0546         //typedef typename get_transition_table<Composite>::type stt;
0547         typedef typename Composite::stt Stt;
0548 
0549         // add the internal events defined in the internal_transition_table
0550         // Note: these are added first because they must have a lesser prio
0551         // than the deeper transitions in the sub regions
0552         // table made of a stt + internal transitions of composite
0553         template<typename T>
0554         using get_transition_cell = typename transition_cell<T, Composite>::type;
0555         typedef typename boost::mp11::mp_transform<
0556             get_transition_cell,
0557             to_mp_list_t<typename Composite::internal_transition_table>
0558         > internal_stt;
0559 
0560         typedef boost::mp11::mp_append<
0561             to_mp_list_t<Stt>,
0562             internal_stt
0563         > stt_plus_internal;
0564 
0565         // for every state, add its transition table (if any)
0566         // transformed as frow
0567         template<typename V, typename State>
0568         using F = boost::mp11::mp_append<
0569             V,
0570             typename get_internal_transition_table<State, is_composite<State>::value>::type
0571             >;
0572         typedef boost::mp11::mp_fold<
0573             state_set,
0574             stt_plus_internal,
0575             F
0576         > type;
0577     };
0578     // extend the table with tables from composite states
0579     typedef typename extend_table<state_machine_base>::type complete_table;
0580     // define the dispatch table used for event dispatch
0581     using sm_dispatch_table = typename compile_policy_impl::template dispatch_table<state_machine_base>;
0582 
0583     struct deferred_event_t
0584     {
0585         std::function<process_result()> process_event;
0586         std::function<bool()> is_event_deferred;
0587         // Deferred events are added with a correlation sequence that helps to
0588         // identify when an event was added.
0589         // Newly deferred events will not be considered for procesing
0590         // within the same sequence.
0591         size_t seq_cnt;
0592     };
0593     using deferred_events_queue_t = std::list<deferred_event_t>;
0594 
0595     struct deferred_events_t
0596     {
0597         deferred_events_queue_t queue;
0598         size_t cur_seq_cnt;
0599     };
0600     using has_any_deferred_event =
0601         mp11::mp_any_of<state_set, has_state_deferred_events>;
0602     using deferred_events_member =
0603         optional_instance<deferred_events_t,
0604                           has_any_deferred_event::value ||
0605                               has_activate_deferred_events<front_end_t>::value>;
0606     using events_queue_member =
0607         optional_instance<events_queue_t,
0608                           !has_no_message_queue<front_end_t>::value>;
0609     using context_member =
0610         optional_instance<context_t*,
0611                           !std::is_same_v<context_t, no_context> &&
0612                               (std::is_same_v<root_sm_t, no_root_sm> ||
0613                                std::is_same_v<root_sm_t, derived_t>)>;
0614 
0615     template <bool C = deferred_events_member::value,
0616               typename = std::enable_if_t<C>>
0617     deferred_events_t& get_deferred_events()
0618     {
0619         return m_optional_members.template get<deferred_events_member>();
0620     }
0621 
0622     template <bool C = deferred_events_member::value,
0623               typename = std::enable_if_t<C>>
0624     const deferred_events_t& get_deferred_events() const
0625     {
0626         return m_optional_members.template get<deferred_events_member>();
0627     }
0628 
0629     template <class Event>
0630     bool is_event_deferred(const Event& event) const
0631     {
0632         return compile_policy_impl::is_event_deferred(
0633             *const_cast<state_machine_base*>(this), event);
0634     }
0635 
0636     // Visit states with a compile-time filter (reduces template instantiations).
0637     template <template <typename> typename Predicate, visit_mode Mode, typename Visitor>
0638     void visit_if(Visitor&& visitor)
0639     {
0640         // TODO:
0641         // Filter needs to be passed to visit to reduce template instantiations.
0642         visit<Mode>(
0643             [&visitor](auto& state)
0644             {
0645                 using State = std::decay_t<decltype(state)>;
0646                 if constexpr (Predicate<State>())
0647                 {
0648                     std::invoke(std::forward<Visitor>(visitor), state);
0649                 }
0650             });
0651     }
0652     
0653   public:
0654     // Construct and forward constructor arguments to the front-end.
0655     template <typename... Args>
0656     state_machine_base(Args&&... args)
0657         : front_end_t(std::forward<Args>(args)...)
0658     {
0659         static_assert(
0660             std::is_base_of_v<state_machine_base, derived_t>,
0661             "Derived must inherit from state_machine");
0662         if constexpr (!std::is_same_v<context_t, no_context>)
0663         {
0664             static_assert(
0665                 std::is_constructible_v<derived_t, context_t&>,
0666                 "Derived must inherit the base class constructors");
0667         }
0668         if constexpr (std::is_same_v<root_sm_t, no_root_sm> ||
0669                       std::is_same_v<root_sm_t, derived_t>)
0670         {
0671             // create states
0672             init(*static_cast<derived_t*>(this));
0673         }
0674         reset_active_state_ids();
0675     }
0676 
0677     // Construct with a context and forward further constructor arguments to the front-end.
0678     template <bool C = context_member::value,
0679               typename = std::enable_if_t<C>,
0680               typename... Args>
0681     state_machine_base(context_t& context, Args&&... args)
0682         : state_machine_base(std::forward<Args>(args)...)
0683         {
0684             m_optional_members.template get<context_member>() = &context;
0685             if constexpr (std::is_same_v<root_sm_t, no_root_sm>)
0686             {
0687                 constexpr visit_mode mode = visit_mode::all_states | visit_mode::recursive;
0688                 visit_if<is_back_end, mode>(
0689                     [&context](auto &state_machine)
0690                     {
0691                         state_machine.m_optional_members.template get<context_member>() = &context;
0692                     });
0693             }
0694         }
0695     
0696     // Copy constructor.
0697     state_machine_base(state_machine_base const& rhs)
0698         : front_end_t(rhs)
0699     {
0700         if constexpr (std::is_same_v<root_sm_t, no_root_sm> ||
0701                       std::is_same_v<root_sm_t, derived_t>)
0702         {
0703             // create states
0704             init(*static_cast<derived_t*>(this));
0705         }
0706         // Copy all members except the root sm pointer.
0707         m_active_state_ids = rhs.m_active_state_ids;
0708         m_optional_members = rhs.m_optional_members;
0709         m_history = rhs.m_history;
0710         m_event_processing = rhs.m_event_processing;
0711         m_states = rhs.m_states;
0712         m_running = rhs.m_running;
0713     }
0714 
0715     // Copy assignment operator.
0716     state_machine_base& operator= (state_machine_base const& rhs)
0717     {
0718         if (this != &rhs)
0719         {
0720            front_end_t::operator=(rhs);
0721             // Copy all members except the root sm pointer.
0722             m_active_state_ids = rhs.m_active_state_ids;
0723             m_optional_members = rhs.m_optional_members;
0724             m_history = rhs.m_history;
0725             m_event_processing = rhs.m_event_processing;
0726             m_states = rhs.m_states;
0727             m_running = rhs.m_running;
0728         }
0729        return *this;
0730     }
0731 
0732     // Start the state machine (calls entry of the initial state).
0733     void start()
0734     {
0735         // Assert for a case where root sm was not set up correctly
0736         // after construction.
0737         if constexpr (!std::is_same_v<typename Config::root_sm, no_root_sm>)
0738         {
0739             BOOST_ASSERT_MSG(&(this->get_root_sm()),
0740             "Root sm must be passed as Derived and configured as root_sm");
0741         }
0742         start(fsm_initial_event{});
0743     }
0744 
0745     // Start the state machine (calls entry of the initial state with initial_event to on_entry's).
0746     template <class Event>
0747     void start(Event const& initial_event)
0748     {
0749         if (!m_running)
0750         {
0751             internal_start<Event, fsm_parameter_t, true>(initial_event, get_fsm_argument());
0752         }
0753     }
0754 
0755     // stop the state machine (calls exit of the current state)
0756     void stop()
0757     {
0758         stop(fsm_final_event{});
0759     }
0760 
0761     // stop the state machine (calls exit of the current state passing finalEvent to on_exit's)
0762     template <class Event>
0763     void stop(Event const& final_event)
0764     {
0765         if (m_running)
0766         {
0767             on_exit(final_event, get_fsm_argument());
0768             m_running = false;
0769         }
0770     }
0771 
0772     // Check whether a state is currently active.
0773   public:
0774     template <typename State>
0775     bool is_state_active() const
0776     {
0777         bool found = false;
0778         const_cast<state_machine_base*>(this)->visit(
0779             [&found](const auto& state)
0780             {
0781                 using StateToCheck = std::decay_t<decltype(state)>;
0782                 found |= std::is_same_v<State, StateToCheck>;
0783             });
0784         return found;
0785     }
0786 
0787     // Main function to process events.
0788     template<class Event>
0789     process_result process_event(Event const& event)
0790     {
0791         return process_event_internal(event, EventSource::EVENT_SOURCE_DIRECT);
0792     }
0793 
0794     // Enqueues an event in the message queue.
0795     // Call process_queued_events to process all queued events.
0796     // Be careful if you do this during event processing, the event will be processed immediately
0797     // and not kept in the queue.
0798     template <class Event,
0799               bool C = events_queue_member::value,
0800               typename = std::enable_if_t<C>>
0801     void enqueue_event(Event const& event)
0802     {
0803         get_events_queue().push_back(
0804             [this, event]
0805             {
0806                 return process_event_internal(
0807                     event,
0808                     EventSource::EVENT_SOURCE_DIRECT |
0809                     EventSource::EVENT_SOURCE_MSG_QUEUE);
0810             }
0811         );
0812     }
0813 
0814     // Process all queued events.
0815     template <bool C = events_queue_member::value,
0816               typename = std::enable_if_t<C>>
0817     void process_queued_events()
0818     {
0819         while(!get_events_queue().empty())
0820         {
0821             process_single_queued_event();
0822         }
0823     }
0824 
0825     // Process a single queued event.
0826     template <bool C = events_queue_member::value,
0827               typename = std::enable_if_t<C>>
0828     void process_single_queued_event()
0829     {
0830         auto to_call = get_events_queue().front();
0831         get_events_queue().pop_front();
0832         to_call();
0833     }
0834 
0835     // Get the context of the state machine.
0836     template <bool C = !std::is_same_v<context_t, no_context>,
0837               typename = std::enable_if_t<C>>
0838     context_t& get_context()
0839     {
0840         if constexpr (context_member::value)
0841         {
0842             return *m_optional_members.template get<context_member>();
0843         }
0844         else
0845         {
0846             return get_root_sm().get_context();
0847         }
0848     }
0849 
0850     // Get the context of the state machine.
0851     template <bool C = !std::is_same_v<context_t, no_context>,
0852               typename = std::enable_if_t<C>>
0853     const context_t& get_context() const
0854     {
0855         if constexpr (context_member::value)
0856         {
0857             return *m_optional_members.template get<context_member>();
0858         }
0859         else
0860         {
0861             return get_root_sm().get_context();
0862         }
0863     }
0864 
0865     // Get the events queued for later processing.
0866     template <bool C = events_queue_member::value,
0867               typename = std::enable_if_t<C>>
0868     events_queue_t& get_events_queue()
0869     {
0870         return m_optional_members.template get<events_queue_member>();
0871     }
0872 
0873     // Get the events queued for later processing.
0874     template <bool C = events_queue_member::value,
0875               typename = std::enable_if_t<C>>
0876     const events_queue_t& get_events_queue() const
0877     {
0878        return m_optional_members.template get<events_queue_member>();
0879     }
0880 
0881     // Get the deferred events queued for later processing.
0882     template <bool C = deferred_events_member::value,
0883               typename = std::enable_if_t<C>>
0884     deferred_events_queue_t& get_deferred_events_queue()
0885     {
0886         return get_deferred_events().queue;
0887     }
0888 
0889     // Get the deferred events queued for later processing.
0890     template <bool C = deferred_events_member::value,
0891               typename = std::enable_if_t<C>>
0892     const deferred_events_queue_t& get_deferred_events_queue() const
0893     {
0894         return get_deferred_events().queue;
0895     }
0896 
0897     // Getter that returns the currently active state ids of the FSM.
0898     const active_state_ids_t& get_active_state_ids() const
0899     {
0900         return m_active_state_ids;
0901     }
0902 
0903     // Get the root sm.
0904     template <typename T = root_sm_t, 
0905               typename = std::enable_if_t<!std::is_same_v<T, no_root_sm>>>
0906     root_sm_t& get_root_sm()
0907     {
0908         return *static_cast<root_sm_t*>(m_root_sm);
0909     }
0910     // Get the root sm.
0911     template <typename T = root_sm_t, 
0912               typename = std::enable_if_t<!std::is_same_v<T, no_root_sm>>>
0913     const root_sm_t& get_root_sm() const
0914     {
0915         return *static_cast<const root_sm_t*>(m_root_sm);
0916     }
0917 
0918     // Return the id of a state in the sm.
0919     template<typename State>
0920     static constexpr int get_state_id(const State&)
0921     {
0922         static_assert(mp11::mp_map_contains<state_map_mp11, State>::value);
0923         return detail::get_state_id<state_map_mp11, State>::type::value;
0924     }
0925     // Return the id of a state in the sm.
0926     template<typename State>
0927     static constexpr int get_state_id()
0928     {
0929         static_assert(mp11::mp_map_contains<state_map_mp11, State>::value);
0930         return detail::get_state_id<state_map_mp11, State>::type::value;
0931     }
0932 
0933     // True if the sm is used in another sm.
0934     bool is_contained() const
0935     {
0936         return (static_cast<const void*>(this) != m_root_sm);
0937     }
0938 
0939     // Get a state.
0940     template <class State>
0941     State& get_state()
0942     {
0943         return std::get<std::remove_reference_t<State>>(m_states);
0944     }
0945     // Get a state.
0946     template <class State>
0947     const State& get_state() const
0948     {
0949         return std::get<std::remove_reference_t<State>>(m_states);
0950     }
0951 
0952     // checks if a flag is active using the BinaryOp as folding function
0953     template <class Flag,class BinaryOp>
0954     bool is_flag_active() const
0955     {
0956         flag_handler* flags_entries = get_entries_for_flag<Flag>();
0957         bool res = (*flags_entries[ m_active_state_ids[0] ])(*this);
0958         for (int i = 1; i < nr_regions ; ++i)
0959         {
0960             res = BinaryOp() (res,(*flags_entries[ m_active_state_ids[i] ])(*this));
0961         }
0962         return res;
0963     }
0964     // checks if a flag is active using no binary op if 1 region, or OR if > 1 regions
0965     template <class Flag>
0966     bool is_flag_active() const
0967     {
0968         return FlagHelper<Flag,(nr_regions>1)>::helper(*this,get_entries_for_flag<Flag>());
0969     }
0970 
0971     // Visit the states (only active states, recursive).
0972     template <typename Visitor>
0973     constexpr void visit(Visitor&& visitor)
0974     {
0975         visit<visit_mode::active_recursive>(std::forward<Visitor>(visitor));
0976     }
0977 
0978     // Visit the states.
0979     // How to traverse is selected with visit_mode.
0980     template <visit_mode Mode, typename Visitor>
0981     constexpr void visit(Visitor&& visitor)
0982     {
0983         static_assert(
0984             is_valid(Mode),
0985             "Mode must specify one of active_states or all_states");
0986         constexpr bool recursive = has_flag(Mode, visit_mode::recursive);
0987         if constexpr (has_flag(Mode, visit_mode::active_states))
0988         {
0989             if (m_running)
0990             {
0991                 for (const int state_id : m_active_state_ids)
0992                 {
0993                     using table = visitor_dispatch_table<Visitor, recursive>;
0994                     table::dispatch(*this, state_id, std::forward<Visitor>(visitor));
0995                 }
0996             }
0997         }
0998         // all states
0999         else
1000         {
1001             mp11::tuple_for_each(m_states,
1002                 [&visitor](auto& state)
1003                 {
1004                     std::invoke(std::forward<Visitor>(visitor), state);
1005 
1006                     using State = std::decay_t<decltype(state)>;
1007                     // recursive needs to be repeated in this lambda,
1008                     // MSVC does not recognize the constexpr correctly.
1009                     constexpr bool recursive = has_flag(Mode, visit_mode::recursive);
1010                     if constexpr (has_back_end_tag<State>::value && recursive)
1011                     {
1012                         state.template visit<Mode>(std::forward<Visitor>(visitor));
1013                     }
1014                 }
1015             );
1016         }   
1017     }
1018 
1019     // Puts the given event into the deferred events queue.
1020     template <
1021         class Event,
1022         bool C = deferred_events_member::value,
1023         typename = std::enable_if_t<C>>
1024     void defer_event(Event const& event)
1025     {
1026         compile_policy_impl::defer_event(*this, event);
1027     }
1028 
1029   protected:
1030     static_assert(std::is_same_v<typename config_t::fsm_parameter, transition_owner> ||
1031                     (std::is_same_v<typename config_t::fsm_parameter, typename config_t::root_sm> &&
1032                      !std::is_same_v<typename config_t::root_sm, no_root_sm>),
1033                   "fsm_parameter must be transition_owner or root_sm"
1034                  );
1035     using fsm_parameter_t = mp11::mp_if_c<
1036         std::is_same_v<typename config_t::fsm_parameter, transition_owner>,
1037         derived_t,
1038         typename config_t::root_sm>;
1039 
1040     fsm_parameter_t& get_fsm_argument()
1041     {
1042         if constexpr (std::is_same_v<typename config_t::fsm_parameter,
1043                                      transition_owner>)
1044         {
1045             return *static_cast<derived_t*>(this);
1046         }
1047         else
1048         {
1049             return get_root_sm();
1050         }
1051     }
1052 
1053     // Checks if an event is an end interrupt event.
1054     template <typename Event>
1055     bool is_end_interrupt_event(const Event& event) const
1056     {
1057         return compile_policy_impl::is_end_interrupt_event(*this, event);
1058     }
1059 
1060     // Helpers used to reset the state machine.
1061     void reset_active_state_ids()
1062     {
1063        size_t index = 0;
1064        mp11::mp_for_each<initial_states_identity>(
1065        [this, &index](auto state_identity)
1066        {
1067            using State = typename decltype(state_identity)::type;
1068            m_active_state_ids[index++] = get_state_id<State>();
1069        });
1070        m_history.reset_active_state_ids(m_active_state_ids);
1071     }
1072     
1073     // handling of deferred events
1074     void try_process_deferred_events()
1075     {
1076         if constexpr (deferred_events_member::value)
1077         {
1078             deferred_events_t& deferred_events = get_deferred_events();
1079             if (deferred_events.queue.empty())
1080             {
1081                 return;
1082             }
1083 
1084             active_state_ids_t active_state_ids = m_active_state_ids;
1085             // Iteratively process all of the events within the deferred
1086             // queue up to (but not including) newly deferred events.
1087             auto it = deferred_events.queue.begin();
1088             do
1089             {
1090                 if (deferred_events.cur_seq_cnt == it->seq_cnt)
1091                 {
1092                     return;
1093                 }
1094                 if (it->is_event_deferred())
1095                 {
1096                     it = std::next(it);
1097                 }
1098                 else
1099                 {
1100                     deferred_event_t deferred_event = std::move(*it);
1101                     it = deferred_events.queue.erase(it);
1102                     const process_result result = deferred_event.process_event();
1103 
1104                     if ((result & process_result::HANDLED_TRUE) &&
1105                         (active_state_ids != m_active_state_ids))
1106                     {
1107                         // The active state configuration has changed.
1108                         // Start from the beginning, we might be able
1109                         // to process events that stayed in the queue before.
1110                         active_state_ids = m_active_state_ids;
1111                         it = deferred_events.queue.begin();
1112                     }
1113                 }
1114             } while (it != deferred_events.queue.end());
1115         }
1116     }
1117 
1118     // handling of eventless transitions
1119     void try_process_completion_event(EventSource source, bool handled)
1120     {
1121         using first_completion_event = mp11::mp_find_if<event_set_mp11, has_completion_event>;
1122         // if none is found in the SM, nothing to do
1123         if constexpr (first_completion_event::value != mp11::mp_size<event_set_mp11>::value)
1124         {
1125             if (handled)
1126             {
1127                 process_event_internal(
1128                     mp11::mp_at<event_set_mp11, first_completion_event>{},
1129                     source | EventSource::EVENT_SOURCE_DIRECT);
1130             }
1131         }
1132     }
1133 
1134     // Handling of enqueued events.
1135     void try_process_queued_events()
1136     {
1137         if constexpr (events_queue_member::value)
1138         {
1139             process_queued_events();
1140         }
1141     }
1142 
1143     // Main function used internally to make transitions
1144     // Can only be called for internally (for example in an action method) generated events.
1145     template<class Event>
1146     process_result process_event_internal(Event const& event,
1147                            EventSource source = EventSource::EVENT_SOURCE_DEFAULT)
1148     {
1149         // The compile policy decides whether the event needs to be wrapped or not.
1150         // After wrapping it should call back process_event_internal_impl.
1151         return compile_policy_impl::process_event_internal(*this, event, source);
1152     }
1153 
1154     template<class Event>
1155     process_result process_event_internal_impl(Event const& event, EventSource source)
1156     {
1157         // If the state machine has terminate or interrupt flags, check them.
1158         if constexpr (mp11::mp_any_of<state_set, is_state_blocking_t>::value)
1159         {
1160             // If the state machine is terminated, do not handle any event.
1161             if (is_flag_active<TerminateFlag>())
1162             {
1163                 return process_result::HANDLED_TRUE;
1164             }
1165             // If the state machine is interrupted, do not handle any event
1166             // unless the event is the end interrupt event.
1167             if (is_flag_active<InterruptedFlag>() && !is_end_interrupt_event(event))
1168             {
1169                 return process_result::HANDLED_TRUE;
1170             }
1171         }
1172 
1173         // If we have an event queue and are already processing events,
1174         // enqueue it for later processing.
1175         if constexpr (events_queue_member::value)
1176         {
1177             if (m_event_processing)
1178             {
1179                 enqueue_event(event);
1180                 return process_result::HANDLED_TRUE;
1181             }
1182         }
1183 
1184         // If deferred events are configured and the event is to be deferred
1185         // in the active state configuration, then defer it for later processing.
1186         if constexpr (has_any_deferred_event::value)
1187         {
1188             if (is_event_deferred(event))
1189             {
1190                 compile_policy_impl::defer_event(*this, event);
1191                 return process_result::HANDLED_DEFERRED;
1192             }
1193         }
1194 
1195         // Process the event.
1196         m_event_processing = true;
1197         process_result handled;
1198         const bool is_direct_call = source & EventSource::EVENT_SOURCE_DIRECT;
1199         if constexpr (has_no_exception_thrown<front_end_t>::value)
1200         {
1201             handled = do_process_event(event, is_direct_call);
1202         }
1203         else
1204         {
1205             // when compiling without exception support there is no formal parameter "e" in the catch handler.
1206             // Declaring a local variable here does not hurt and will be "used" to make the code in the handler
1207             // compilable although the code will never be executed.
1208             std::exception e;
1209             BOOST_TRY
1210             {
1211                 handled = do_process_event(event, is_direct_call);
1212             }
1213             BOOST_CATCH (std::exception& e)
1214             {
1215                 // give a chance to the concrete state machine to handle
1216                 this->exception_caught(event, get_fsm_argument(), e);
1217                 handled = process_result::HANDLED_FALSE;
1218             }
1219             BOOST_CATCH_END
1220         }
1221 
1222         // at this point we allow the next transition be executed without enqueing
1223         // so that completion events and deferred events execute now (if any)
1224         m_event_processing = false;
1225 
1226         // Process completion transitions BEFORE any other event in the
1227         // pool (UML Standard 2.3 15.3.14)
1228         try_process_completion_event(source, (handled & process_result::HANDLED_TRUE));
1229 
1230         // After handling, take care of the queued and deferred events.
1231         // Default:
1232         // Handle deferred events queue with higher prio than events queue.
1233         if constexpr (!has_event_queue_before_deferred_queue<front_end_t>::value)
1234         {
1235             if (!(EventSource::EVENT_SOURCE_DEFERRED & source))
1236             {
1237                 try_process_deferred_events();
1238 
1239                 // Handle any new events generated into the queue, but only if
1240                 // we're not already processing from the message queue.
1241                 if (!(EventSource::EVENT_SOURCE_MSG_QUEUE & source))
1242                 {
1243                     try_process_queued_events();
1244                 }
1245             }
1246         }
1247         // Non-default:
1248         // Handle events queue with higher prio than deferred events queue.
1249         else
1250         {
1251             if (!(EventSource::EVENT_SOURCE_MSG_QUEUE & source))
1252             {
1253                 try_process_queued_events();
1254                 if (!(EventSource::EVENT_SOURCE_DEFERRED & source))
1255                 {
1256                     try_process_deferred_events();
1257                 }
1258             }
1259         }
1260 
1261         return handled;
1262     }
1263 
1264     // minimum event processing without exceptions, queues, etc.
1265     template<class Event>
1266     process_result do_process_event(Event const& event, bool is_direct_call)
1267     {
1268         if constexpr (deferred_events_member::value)
1269         {
1270             if (is_direct_call)
1271             {
1272                 get_deferred_events().cur_seq_cnt += 1;
1273             }
1274         }
1275 
1276         process_result handled = process_result::HANDLED_FALSE;
1277         // Dispatch the event to every region.
1278         for (int region_id=0; region_id<nr_regions; region_id++)
1279         {
1280             handled = static_cast<process_result>(
1281                 static_cast<int>(handled) |
1282                 static_cast<int>(sm_dispatch_table::dispatch(*this, region_id, m_active_state_ids[region_id], event))
1283             );
1284         }
1285         // Process the event in the internal table of this fsm if the event is processable (present in the table).
1286         if constexpr (mp11::mp_set_contains<processable_events_internal_table,Event>::value)
1287         {
1288             handled = static_cast<process_result>(
1289                 static_cast<int>(handled) |
1290                 static_cast<int>(sm_dispatch_table::dispatch_internal(*this, 0, m_active_state_ids[0], event))
1291             );
1292         }
1293 
1294         // if the event has not been handled and we have orthogonal zones, then
1295         // generate an error on every active state
1296         // for state machine states contained in other state machines, do not handle
1297         // but let the containing sm handle the error, unless the event was generated in this fsm
1298         // (by calling process_event on this fsm object, is_direct_call == true)
1299         // completion events do not produce an error
1300         if ((!is_contained() || is_direct_call) && !handled && !compile_policy_impl::is_completion_event(event))
1301         {
1302             for (const auto state_id: m_active_state_ids)
1303             {
1304                 this->no_transition(event, get_fsm_argument(), state_id);
1305             }
1306         }
1307         return handled;
1308     }
1309 
1310 private:
1311     // helper for flag handling. Uses OR by default on orthogonal zones.
1312     template <class Flag,bool OrthogonalStates>
1313     struct FlagHelper
1314     {
1315         static bool helper(state_machine_base const& sm,flag_handler* )
1316         {
1317             // by default we use OR to accumulate the flags
1318             return sm.is_flag_active<Flag,std::logical_or<bool>>();
1319         }
1320     };
1321     template <class Flag>
1322     struct FlagHelper<Flag,false>
1323     {
1324         static bool helper(state_machine_base const& sm,flag_handler* flags_entries)
1325         {
1326             // just one active state, so we can call operator[] with 0
1327             return flags_entries[sm.get_active_state_ids()[0]](sm);
1328         }
1329     };
1330     // handling of flag
1331     // defines a true and false functions plus a forwarding one for composite states
1332     template <class State,class Flag>
1333     struct FlagHandler
1334     {
1335         static bool flag_true(state_machine_base const& )
1336         {
1337             return true;
1338         }
1339         static bool flag_false(state_machine_base const& )
1340         {
1341             return false;
1342         }
1343         static bool forward(state_machine_base const& fsm)
1344         {
1345             return fsm.template get_state<State>().template is_flag_active<Flag>();
1346         }
1347     };
1348     template <class Flag>
1349     struct init_flags
1350     {
1351     private:
1352         // helper function, helps hiding the forward function for non-state machines states.
1353         template <class T>
1354         void helper (flag_handler* an_entry,int offset, ::boost::mpl::true_ const &  )
1355         {
1356             // composite => forward
1357             an_entry[offset] = &FlagHandler<T,Flag>::forward;
1358         }
1359         template <class T>
1360         void helper (flag_handler* an_entry,int offset, ::boost::mpl::false_ const &  )
1361         {
1362             // default no flag
1363             an_entry[offset] = &FlagHandler<T,Flag>::flag_false;
1364         }
1365         // attributes
1366         flag_handler* entries;
1367 
1368     public:
1369         init_flags(flag_handler* entries_)
1370             : entries(entries_)
1371         {}
1372 
1373         // Flags initializer function object, used with for_each
1374         template <class State>
1375         void operator()( mp11::mp_identity<State> const& )
1376         {
1377             typedef typename get_flag_list<State>::type flags;
1378             typedef mp11::mp_contains<flags,Flag > found;
1379 
1380             BOOST_STATIC_CONSTANT(int, state_id = (get_state_id<State>()));
1381             if (found::type::value)
1382             {
1383                 // the type defined the flag => true
1384                 entries[state_id] = &FlagHandler<State,Flag>::flag_true;
1385             }
1386             else
1387             {
1388                 // false or forward
1389                 typedef typename ::boost::mpl::and_<
1390                             typename has_back_end_tag<State>::type,
1391                             typename ::boost::mpl::not_<
1392                                     typename has_non_forwarding_flag<Flag>::type>::type >::type composite_no_forward;
1393 
1394                 helper<State>(entries,state_id,::boost::mpl::bool_<composite_no_forward::type::value>());
1395             }
1396         }
1397     };
1398     // maintains for every flag a static array containing the flag value for every state
1399     template <class Flag>
1400     flag_handler* get_entries_for_flag() const
1401     {
1402         BOOST_STATIC_CONSTANT(int, max_state = (mp11::mp_size<state_set>::value));
1403 
1404         static flag_handler flags_entries[max_state];
1405         // build a state list, but only once
1406         static flag_handler* flags_entries_ptr =
1407             (mp11::mp_for_each<mp11::mp_transform<mp11::mp_identity, state_set>>
1408                             (init_flags<Flag>(flags_entries)),
1409             flags_entries);
1410         return flags_entries_ptr;
1411     }
1412 
1413     template <class Event, class Fsm, bool InitialStart = false>
1414     void internal_start(Event const& event, Fsm& fsm)
1415     {
1416         m_running = true;
1417         
1418         // Call on_entry on this SM first.
1419         static_cast<front_end_t*>(this)->on_entry(event, fsm);
1420 
1421         // Then call on_entry on the states.
1422         if constexpr (InitialStart)
1423         {
1424             mp11::mp_for_each<initial_states_identity>(
1425                 [this, &event, &fsm](auto state_identity)
1426                 {
1427                     using State = typename decltype(state_identity)::type;
1428                     execute_entry(this->get_state<State>(), event, fsm);
1429                 });
1430         }
1431         else 
1432         {
1433             // Visit active states non-recursively.
1434             visit(
1435                 [&event, &fsm](auto& state)
1436                 {
1437                     // TODO:
1438                     // Add filter to rule out impossible entry states.
1439                     execute_entry(state, event, fsm);
1440                 });
1441         }
1442         
1443         // give a chance to handle an anonymous (eventless) transition
1444         try_process_completion_event(EventSource::EVENT_SOURCE_DEFAULT, true);
1445     }
1446 
1447     // helper to find out if a SM has an active exit state and is therefore waiting for exiting
1448     template <class State, class StateOwner>
1449     inline
1450     bool is_exit_state_active()
1451     {
1452         if constexpr (has_pseudo_exit<State>::value)
1453         {
1454             typedef typename StateOwner::type Owner;
1455             Owner& owner = get_state<Owner&>();
1456             const int state_id = owner.template get_state_id<State>();
1457             for (const auto active_state_id : owner.get_active_state_ids())
1458             {
1459                 if (active_state_id == state_id)
1460                 {
1461                     return true;
1462                 }
1463             }
1464         }
1465         return false;
1466     }
1467 
1468      template <class State>
1469      struct find_region_id
1470      {
1471          template <int region,int Dummy=0>
1472          struct In
1473          {
1474              enum {region_index=region};
1475          };
1476         enum {region_index = In<State::zone_index>::region_index };
1477      };
1478 
1479     // entry for states machines which are themselves embedded in other state machines (composites)
1480     template <class Event, class Fsm>
1481     void on_entry(Event const& event, Fsm& fsm)
1482     {
1483         // block immediate handling of events
1484         m_event_processing = true;
1485         // by default we activate the history/init states, can be overwritten by direct events.
1486         m_active_state_ids = m_history.on_entry(event);
1487 
1488         // this variant is for the standard case, entry due to activation of the containing FSM
1489         if constexpr (!has_direct_entry<Event>::value)
1490         {
1491             internal_start(event, fsm);
1492         }
1493         // this variant is for the direct entry case
1494         else if constexpr (has_direct_entry<Event>::value)
1495         {
1496             // Set the new active state(s) first, this includes
1497             // a normal direct entry (or entries) and a pseudo entry.
1498             using entry_states = to_mp_list_t<typename Event::active_state>;
1499             mp11::mp_for_each<mp11::mp_transform<mp11::mp_identity, entry_states>>(
1500                 [this](auto state_identity)
1501                 {
1502                     using State = typename decltype(state_identity)::type::wrapped_entry;
1503                     static constexpr int region_index = find_region_id<State>::region_index;
1504                     static_assert(region_index >= 0 && region_index < nr_regions);
1505                     m_active_state_ids[region_index] = get_state_id<State>();
1506                 }
1507             );
1508             internal_start(event.m_event, fsm);
1509             // in case of a pseudo entry process the transition in the zone of the newly active state
1510             // (entry pseudo states are, according to UML, a state connecting 1 transition outside to 1 inside
1511             if constexpr (has_pseudo_entry<typename Event::active_state>::value)
1512             {
1513                 static_assert(!mpl::is_sequence<typename Event::active_state>::value);
1514                 process_event(event.m_event);
1515             }
1516         }
1517         // handle messages which were generated and blocked in the init calls
1518         m_event_processing = false;
1519         // look for deferred events waiting
1520         try_process_deferred_events();
1521         try_process_queued_events();
1522     }
1523     template <class Event,class Fsm>
1524     void on_exit(Event const& event, Fsm& fsm)
1525     {
1526         // first recursively exit the sub machines
1527         // forward the event for handling by sub state machines
1528         visit(
1529             [&event, &fsm](auto& state)
1530             {
1531                 // TODO:
1532                 // Filter out impossible exit states.
1533                 state.on_exit(event, fsm);
1534             }
1535         );
1536         // then call our own exit
1537         (static_cast<front_end_t*>(this))->on_exit(event,fsm);
1538         // give the history a chance to handle this (or not).
1539         m_history.on_exit(this->m_active_state_ids);
1540         // history decides what happens with deferred events
1541         if (!m_history.process_deferred_events(event))
1542         {
1543             if constexpr (deferred_events_member::value)
1544             {
1545                 get_deferred_events_queue().clear();
1546             }
1547         }
1548     }
1549 
1550     // calls entry or on_entry depending on the state type
1551     template <class State, class Event, class Fsm>
1552     static void execute_entry(State& state, Event const& event, Fsm& fsm)
1553     {
1554         // calls on_entry on the fsm then handles direct entries, fork, entry pseudo state
1555         if constexpr (has_back_end_tag<State>::value)
1556         {
1557             state.on_entry(event,fsm);
1558         }
1559         else if constexpr (has_pseudo_exit<State>::value)
1560         {
1561             // calls on_entry on the state then forward the event to the transition which should be defined inside the
1562             // contained fsm
1563             state.on_entry(event,fsm);
1564             state.forward_event(event);
1565         }
1566         else if constexpr (has_direct_entry<Event>::value)
1567         {
1568             state.on_entry(event.m_event, fsm);
1569         }
1570         else
1571         {
1572             state.on_entry(event, fsm);
1573         }
1574         
1575     }
1576 
1577     // helper allowing special handling of direct entries / fork
1578     template <class Target,class State,class Event>
1579     static void convert_event_and_execute_entry(State& state,Event const& event, state_machine_base& sm)
1580     {
1581         auto& fsm = sm.get_fsm_argument();
1582         if constexpr (has_explicit_entry_state<Target>::value || mpl::is_sequence<Target>::value)
1583         {
1584             // for the direct entry, pack the event in a wrapper so that we handle it differently during fsm entry
1585             execute_entry(state,direct_entry_event<Target,Event>(event),fsm);
1586         }
1587         else
1588         {
1589             // if the target is a normal state, do the standard entry handling
1590             execute_entry(state,event,fsm);
1591         }
1592     }
1593 
1594     template <typename State>
1595     using state_filter_predicate = mp11::mp_or<
1596         has_pseudo_exit<State>,
1597         has_back_end_tag<State>
1598         >;
1599     using states_to_init = mp11::mp_copy_if<
1600         states_t,
1601         state_filter_predicate>;
1602     
1603     // initializes the SM
1604     template <class TRootSm>
1605     void init(TRootSm& root_sm)
1606     {
1607         if constexpr (!std::is_same_v<root_sm_t, no_root_sm>)
1608         {
1609             static_assert(
1610                 std::is_same_v<TRootSm, root_sm_t>,
1611                 "The configured root_sm must match the used one"
1612             );
1613             static_assert(
1614                 std::is_same_v<context_t, no_context> ||
1615                 std::is_same_v<context_t, typename TRootSm::context_t>,
1616                 "The configured context must match the root sm's one");
1617         }
1618         m_root_sm = static_cast<void*>(&root_sm);
1619 
1620         mp11::mp_for_each<mp11::mp_transform<mp11::mp_identity, states_to_init>>(
1621             [this, &root_sm](auto state_identity)
1622             {
1623                 using State = typename decltype(state_identity)::type;
1624                 auto& state = this->get_state<State>();
1625                 
1626                 if constexpr (has_pseudo_exit<State>::value)
1627                 {
1628                     state.set_forward_fct(
1629                         [&root_sm](typename State::event const& event)
1630                         {
1631                             return root_sm.process_event(event);
1632                         }
1633                     );
1634                 }
1635 
1636                 if constexpr (is_back_end<State>::value)
1637                 {
1638                     static_assert(
1639                         std::is_same_v<compile_policy, typename State::compile_policy>,
1640                         "All compile policies must be identical"
1641                     );
1642                     state.init(root_sm);
1643                 }
1644             }
1645         );
1646     }
1647 
1648     // Dispatch table for calling invoking visitors with active states.
1649     template <typename Visitor, bool Recursive>
1650     class visitor_dispatch_table
1651     {
1652     public:
1653         visitor_dispatch_table()
1654         {
1655             using state_identities = mp11::mp_transform<mp11::mp_identity, state_set>;
1656             mp11::mp_for_each<state_identities>(
1657                 [this](auto state_identity)
1658                 {
1659                     using State = typename decltype(state_identity)::type;
1660                     m_cells[get_state_id<State>()] = &accept<State>;
1661                 }
1662             );
1663         }
1664 
1665         template<typename State>
1666         static void accept(state_machine_base& sm, Visitor visitor)
1667         {
1668             auto& state = sm.template get_state<State>();
1669             visitor(state);
1670 
1671             if constexpr (has_back_end_tag<State>::value && Recursive)
1672             {
1673                 state.template visit
1674                     <visit_mode::active_states | visit_mode::recursive>
1675                     (std::forward<Visitor>(visitor));
1676             }
1677         }
1678 
1679         static void dispatch(state_machine_base& sm, int index, Visitor visitor)
1680         {
1681             instance().m_cells[index](sm, visitor);
1682         }
1683 
1684     private:
1685         using cell_t = void (*)(state_machine_base&, Visitor);
1686 
1687         static visitor_dispatch_table& instance()
1688         {
1689             static visitor_dispatch_table instance;
1690             return instance;
1691         }
1692 
1693         cell_t m_cells[mp11::mp_size<state_set>::value];
1694     };
1695 
1696     struct optional_members :
1697         events_queue_member,
1698         deferred_events_member,
1699         context_member
1700     {
1701         template <typename T>
1702         typename T::type& get()
1703         {
1704             return static_cast<T*>(this)->instance;
1705         }
1706         template <typename T>
1707         const typename T::type& get() const
1708         {
1709             return static_cast<const T*>(this)->instance;
1710         }
1711     };
1712 
1713     // data members
1714     active_state_ids_t   m_active_state_ids;
1715     optional_members     m_optional_members;
1716     concrete_history     m_history{};
1717     bool                 m_event_processing{false};
1718     void*                m_root_sm{nullptr};
1719     states_t             m_states{};
1720     bool                 m_running{false};
1721 };
1722 
1723 } // detail
1724 
1725 /**
1726  * @brief Back-end for state machines.
1727  *
1728  * Can take 1...3 parameters.
1729  * 
1730  * @tparam T0 (mandatory) : Front-end
1731  * @tparam T1 (optional)  : State machine config
1732  * @tparam T2 (optional)  : Derived class (required when inheriting from state_machine)
1733  */
1734 template <typename ...T>
1735 class state_machine;
1736 
1737 template <class FrontEnd, class Config, class Derived>
1738 class state_machine<FrontEnd, Config, Derived>
1739     : public detail::state_machine_base<FrontEnd, Config, Derived>
1740 {
1741     using Base = detail::state_machine_base<FrontEnd, Config, Derived>;
1742   public:
1743     using Base::Base;
1744 };
1745 
1746 template <class FrontEnd, class Config>
1747 class state_machine<FrontEnd, Config>
1748     : public detail::state_machine_base<FrontEnd, Config, state_machine<FrontEnd, Config>>
1749 {
1750     using Base = detail::state_machine_base<FrontEnd, Config, state_machine<FrontEnd, Config>>;
1751   public:
1752     using Base::Base;
1753 };
1754 
1755 template <class FrontEnd>
1756 class state_machine<FrontEnd>
1757     : public detail::state_machine_base<FrontEnd, default_state_machine_config, state_machine<FrontEnd>>
1758 {
1759     using Base = detail::state_machine_base<FrontEnd, default_state_machine_config, state_machine<FrontEnd>>;
1760   public:
1761     using Base::Base;
1762 };
1763 
1764 }}} // boost::msm::backmp11
1765 
1766 #endif //BOOST_MSM_BACKMP11_STATE_MACHINE_H