Back to home page

EIC code displayed by LXR

 
 

    


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

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_METAFUNCTIONS_H
0013 #define BOOST_MSM_BACKMP11_METAFUNCTIONS_H
0014 
0015 #include <boost/mp11.hpp>
0016 #include <boost/mp11/mpl_list.hpp>
0017 
0018 #include <boost/mpl/copy.hpp>
0019 #include <boost/mpl/is_sequence.hpp>
0020 #include <boost/mpl/front.hpp>
0021 
0022 #include <boost/type_traits/is_same.hpp>
0023 #include <boost/utility/enable_if.hpp>
0024 
0025 #include <boost/msm/row_tags.hpp>
0026 
0027 #include <boost/msm/backmp11/common_types.hpp>
0028 #include <boost/msm/back/traits.hpp>
0029 #include <boost/msm/front/detail/common_states.hpp>
0030 
0031 
0032 namespace boost { namespace msm { namespace backmp11
0033 {
0034 
0035 namespace detail
0036 {
0037 
0038 constexpr bool has_flag(visit_mode value, visit_mode flag)
0039 {
0040     return (static_cast<int>(value) & static_cast<int>(flag)) != 0;
0041 }
0042 
0043 struct back_end_tag {};
0044 
0045 template <typename T>
0046 using has_back_end_tag = std::is_same<typename T::internal::tag, back_end_tag>;
0047 
0048 template <class T>
0049 using is_back_end = has_back_end_tag<T>;
0050 
0051 template <typename T>
0052 using is_composite = mp11::mp_or<
0053     std::is_same<typename T::internal::tag, msm::front::detail::composite_state_tag>,
0054     has_back_end_tag<T>
0055     >;
0056 
0057 // Call a functor on all elements of List, until the functor returns true.
0058 template <typename List, typename Func>
0059 constexpr bool for_each_until(Func&& func)
0060 {
0061     bool condition = false;
0062 
0063     boost::mp11::mp_for_each<List>(
0064         [&func, &condition](auto&& item)
0065         {
0066             if (!condition)
0067             {
0068                 condition = func(std::forward<decltype(item)>(item));
0069             }
0070         }
0071     );
0072     return condition;
0073 }
0074 
0075 // Wrapper for an instance of a type, which might not be present.
0076 template<typename T, bool C>
0077 struct optional_instance;
0078 template <typename T>
0079 struct optional_instance<T, true>
0080 {
0081     using type = T;
0082     type instance;
0083     static constexpr bool value = true;
0084 };
0085 template<typename T>
0086 struct optional_instance<T, false>
0087 {
0088     using type = T;
0089     static constexpr bool value = false;
0090 };
0091 
0092 // Helper to convert a single type or MPL sequence to Mp11
0093 template<typename T, typename Enable = void>
0094 struct to_mp_list
0095 {
0096     typedef typename mpl::copy<T, mpl::back_inserter<mp11::mp_list<>>>::type type;
0097 };
0098 template<typename T>
0099 struct to_mp_list<T, std::enable_if_t<!mpl::is_sequence<T>::value>>
0100 {
0101     using type = mp11::mp_list<T>;
0102 };
0103 template<typename ...T>
0104 struct to_mp_list<mp11::mp_list<T...>>
0105 {
0106     typedef mp11::mp_list<T...> type;
0107 };
0108 template<typename ...T>
0109 using to_mp_list_t = typename to_mp_list<T...>::type;
0110 
0111 template <class stt>
0112 struct generate_state_set;
0113 
0114 // iterates through a transition table to generate an ordered state set
0115 // first the source states, transition up to down
0116 // then the target states, up to down
0117 template <class Stt>
0118 struct generate_state_set
0119 {
0120     typedef to_mp_list_t<Stt> stt;
0121     // first add the source states
0122     template <typename V, typename T>
0123     using set_push_source_state =
0124         mp11::mp_set_push_back<V, typename T::current_state_type>;
0125     using source_state_set =
0126         mp11::mp_fold<stt, mp11::mp_list<>, set_push_source_state>;
0127     // then add the target states
0128     template <typename V, typename T>
0129     using set_push_target_state =
0130         mp11::mp_set_push_back<V, typename T::next_state_type>;
0131     using state_set =
0132         mp11::mp_fold<stt, source_state_set, set_push_target_state>;
0133 };
0134 
0135 // extends a state set to a map with key=state and value=id
0136 template <class StateSet>
0137 struct generate_state_map
0138 {
0139     typedef StateSet state_set;
0140     typedef mp11::mp_iota<mp11::mp_size<state_set>> indices;
0141     typedef mp11::mp_transform_q<
0142         mp11::mp_bind<mp11::mp_list, mp11::_1, mp11::_2>,
0143         state_set,
0144         indices
0145         > type;
0146 };
0147 
0148 // returns the id of a given state
0149 template <class StateMap, class State>
0150 struct get_state_id
0151 {
0152     typedef mp11::mp_second<mp11::mp_map_find<
0153         StateMap,
0154         State
0155         >> type;
0156     
0157     static constexpr typename type::value_type value = type::value;
0158 };
0159 
0160 // iterates through the transition table and generate a set containing all the events
0161 template <class stt>
0162 struct generate_event_set
0163 {
0164     typedef to_mp_list_t<stt> stt_mp11;
0165     template<typename V, typename T>
0166     using event_set_pusher = mp11::mp_set_push_back<
0167         V,
0168         typename T::transition_event
0169         >;
0170     typedef mp11::mp_fold<
0171         to_mp_list_t<stt>,
0172         mp11::mp_list<>,
0173         event_set_pusher
0174         > event_set_mp11;
0175 };
0176 
0177 // extends an event set to a map with key=event and value=id
0178 template <class stt>
0179 struct generate_event_map
0180 {
0181     typedef typename generate_event_set<stt>::event_set_mp11 event_set;
0182     typedef mp11::mp_iota<mp11::mp_size<event_set>> indices;
0183     typedef mp11::mp_transform_q<
0184         mp11::mp_bind<mp11::mp_list, mp11::_1, mp11::_2>,
0185         event_set,
0186         indices
0187         > type;
0188 };
0189 
0190 // returns the id of a given event
0191 template <class stt,class Event>
0192 struct get_event_id
0193 {
0194     typedef mp11::mp_second<mp11::mp_map_find<
0195         typename generate_event_map<stt>::type,
0196         Event
0197         >> type;
0198     enum {value = type::value};
0199 };
0200 
0201 template <class State>
0202 using has_state_deferred_events = mp11::mp_not<
0203     mp11::mp_empty<to_mp_list_t<typename State::deferred_events>>
0204     >;
0205 
0206 // Template used to create dummy entries for initial states not found in the stt.
0207 template< typename T1 >
0208 struct not_a_row
0209 {
0210     typedef int not_real_row_tag;
0211     struct dummy_event 
0212     {
0213     };
0214     typedef T1                  current_state_type;
0215     typedef T1                  next_state_type;
0216     typedef dummy_event         transition_event;
0217 };
0218 
0219 // used for states created with explicit_creation
0220 // if the state is an explicit entry, we reach for the wrapped state
0221 // otherwise, this returns the state itself
0222 template <class State>
0223 struct get_wrapped_state 
0224 {
0225     template <typename T>
0226     using get_wrapped_entry = typename T::wrapped_entry;
0227     using type = mp11::mp_eval_or<State, get_wrapped_entry, State>;
0228 };
0229 
0230 // returns the transition table of a Composite state
0231 template <class Derived>
0232 struct get_transition_table
0233 {
0234     typedef typename Derived::internal::template create_real_stt<typename Derived::front_end_t>::type Stt;
0235     // get the state set
0236     typedef typename generate_state_set<Stt>::state_set states;
0237     // iterate through the initial states and add them in the stt if not already there
0238     typedef typename Derived::internal::initial_states initial_states;
0239     template<typename V, typename T>
0240     using states_pusher = mp11::mp_if_c<
0241         mp11::mp_set_contains<states, T>::value,
0242         V,
0243         mp11::mp_push_back<
0244             V,
0245             not_a_row<typename get_wrapped_state<T>::type>
0246             >
0247         >;
0248     typedef typename mp11::mp_fold<
0249         to_mp_list_t<initial_states>,
0250         to_mp_list_t<Stt>,
0251         states_pusher
0252         > with_init;
0253 
0254     // do the same for states marked as explicitly created
0255     template<typename T>
0256     using get_explicit_creation = to_mp_list_t<typename T::explicit_creation>;
0257     using fake_explicit_created = mp11::mp_eval_or<
0258             mp11::mp_list<>,
0259             get_explicit_creation,
0260             Derived
0261             >;
0262     //converts a "fake" (simulated in a state_machine_ description )state into one which will really get created
0263     template <class State>
0264     using convert_fake_state = mp11::mp_if_c<
0265         has_direct_entry<State>::value,
0266         typename Derived::template direct<State>,
0267         State
0268         >;
0269     using explicit_created = mp11::mp_transform<
0270         convert_fake_state,
0271         fake_explicit_created
0272         >;
0273     
0274     typedef typename mp11::mp_fold<
0275         to_mp_list_t<explicit_created>,
0276         with_init,
0277         states_pusher
0278         > type;
0279 };
0280 template<typename T>
0281 using get_transition_table_t = typename get_transition_table<T>::type;
0282 
0283 // recursively builds an internal table including those of substates, sub-substates etc.
0284 // variant for submachines
0285 template <class State, bool IsComposite>
0286 struct recursive_get_internal_transition_table
0287 {
0288     // get the composite's internal table
0289     typedef typename State::front_end_t::internal_transition_table composite_table;
0290     // and for every substate (state of submachine), recursively get the internal transition table
0291     using composite_states = typename State::internal::state_set;
0292     template<typename V, typename SubState>
0293     using append_recursive_internal_transition_table = mp11::mp_append<
0294         V,
0295         typename recursive_get_internal_transition_table<SubState, has_back_end_tag<SubState>::value>::type
0296         >;
0297     typedef typename mp11::mp_fold<
0298         composite_states,
0299         to_mp_list_t<composite_table>,
0300         append_recursive_internal_transition_table
0301         > type;
0302 };
0303 // stop iterating on leafs (simple states)
0304 template <class State>
0305 struct recursive_get_internal_transition_table<State, false>
0306 {
0307     typedef to_mp_list_t<
0308         typename State::internal_transition_table
0309         > type;
0310 };
0311 // recursively get a transition table for a given composite state.
0312 // returns the transition table for this state + the tables of all composite sub states recursively
0313 template <class Composite>
0314 struct recursive_get_transition_table
0315 {
0316     // get the transition table of the state if it's a state machine
0317     typedef typename mp11::mp_eval_if_c<
0318         !has_back_end_tag<Composite>::value,
0319         mp11::mp_list<>,
0320         get_transition_table_t,
0321         Composite
0322         > org_table;
0323 
0324     typedef typename generate_state_set<org_table>::state_set states;
0325 
0326     // and for every substate, recursively get the transition table if it's a state machine
0327     template<typename V, typename T>
0328     using append_recursive_transition_table = mp11::mp_append<
0329         V,
0330         typename recursive_get_transition_table<T>::type
0331         >;
0332     typedef typename mp11::mp_fold<
0333         states,
0334         org_table,
0335         append_recursive_transition_table> type;
0336 };
0337 
0338 // event used internally for wrapping a direct entry
0339 template <class State, class Event>
0340 struct direct_entry_event
0341 {
0342   public:
0343     typedef int direct_entry;
0344     typedef State active_state;
0345     typedef Event contained_event;
0346 
0347     direct_entry_event(Event const& event):m_event(event){}
0348     Event const& m_event;
0349 };
0350 
0351 //returns the owner of an explicit_entry state
0352 //which is the containing SM if the transition originates from outside the containing SM
0353 //or else the explicit_entry state itself
0354 template <class State,class ContainingSM>
0355 struct get_owner 
0356 {
0357     using type = mp11::mp_if<
0358         mp11::mp_same<typename State::owner, ContainingSM>,
0359         State,
0360         typename State::owner
0361         >;
0362 };
0363 
0364 
0365 template <class Sequence, class ContainingSM>
0366 struct get_fork_owner 
0367 {
0368     typedef typename ::boost::mpl::front<Sequence>::type seq_front;
0369     typedef typename ::boost::mpl::if_<
0370                     typename ::boost::mpl::not_<
0371                         typename ::boost::is_same<typename seq_front::owner,ContainingSM>::type>::type,
0372                     typename seq_front::owner, 
0373                     seq_front >::type type;
0374 };
0375 
0376 // builds flags (add internal_flag_list and flag_list). internal_flag_list is used for terminate/interrupt states
0377 template <class State>
0378 struct get_flag_list
0379 {
0380     typedef typename mp11::mp_append<
0381         to_mp_list_t<typename State::flag_list>,
0382         to_mp_list_t<typename State::internal_flag_list>
0383         > type;
0384 };
0385 
0386 template <class State>
0387 struct is_state_blocking 
0388 {
0389     template<typename T>
0390     using has_event_blocking_flag = typename has_event_blocking_flag<T>::type;
0391     typedef typename mp11::mp_any_of<
0392         typename get_flag_list<State>::type,
0393         has_event_blocking_flag
0394         > type;
0395 
0396 };
0397 template<typename T>
0398 using is_state_blocking_t = typename is_state_blocking<T>::type;
0399 
0400 } // detail
0401 
0402 }}} // boost::msm::backmp11
0403 
0404 #endif // BOOST_MSM_BACKMP11_METAFUNCTIONS_H