File indexing completed on 2026-08-17 08:50:42
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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
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
0085
0086 struct starting {};
0087
0088
0089 struct stopping {};
0090
0091 template <class ExitPoint>
0092 struct exit_pt : public ExitPoint
0093 {
0094
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
0105 template <class ForwardEvent>
0106 void forward_event(ForwardEvent const& incomingEvent)
0107 {
0108
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
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
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
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
0145 if (forward_fct)
0146 forward_fct(incomingEvent);
0147 }
0148 };
0149 };
0150
0151 template <class EntryPoint>
0152 struct entry_pt : public EntryPoint
0153 {
0154
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
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
0231
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
0238
0239
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
0247
0248
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
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);
0264 BOOST_ASSERT(state == (current_state));
0265
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
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
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
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
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
0299
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
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);
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
0321 return process_result::HANDLED_GUARD_REJECT;
0322 }
0323
0324
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
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
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
0445
0446
0447
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
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
0469 typedef int is_frow;
0470
0471
0472 static process_result execute(state_machine_base& sm, int region_index, int , transition_event const& event)
0473 {
0474
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
0481
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
0502 template <class State,bool IsComposite>
0503 struct get_internal_transition_table
0504 {
0505
0506 typedef typename recursive_get_transition_table<State>::type original_table;
0507
0508
0509
0510
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
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
0542 template <class Composite>
0543 struct extend_table
0544 {
0545
0546
0547 typedef typename Composite::stt Stt;
0548
0549
0550
0551
0552
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
0566
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
0579 typedef typename extend_table<state_machine_base>::type complete_table;
0580
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
0588
0589
0590
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
0637 template <template <typename> typename Predicate, visit_mode Mode, typename Visitor>
0638 void visit_if(Visitor&& visitor)
0639 {
0640
0641
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
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
0672 init(*static_cast<derived_t*>(this));
0673 }
0674 reset_active_state_ids();
0675 }
0676
0677
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
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
0704 init(*static_cast<derived_t*>(this));
0705 }
0706
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
0716 state_machine_base& operator= (state_machine_base const& rhs)
0717 {
0718 if (this != &rhs)
0719 {
0720 front_end_t::operator=(rhs);
0721
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
0733 void start()
0734 {
0735
0736
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
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
0756 void stop()
0757 {
0758 stop(fsm_final_event{});
0759 }
0760
0761
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
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
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
0795
0796
0797
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
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
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
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
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
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
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
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
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
0898 const active_state_ids_t& get_active_state_ids() const
0899 {
0900 return m_active_state_ids;
0901 }
0902
0903
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
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
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
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
0934 bool is_contained() const
0935 {
0936 return (static_cast<const void*>(this) != m_root_sm);
0937 }
0938
0939
0940 template <class State>
0941 State& get_state()
0942 {
0943 return std::get<std::remove_reference_t<State>>(m_states);
0944 }
0945
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
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
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
0972 template <typename Visitor>
0973 constexpr void visit(Visitor&& visitor)
0974 {
0975 visit<visit_mode::active_recursive>(std::forward<Visitor>(visitor));
0976 }
0977
0978
0979
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
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
1008
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
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
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
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
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
1086
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
1108
1109
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
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
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
1135 void try_process_queued_events()
1136 {
1137 if constexpr (events_queue_member::value)
1138 {
1139 process_queued_events();
1140 }
1141 }
1142
1143
1144
1145 template<class Event>
1146 process_result process_event_internal(Event const& event,
1147 EventSource source = EventSource::EVENT_SOURCE_DEFAULT)
1148 {
1149
1150
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
1158 if constexpr (mp11::mp_any_of<state_set, is_state_blocking_t>::value)
1159 {
1160
1161 if (is_flag_active<TerminateFlag>())
1162 {
1163 return process_result::HANDLED_TRUE;
1164 }
1165
1166
1167 if (is_flag_active<InterruptedFlag>() && !is_end_interrupt_event(event))
1168 {
1169 return process_result::HANDLED_TRUE;
1170 }
1171 }
1172
1173
1174
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
1185
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
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
1206
1207
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
1216 this->exception_caught(event, get_fsm_argument(), e);
1217 handled = process_result::HANDLED_FALSE;
1218 }
1219 BOOST_CATCH_END
1220 }
1221
1222
1223
1224 m_event_processing = false;
1225
1226
1227
1228 try_process_completion_event(source, (handled & process_result::HANDLED_TRUE));
1229
1230
1231
1232
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
1240
1241 if (!(EventSource::EVENT_SOURCE_MSG_QUEUE & source))
1242 {
1243 try_process_queued_events();
1244 }
1245 }
1246 }
1247
1248
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
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
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
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
1295
1296
1297
1298
1299
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
1312 template <class Flag,bool OrthogonalStates>
1313 struct FlagHelper
1314 {
1315 static bool helper(state_machine_base const& sm,flag_handler* )
1316 {
1317
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
1327 return flags_entries[sm.get_active_state_ids()[0]](sm);
1328 }
1329 };
1330
1331
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
1353 template <class T>
1354 void helper (flag_handler* an_entry,int offset, ::boost::mpl::true_ const & )
1355 {
1356
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
1363 an_entry[offset] = &FlagHandler<T,Flag>::flag_false;
1364 }
1365
1366 flag_handler* entries;
1367
1368 public:
1369 init_flags(flag_handler* entries_)
1370 : entries(entries_)
1371 {}
1372
1373
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
1384 entries[state_id] = &FlagHandler<State,Flag>::flag_true;
1385 }
1386 else
1387 {
1388
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
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
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
1419 static_cast<front_end_t*>(this)->on_entry(event, fsm);
1420
1421
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
1434 visit(
1435 [&event, &fsm](auto& state)
1436 {
1437
1438
1439 execute_entry(state, event, fsm);
1440 });
1441 }
1442
1443
1444 try_process_completion_event(EventSource::EVENT_SOURCE_DEFAULT, true);
1445 }
1446
1447
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
1480 template <class Event, class Fsm>
1481 void on_entry(Event const& event, Fsm& fsm)
1482 {
1483
1484 m_event_processing = true;
1485
1486 m_active_state_ids = m_history.on_entry(event);
1487
1488
1489 if constexpr (!has_direct_entry<Event>::value)
1490 {
1491 internal_start(event, fsm);
1492 }
1493
1494 else if constexpr (has_direct_entry<Event>::value)
1495 {
1496
1497
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
1510
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
1518 m_event_processing = false;
1519
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
1527
1528 visit(
1529 [&event, &fsm](auto& state)
1530 {
1531
1532
1533 state.on_exit(event, fsm);
1534 }
1535 );
1536
1537 (static_cast<front_end_t*>(this))->on_exit(event,fsm);
1538
1539 m_history.on_exit(this->m_active_state_ids);
1540
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
1551 template <class State, class Event, class Fsm>
1552 static void execute_entry(State& state, Event const& event, Fsm& fsm)
1553 {
1554
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
1562
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
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
1585 execute_entry(state,direct_entry_event<Target,Event>(event),fsm);
1586 }
1587 else
1588 {
1589
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
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
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
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 }
1724
1725
1726
1727
1728
1729
1730
1731
1732
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 }}}
1765
1766 #endif