Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions include/boost/msm/backmp11/common_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <boost/msm/back/common_types.hpp>
#include <cstddef>

namespace boost { namespace msm { namespace backmp11
namespace boost::msm::backmp11
{

using process_result = back::HandledEnum;
Expand Down Expand Up @@ -85,7 +85,6 @@ class deferred_event
};

using EventSource = back::EventSourceEnum;
using back::HandledEnum;

constexpr EventSource operator|(EventSource lhs, EventSource rhs)
{
Expand Down Expand Up @@ -146,7 +145,38 @@ class basic_unique_ptr
};

} // namespace detail
} // namespace boost::msm::backmp11

}}} // namespace boost::msm::backmp11
namespace boost::msm::back
{

// Bitwise operations for process_result.
// Defined in this header instead of back because type_traits are C++11.
// Defined in the back namespace because the operations have to be in the
// same namespace as HandledEnum.

constexpr HandledEnum operator|(HandledEnum lhs, HandledEnum rhs)
{
return static_cast<HandledEnum>(
static_cast<std::underlying_type_t<HandledEnum>>(lhs) |
static_cast<std::underlying_type_t<HandledEnum>>(rhs)
);
}

constexpr HandledEnum& operator|=(HandledEnum& lhs, HandledEnum rhs)
{
lhs = lhs | rhs;
return lhs;
}

constexpr HandledEnum operator&(HandledEnum lhs, HandledEnum rhs)
{
return static_cast<HandledEnum>(
static_cast<std::underlying_type_t<HandledEnum>>(lhs) &
static_cast<std::underlying_type_t<HandledEnum>>(rhs)
);
}

} // namespace boost::msm::back

#endif // BOOST_MSM_BACKMP11_COMMON_TYPES_H
145 changes: 56 additions & 89 deletions include/boost/msm/backmp11/detail/favor_runtime_speed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ struct compile_policy_impl<favor_runtime_speed>
return sm.template is_flag_active<EndInterruptFlag<Event>>();
}

template <typename StateMachine, typename Event>
static process_result process_event_internal(StateMachine& sm, const Event& event, EventSource source)
template <typename Event>
constexpr static const Event& normalize_event(const Event& event)
{
return sm.process_event_internal_impl(event, source);
return event;
}

template <typename StateMachine, typename Event>
Expand All @@ -73,8 +73,7 @@ struct compile_policy_impl<favor_runtime_speed>

process_result process() override
{
return process_event_internal(
m_sm,
return m_sm.process_event_internal(
m_event,
EventSource::EVENT_SOURCE_DEFERRED);
}
Expand Down Expand Up @@ -130,7 +129,7 @@ struct compile_policy_impl<favor_runtime_speed>
{
using event_list = typename StateMachine::event_set_mp11;
bool found =
for_each_until<mp11::mp_transform<mp11::mp_identity, event_list>>(
mp_for_each_until<mp11::mp_transform<mp11::mp_identity, event_list>>(
[&sm, &event](auto event_identity)
{
using KnownEvent = typename decltype(event_identity)::type;
Expand Down Expand Up @@ -177,49 +176,50 @@ struct compile_policy_impl<favor_runtime_speed>
}
};

template<typename Fsm, typename State>
template<typename StateMachine, typename State>
struct table_index
{
using type = mp11::mp_if<
mp11::mp_not<is_same<State, Fsm>>,
mp11::mp_size_t<Fsm::template get_state_id<State>() + 1>,
mp11::mp_not<is_same<State, StateMachine>>,
mp11::mp_size_t<StateMachine::template get_state_id<State>() + 1>,
mp11::mp_size_t<0>
>;
};
template<typename Fsm, typename State>
using get_table_index = typename table_index<Fsm, State>::type;
template<typename StateMachine, typename State>
using get_table_index = typename table_index<StateMachine, State>::type;

// Generates a singleton runtime lookup table that maps current state
// to a function that makes the SM take its transition on the given
// Event type.
template<class Fsm>
template<class StateMachine>
class dispatch_table
{
using Stt = typename Fsm::complete_table;
using Stt = typename StateMachine::complete_table;
public:
// Dispatch function for a specific event.
template<class Event>
using cell = HandledEnum (*)(Fsm&, int,int,Event const&);
using cell = process_result (*)(StateMachine&, int&, Event const&);

// Dispatch an event.
template<class Event>
static HandledEnum dispatch(Fsm& fsm, int region_id, int state_id, const Event& event)
static process_result dispatch(StateMachine& sm, int& state_id, const Event& event)
{
return event_dispatch_table<Event>::instance().entries[state_id+1](fsm, region_id, state_id, event);
return event_dispatch_table<Event>::instance().entries[state_id+1](sm, state_id, event);
}

// Dispatch an event to the FSM's internal table.
template<class Event>
static HandledEnum dispatch_internal(Fsm& fsm, int region_id, int state_id, const Event& event)
static process_result dispatch_internal(StateMachine& sm, const Event& event)
{
return event_dispatch_table<Event>::instance().entries[0](fsm, region_id, state_id, event);
int no_state_id;
return event_dispatch_table<Event>::instance().entries[0](sm, no_state_id, event);
}

private:
// Compute the maximum state value in the sm so we know how big
// to make the tables
typedef typename generate_state_set<Stt>::state_set state_set;
BOOST_STATIC_CONSTANT(int, max_state = (mp11::mp_size<state_set>::value));
// to make the tables.
using state_set = typename StateMachine::internal::state_set;
static constexpr int max_state = mp11::mp_size<state_set>::value;

// Dispatch table for a specific event.
template<class Event>
Expand All @@ -235,39 +235,12 @@ struct compile_policy_impl<favor_runtime_speed>
}

private:
// A function object for use with mp11::mp_for_each that stuffs transitions into cells.
class row_init_helper
{
public:
row_init_helper(event_cell* entries)
: m_entries(entries) {}

template<typename Row>
typename ::boost::disable_if<typename is_kleene_event<typename Row::transition_event>::type, void>::type
operator()(Row)
{
m_entries[get_table_index<Fsm, typename Row::current_state_type>::value] =
&Row::execute;
}

template<typename Row>
typename ::boost::enable_if<typename is_kleene_event<typename Row::transition_event>::type, void>::type
operator()(Row)
{
m_entries[get_table_index<Fsm, typename Row::current_state_type>::value] =
&convert_event_and_forward<Row>::execute;
}

private:
event_cell* m_entries;
};

static process_result execute_no_transition(Fsm&, int, int, const Event&)
static process_result execute_no_transition(StateMachine&, int&, const Event&)
{
return process_result::HANDLED_FALSE;
}

// initialize the dispatch table for a given Event and Fsm
// Initialize the dispatch table for the event
event_dispatch_table()
{
// Initialize cells for no transition
Expand All @@ -294,8 +267,6 @@ struct compile_policy_impl<favor_runtime_speed>
> chained_rows;

// Go back and fill in cells for matching transitions.
// MSVC crashes when using get_init_cells.
#if !defined(_MSC_VER)
typedef mp11::mp_transform<
preprocess_row,
chained_rows
Expand All @@ -305,67 +276,64 @@ struct compile_policy_impl<favor_runtime_speed>
get_init_cells<event_cell, chained_and_preprocessed_rows>(),
mp11::mp_size<chained_and_preprocessed_rows>::value
);
#else
mp11::mp_for_each<chained_rows>(row_init_helper{entries});
#endif
}

// class used to build a chain (or sequence) of transitions for a given event and start state
// (like an UML diamond). Allows transition conflicts.
template< typename Seq,typename AnEvent,typename State >
struct chain_row
// Class used to build a chain of transitions for a given event and state.
// Allows transition conflicts.
template< typename Seq, typename State>
struct transition_chain
{
typedef State current_state_type;
typedef AnEvent transition_event;
typedef Event transition_event;

// helper for building a disable/enable_if-controlled execute function
struct execute_helper
{
template <class Sequence>
static
HandledEnum
execute(Fsm& , int, int, Event const& , ::boost::mpl::true_ const & )
process_result
execute(StateMachine&, int& /*state_id*/, Event const&, ::boost::mpl::true_ const &)
{
// if at least one guard rejected, this will be ignored, otherwise will generate an error
return HandledEnum::HANDLED_FALSE;
return process_result::HANDLED_FALSE;
}

template <class Sequence>
static
HandledEnum
execute(Fsm& fsm, int region_index , int state, Event const& evt,
process_result
execute(StateMachine& sm, int& state_id, Event const& evt,
::boost::mpl::false_ const & )
{
// try the first guard
typedef typename ::boost::mpl::front<Sequence>::type first_row;
HandledEnum res = first_row::execute(fsm,region_index,state,evt);
if (HandledEnum::HANDLED_TRUE!=res && HandledEnum::HANDLED_DEFERRED!=res)
process_result res = first_row::execute(sm, state_id, evt);
if (process_result::HANDLED_TRUE!=res && process_result::HANDLED_DEFERRED!=res)
{
// if the first rejected, move on to the next one
HandledEnum sub_res =
execute<typename ::boost::mpl::pop_front<Sequence>::type>(fsm,region_index,state,evt,
process_result sub_res =
execute<typename ::boost::mpl::pop_front<Sequence>::type>(sm, state_id, evt,
::boost::mpl::bool_<
::boost::mpl::empty<typename ::boost::mpl::pop_front<Sequence>::type>::type::value>());
// if at least one guards rejects, the event will not generate a call to no_transition
if ((HandledEnum::HANDLED_FALSE==sub_res) && (HandledEnum::HANDLED_GUARD_REJECT==res) )
return HandledEnum::HANDLED_GUARD_REJECT;
if ((process_result::HANDLED_FALSE==sub_res) && (process_result::HANDLED_GUARD_REJECT==res) )
return process_result::HANDLED_GUARD_REJECT;
else
return sub_res;
}
return res;
}
};
// Take the transition action and return the next state.
static HandledEnum execute(Fsm& fsm, int region_index, int state, Event const& evt)
static process_result execute(StateMachine& sm, int& state_id, Event const& evt)
{
// forward to helper
return execute_helper::template execute<Seq>(fsm,region_index,state,evt,
return execute_helper::template execute<Seq>(sm, state_id, evt,
::boost::mpl::bool_< ::boost::mpl::empty<Seq>::type::value>());
}
};
// nullary metafunction whose only job is to prevent early evaluation of _1
template< typename Entry >
struct make_chain_row_from_map_entry
struct make_transition_chain_from_map_entry
{
// if we have more than one frow with the same state as source, remove the ones extra
// note: we know the frow's are located at the beginning so we remove at the beginning (number of frows - 1) elements
Expand All @@ -390,8 +358,7 @@ struct compile_policy_impl<favor_runtime_speed>
::boost::mpl::identity<typename Entry::second>
>::type filtered_stt;

typedef chain_row<filtered_stt,Event,
typename Entry::first > type;
typedef transition_chain<filtered_stt, typename Entry::first> type;
};
// helper for lazy evaluation in eval_if of change_frow_event
template <class Transition,class NewEvent>
Expand All @@ -411,13 +378,13 @@ struct compile_policy_impl<favor_runtime_speed>
>::type type;
};

template <class Row>
template <class Transition>
struct convert_event_and_forward
{
static HandledEnum execute(Fsm& fsm, int region_index, int state, Event const& evt)
static process_result execute(StateMachine& sm, int& state_id, Event const& evt)
{
typename Row::transition_event forwarded(evt);
return Row::execute(fsm,region_index,state,forwarded);
typename Transition::transition_event forwarded(evt);
return Transition::execute(sm, state_id, forwarded);
}
};

Expand Down Expand Up @@ -472,30 +439,30 @@ struct compile_policy_impl<favor_runtime_speed>
using row_chainer = mp11::mp_if_c<
(mp11::mp_size<to_mp_list_t<mp11::mp_second<T>>>::value > 1),
// we need row chaining
typename make_chain_row_from_map_entry<to_mpl_map_entry<T>>::type,
typename make_transition_chain_from_map_entry<to_mpl_map_entry<T>>::type,
// just one row, no chaining, we rebuild the row like it was before
mp11::mp_front<mp11::mp_second<T>>
>;
template<typename Row>
using preprocess_row_helper = cell_constant<&Row::execute>;
template<typename Row>
template<typename Transition>
using preprocess_row_helper = cell_constant<&Transition::execute>;
template<typename Transition>
using preprocess_row = init_cell_constant<
// Offset into the entries array
get_table_index<Fsm, typename Row::current_state_type>::value,
get_table_index<StateMachine, typename Transition::current_state_type>::value,
// Address of the execute function
mp11::mp_eval_if_c<
is_kleene_event<typename Row::transition_event>::type::value,
is_kleene_event<typename Transition::transition_event>::type::value,
cell_constant<
&convert_event_and_forward<Row>::execute
&convert_event_and_forward<Transition>::execute
>,
preprocess_row_helper,
Row
Transition
>::value
>;

// data members
public:
// max_state+1, because 0 is reserved for this fsm (internal transitions)
// max_state+1, because 0 is reserved for this sm (internal transitions)
event_cell entries[max_state+1];
};
};
Expand Down
Loading