// Copyright 2025 Christian Granzin // Copyright 2008 Christophe Henry // henry UNDERSCORE christophe AT hotmail DOT com // This is an extended version of the state machine available in the boost::mpl library // Distributed under the same license as the original. // Copyright for the original version: // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed // under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_MSM_BACKMP11_METAFUNCTIONS_H #define BOOST_MSM_BACKMP11_METAFUNCTIONS_H #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace msm { namespace backmp11 { namespace detail { constexpr bool has_flag(visit_mode value, visit_mode flag) { return (static_cast(value) & static_cast(flag)) != 0; } struct back_end_tag {}; template using has_back_end_tag = std::is_same; template using is_back_end = has_back_end_tag; template using is_composite = mp11::mp_or< std::is_same, has_back_end_tag >; // Call a functor on all elements of List, until the functor returns true. template constexpr bool for_each_until(Func&& func) { bool condition = false; boost::mp11::mp_for_each( [&func, &condition](auto&& item) { if (!condition) { condition = func(std::forward(item)); } } ); return condition; } // Wrapper for an instance of a type, which might not be present. template struct optional_instance; template struct optional_instance { using type = T; type instance; static constexpr bool value = true; }; template struct optional_instance { using type = T; static constexpr bool value = false; }; // Helper to convert a single type or MPL sequence to Mp11 template struct to_mp_list { typedef typename mpl::copy>>::type type; }; template struct to_mp_list::value>> { using type = mp11::mp_list; }; template struct to_mp_list> { typedef mp11::mp_list type; }; template using to_mp_list_t = typename to_mp_list::type; template struct generate_state_set; // iterates through a transition table to generate an ordered state set // first the source states, transition up to down // then the target states, up to down template struct generate_state_set { typedef to_mp_list_t stt; // first add the source states template using set_push_source_state = mp11::mp_set_push_back; using source_state_set = mp11::mp_fold, set_push_source_state>; // then add the target states template using set_push_target_state = mp11::mp_set_push_back; using state_set = mp11::mp_fold; }; // extends a state set to a map with key=state and value=id template struct generate_state_map { typedef StateSet state_set; typedef mp11::mp_iota> indices; typedef mp11::mp_transform_q< mp11::mp_bind, state_set, indices > type; }; // returns the id of a given state template struct get_state_id { typedef mp11::mp_second> type; static constexpr typename type::value_type value = type::value; }; // iterates through the transition table and generate a set containing all the events template struct generate_event_set { typedef to_mp_list_t stt_mp11; template using event_set_pusher = mp11::mp_set_push_back< V, typename T::transition_event >; typedef mp11::mp_fold< to_mp_list_t, mp11::mp_list<>, event_set_pusher > event_set_mp11; }; // extends an event set to a map with key=event and value=id template struct generate_event_map { typedef typename generate_event_set::event_set_mp11 event_set; typedef mp11::mp_iota> indices; typedef mp11::mp_transform_q< mp11::mp_bind, event_set, indices > type; }; // returns the id of a given event template struct get_event_id { typedef mp11::mp_second::type, Event >> type; enum {value = type::value}; }; template using has_state_deferred_events = mp11::mp_not< mp11::mp_empty> >; // Template used to create dummy entries for initial states not found in the stt. template< typename T1 > struct not_a_row { typedef int not_real_row_tag; struct dummy_event { }; typedef T1 current_state_type; typedef T1 next_state_type; typedef dummy_event transition_event; }; // used for states created with explicit_creation // if the state is an explicit entry, we reach for the wrapped state // otherwise, this returns the state itself template struct get_wrapped_state { template using get_wrapped_entry = typename T::wrapped_entry; using type = mp11::mp_eval_or; }; // returns the transition table of a Composite state template struct get_transition_table { typedef typename Derived::internal::template create_real_stt::type Stt; // get the state set typedef typename generate_state_set::state_set states; // iterate through the initial states and add them in the stt if not already there typedef typename Derived::internal::initial_states initial_states; template using states_pusher = mp11::mp_if_c< mp11::mp_set_contains::value, V, mp11::mp_push_back< V, not_a_row::type> > >; typedef typename mp11::mp_fold< to_mp_list_t, to_mp_list_t, states_pusher > with_init; // do the same for states marked as explicitly created template using get_explicit_creation = to_mp_list_t; using fake_explicit_created = mp11::mp_eval_or< mp11::mp_list<>, get_explicit_creation, Derived >; //converts a "fake" (simulated in a state_machine_ description )state into one which will really get created template using convert_fake_state = mp11::mp_if_c< has_direct_entry::value, typename Derived::template direct, State >; using explicit_created = mp11::mp_transform< convert_fake_state, fake_explicit_created >; typedef typename mp11::mp_fold< to_mp_list_t, with_init, states_pusher > type; }; template using get_transition_table_t = typename get_transition_table::type; // recursively builds an internal table including those of substates, sub-substates etc. // variant for submachines template struct recursive_get_internal_transition_table { // get the composite's internal table typedef typename State::front_end_t::internal_transition_table composite_table; // and for every substate (state of submachine), recursively get the internal transition table using composite_states = typename State::internal::state_set; template using append_recursive_internal_transition_table = mp11::mp_append< V, typename recursive_get_internal_transition_table::value>::type >; typedef typename mp11::mp_fold< composite_states, to_mp_list_t, append_recursive_internal_transition_table > type; }; // stop iterating on leafs (simple states) template struct recursive_get_internal_transition_table { typedef to_mp_list_t< typename State::internal_transition_table > type; }; // recursively get a transition table for a given composite state. // returns the transition table for this state + the tables of all composite sub states recursively template struct recursive_get_transition_table { // get the transition table of the state if it's a state machine typedef typename mp11::mp_eval_if_c< !has_back_end_tag::value, mp11::mp_list<>, get_transition_table_t, Composite > org_table; typedef typename generate_state_set::state_set states; // and for every substate, recursively get the transition table if it's a state machine template using append_recursive_transition_table = mp11::mp_append< V, typename recursive_get_transition_table::type >; typedef typename mp11::mp_fold< states, org_table, append_recursive_transition_table> type; }; // event used internally for wrapping a direct entry template struct direct_entry_event { public: typedef int direct_entry; typedef State active_state; typedef Event contained_event; direct_entry_event(Event const& event):m_event(event){} Event const& m_event; }; //returns the owner of an explicit_entry state //which is the containing SM if the transition originates from outside the containing SM //or else the explicit_entry state itself template struct get_owner { using type = mp11::mp_if< mp11::mp_same, State, typename State::owner >; }; template struct get_fork_owner { typedef typename ::boost::mpl::front::type seq_front; typedef typename ::boost::mpl::if_< typename ::boost::mpl::not_< typename ::boost::is_same::type>::type, typename seq_front::owner, seq_front >::type type; }; // builds flags (add internal_flag_list and flag_list). internal_flag_list is used for terminate/interrupt states template struct get_flag_list { typedef typename mp11::mp_append< to_mp_list_t, to_mp_list_t > type; }; template struct is_state_blocking { template using has_event_blocking_flag = typename has_event_blocking_flag::type; typedef typename mp11::mp_any_of< typename get_flag_list::type, has_event_blocking_flag > type; }; template using is_state_blocking_t = typename is_state_blocking::type; } // detail }}} // boost::msm::backmp11 #endif // BOOST_MSM_BACKMP11_METAFUNCTIONS_H