#include <boost/type_traits/is_convertible.hpp>
#include <boost/bind.hpp>
-#include <boost/bind/apply.hpp>
#include <boost/function.hpp>
#ifndef BOOST_NO_RTTI
#include <boost/any.hpp>
#endif
-#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/base_object.hpp>
#include <boost/parameter.hpp>
BOOST_MPL_HAS_XXX_TRAIT_DEF(compile_policy)
BOOST_MPL_HAS_XXX_TRAIT_DEF(queue_container_policy)
BOOST_MPL_HAS_XXX_TRAIT_DEF(using_declared_table)
+BOOST_MPL_HAS_XXX_TRAIT_DEF(event_queue_before_deferred_queue)
#ifndef BOOST_MSM_CONSTRUCTOR_ARG_SIZE
#define BOOST_MSM_CONSTRUCTOR_ARG_SIZE 5 // default max number of arguments for constructors
{
// event used internally for wrapping a direct entry
template <class StateType,class Event>
-struct direct_entry_event
+struct direct_entry_event
{
typedef int direct_entry;
typedef StateType active_state;
typedef ::boost::parameter::parameters<
::boost::parameter::required< ::boost::msm::back::tag::front_end >
- , ::boost::parameter::optional<
- ::boost::parameter::deduced< ::boost::msm::back::tag::history_policy>, has_history_policy< ::boost::mpl::_ >
+ , ::boost::parameter::optional<
+ ::boost::parameter::deduced< ::boost::msm::back::tag::history_policy>, has_history_policy< ::boost::mpl::_ >
>
- , ::boost::parameter::optional<
- ::boost::parameter::deduced< ::boost::msm::back::tag::compile_policy>, has_compile_policy< ::boost::mpl::_ >
+ , ::boost::parameter::optional<
+ ::boost::parameter::deduced< ::boost::msm::back::tag::compile_policy>, has_compile_policy< ::boost::mpl::_ >
>
- , ::boost::parameter::optional<
- ::boost::parameter::deduced< ::boost::msm::back::tag::fsm_check_policy>, has_fsm_check< ::boost::mpl::_ >
+ , ::boost::parameter::optional<
+ ::boost::parameter::deduced< ::boost::msm::back::tag::fsm_check_policy>, has_fsm_check< ::boost::mpl::_ >
>
- , ::boost::parameter::optional<
- ::boost::parameter::deduced< ::boost::msm::back::tag::queue_container_policy>,
- has_queue_container_policy< ::boost::mpl::_ >
+ , ::boost::parameter::optional<
+ ::boost::parameter::deduced< ::boost::msm::back::tag::queue_container_policy>,
+ has_queue_container_policy< ::boost::mpl::_ >
>
> state_machine_signature;
, public make_euml_terminal<state_machine<A0,A1,A2,A3,A4>,
typename ::boost::parameter::binding<
typename state_machine_signature::bind<A0,A1,A2,A3,A4>::type, ::boost::msm::back::tag::front_end
- >::type
+ >::type
>
{
public:
state_machine_args, ::boost::msm::back::tag::fsm_check_policy, no_fsm_check >::type FsmCheckPolicy;
typedef typename ::boost::parameter::binding<
- state_machine_args, ::boost::msm::back::tag::queue_container_policy,
+ state_machine_args, ::boost::msm::back::tag::queue_container_policy,
queue_container_deque >::type QueueContainerPolicy;
-private:
+private:
typedef boost::msm::back::state_machine<
A0,A1,A2,A3,A4> library_sm;
typedef ::boost::function<
execute_return () > deferred_fct;
typedef typename QueueContainerPolicy::
- template In<
- std::pair<deferred_fct,bool> >::type deferred_events_queue_t;
+ template In<
+ std::pair<deferred_fct,char> >::type deferred_events_queue_t;
typedef typename QueueContainerPolicy::
template In<transition_fct>::type events_queue_t;
// helper to add, if needed, visitors to all states
// version without visitors
template <class StateType,class Enable=void>
- struct visitor_fct_helper
+ struct visitor_fct_helper
{
public:
visitor_fct_helper(){}
};
// version with visitors
template <class StateType>
- struct visitor_fct_helper<StateType,typename ::boost::enable_if<has_accept_sig<StateType> >::type>
+ struct visitor_fct_helper<StateType,typename ::boost::enable_if<has_accept_sig<StateType> >::type>
{
public:
visitor_fct_helper():m_state_visitors(){}
};
template <class StateType,class Enable=int>
- struct deferred_msg_queue_helper
+ struct deferred_msg_queue_helper
{
void clear(){}
};
template <class StateType>
struct deferred_msg_queue_helper<StateType,
- typename ::boost::enable_if<
- typename ::boost::msm::back::has_fsm_deferred_events<StateType>::type,int >::type>
+ typename ::boost::enable_if<
+ typename ::boost::msm::back::has_fsm_deferred_events<StateType>::type,int >::type>
{
public:
- deferred_msg_queue_helper():m_deferred_events_queue(){}
+ deferred_msg_queue_helper():m_deferred_events_queue(),m_cur_seq(0){}
void clear()
{
m_deferred_events_queue.clear();
}
deferred_events_queue_t m_deferred_events_queue;
+ char m_cur_seq;
};
- public:
+ public:
// tags
typedef int composite_tag;
typedef Derived ConcreteSM;
// if the front-end fsm provides an initial_event typedef, replace InitEvent by this one
- typedef typename ::boost::mpl::eval_if<
+ typedef typename ::boost::mpl::eval_if<
typename has_initial_event<Derived>::type,
get_initial_event<Derived>,
::boost::mpl::identity<InitEvent>
>::type fsm_initial_event;
// if the front-end fsm provides an exit_event typedef, replace ExitEvent by this one
- typedef typename ::boost::mpl::eval_if<
+ typedef typename ::boost::mpl::eval_if<
typename has_final_event<Derived>::type,
get_final_event<Derived>,
::boost::mpl::identity<ExitEvent>
typedef int pseudo_exit;
typedef library_sm owner;
typedef int no_automatic_create;
- typedef typename
+ typedef typename
ExitPoint::event Event;
typedef ::boost::function<execute_return (Event const&)>
forwarding_function;
void set_forward_fct(::boost::function<execute_return (Event const&)> fct)
{
m_forward = fct;
- }
+ }
exit_pt():m_forward(){}
// by assignments, we keep our forwarding functor unchanged as our containing SM did not change
template <class RHS>
exit_pt(RHS&):m_forward(){}
- exit_pt<ExitPoint>& operator= (const exit_pt<ExitPoint>& )
- {
- return *this;
- }
+ exit_pt<ExitPoint>& operator= (const exit_pt<ExitPoint>& )
+ {
+ return *this;
+ }
private:
forwarding_function m_forward;
BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<stt,next_state_type>::type::value));
BOOST_ASSERT(state == (current_state));
// if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
- if (has_pseudo_exit<T1>::type::value &&
+ if (has_pseudo_exit<T1>::type::value &&
!is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
{
return HANDLED_FALSE;
BOOST_STATIC_CONSTANT(int, next_state = (get_state_id<stt,next_state_type>::type::value));
BOOST_ASSERT(state == (current_state));
// if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
- if (has_pseudo_exit<T1>::type::value &&
+ if (has_pseudo_exit<T1>::type::value &&
!is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
{
return HANDLED_FALSE;
template<
typename ROW
>
- struct a_row_
+ struct a_row_
{
//typedef typename ROW::Source T1;
typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
BOOST_ASSERT(state == (current_state));
// if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
- if (has_pseudo_exit<T1>::type::value &&
+ if (has_pseudo_exit<T1>::type::value &&
!is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
{
return HANDLED_FALSE;
BOOST_ASSERT(state == (current_state));
// if T1 is an exit pseudo state, then take the transition only if the pseudo exit state is active
- if (has_pseudo_exit<T1>::type::value &&
+ if (has_pseudo_exit<T1>::type::value &&
!is_exit_state_active<T1,get_owner<T1,library_sm> >(fsm))
{
return HANDLED_FALSE;
template<
typename ROW
>
- struct a_irow_
+ struct a_irow_
{
typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
template<
typename ROW
>
- struct _irow_
+ struct _irow_
{
typedef typename make_entry<typename ROW::Source,library_sm>::type T1;
typedef typename make_exit<typename ROW::Target,library_sm>::type T2;
static HandledEnum execute(library_sm& fsm, int region_index, int , transition_event const& evt)
{
// false as second parameter because this event is forwarded from outer fsm
- execute_return res =
- (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list)).process_event_internal(evt,false);
+ execute_return res =
+ (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list)).process_event_internal(evt);
fsm.m_states[region_index]=get_state_id<stt,T1>::type::value;
return res;
}
// add to the stt the initial states which could be missing (if not being involved in a transition)
template <class BaseType, class stt_simulated = typename BaseType::transition_table>
- struct create_real_stt
+ struct create_real_stt
{
//typedef typename BaseType::transition_table stt_simulated;
typedef typename ::boost::mpl::fold<
make_row_tag< ::boost::mpl::placeholders::_2 , StateType> >
>::type recursive_istt_with_tag;
- typedef typename ::boost::mpl::insert_range< original_table, typename ::boost::mpl::end<original_table>::type,
+ typedef typename ::boost::mpl::insert_range< original_table, typename ::boost::mpl::end<original_table>::type,
recursive_istt_with_tag>::type table_with_all_events;
// and add for every event a forwarding row
// for every state, add its transition table (if any)
// transformed as frow
typedef typename ::boost::mpl::fold<state_list,stt_plus_internal,
- ::boost::mpl::insert_range<
- ::boost::mpl::placeholders::_1,
+ ::boost::mpl::insert_range<
+ ::boost::mpl::placeholders::_1,
::boost::mpl::end< ::boost::mpl::placeholders::_1>,
- get_internal_transition_table<
+ get_internal_transition_table<
::boost::mpl::placeholders::_2,
- is_composite_state< ::boost::mpl::placeholders::_2> > >
+ is_composite_state< ::boost::mpl::placeholders::_2> > >
>::type type;
};
// extend the table with tables from composite states
template<class Event>
execute_return process_event(Event const& evt)
{
- return process_event_internal(evt,true);
+ return process_event_internal(evt, EVENT_SOURCE_DIRECT);
}
template <class EventType>
void enqueue_event_helper(EventType const& evt, ::boost::mpl::false_ const &)
{
- execute_return (library_sm::*pf) (EventType const& evt) =
- &library_sm::process_event;
+ execute_return (library_sm::*pf) (EventType const&, EventSource) =
+ &library_sm::process_event_internal;
- transition_fct f = ::boost::bind(pf,this,evt);
- m_events_queue.m_events_queue.push_back(f);
+ m_events_queue.m_events_queue.push_back(
+ ::boost::bind(
+ pf, this, evt,
+ static_cast<EventSource>(EVENT_SOURCE_MSG_QUEUE)));
}
template <class EventType>
void enqueue_event_helper(EventType const& , ::boost::mpl::true_ const &)
serialize_state(Archive& ar):ar_(ar){}
template<typename T>
- typename ::boost::enable_if<
+ typename ::boost::enable_if<
typename ::boost::mpl::or_<
typename has_do_serialize<T>::type,
typename is_composite_state<T>::type
>::type
- ,void
+ ,void
>::type
operator()(T& t) const
{
ar_ & t;
}
template<typename T>
- typename ::boost::disable_if<
+ typename ::boost::disable_if<
typename ::boost::mpl::or_<
typename has_do_serialize<T>::type,
typename is_composite_state<T>::type
>::type
- ,void
+ ,void
>::type
operator()(T&) const
{
}
Archive& ar_;
};
-
+
template<class Archive>
void serialize(Archive & ar, const unsigned int)
{
- // invoke serialization of the base class
+ // invoke serialization of the base class
(serialize_state<Archive>(ar))(boost::serialization::base_object<Derived>(*this));
// now our attributes
ar & m_states;
}
// linearly search for the state with the given id
- struct get_state_id_helper
+ struct get_state_id_helper
{
get_state_id_helper(int id,const BaseState** res,const library_sm* self_):
result_state(res),searched_id(id),self(self_) {}
BaseState* get_state_by_id(int id)
{
const BaseState* result_state=0;
- ::boost::mpl::for_each<state_list,
+ ::boost::mpl::for_each<state_list,
::boost::msm::wrap< ::boost::mpl::placeholders::_1> > (get_state_id_helper(id,&result_state,this));
return const_cast<BaseState*>(result_state);
}
typename ::boost::enable_if<typename ::boost::is_pointer<State>::type,State >::type
get_state(::boost::msm::back::dummy<0> = 0)
{
- return &(static_cast<typename boost::add_reference<typename ::boost::remove_pointer<State>::type>::type >
+ return &(static_cast<typename boost::add_reference<typename ::boost::remove_pointer<State>::type>::type >
(::boost::fusion::at_key<typename ::boost::remove_pointer<State>::type>(m_substate_list)));
}
// as a reference
bool res = (*flags_entries[ m_states[0] ])(*this);
for (int i = 1; i < nr_regions::value ; ++i)
{
- res = typename BinaryOp::type() (res,(*flags_entries[ m_states[i] ])(*this));
+ res = typename BinaryOp::type() (res,(*flags_entries[ m_states[i] ])(*this));
}
return res;
}
// to call this function, you need either a state with a deferred_events typedef
// or that the fsm provides the activate_deferred_events typedef
BOOST_MPL_ASSERT(( has_fsm_deferred_events<library_sm> ));
- execute_return (library_sm::*pf) (Event const& evt)= &library_sm::process_event;
- Event temp (e);
- ::boost::function<execute_return () > f= ::boost::bind(pf, this,temp);
- post_deferred_event(f);
+ execute_return (library_sm::*pf) (Event const&, EventSource) =
+ &library_sm::process_event_internal;
+
+ // Deferred events are added with a correlation sequence that helps to
+ // identify when an event was added - This is typically to distinguish
+ // between events deferred in this processing versus previous.
+ m_deferred_events_queue.m_deferred_events_queue.push_back(
+ std::make_pair(
+ ::boost::bind(
+ pf, this, e, static_cast<EventSource>(EVENT_SOURCE_DIRECT|EVENT_SOURCE_DEFERRED)),
+ static_cast<char>(m_deferred_events_queue.m_cur_seq+1)));
}
protected: // interface for the derived class
template <class Expr>
void set_states(Expr const& expr)
{
- ::boost::fusion::for_each(
- ::boost::fusion::as_vector(FoldToList()(expr, boost::fusion::nil())),update_state(this->m_substate_list));
+ ::boost::fusion::for_each(
+ ::boost::fusion::as_vector(FoldToList()(expr, boost::fusion::nil_())),update_state(this->m_substate_list));
}
// Construct with the default initial states
state_machine<A0,A1,A2,A3,A4 >()
:Derived()
- ,m_events_queue()
+ ,m_events_queue()
,m_deferred_events_queue()
,m_history()
,m_event_processing(false)
state_machine<A0,A1,A2,A3,A4 >
(Expr const& expr,typename ::boost::enable_if<typename ::boost::proto::is_expr<Expr>::type >::type* =0)
:Derived()
- ,m_events_queue()
+ ,m_events_queue()
,m_deferred_events_queue()
,m_history()
,m_event_processing(false)
fill_states(this);
}
// Construct with the default initial states and some default argument(s)
+#if defined (BOOST_NO_CXX11_RVALUE_REFERENCES) \
+ || defined (BOOST_NO_CXX11_VARIADIC_TEMPLATES) \
+ || defined (BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS)
#define MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB(z, n, unused) ARG ## n t ## n
#define MSM_CONSTRUCTOR_HELPER_EXECUTE(z, n, unused) \
template <BOOST_PP_ENUM_PARAMS(n, class ARG)> \
#undef MSM_CONSTRUCTOR_HELPER_EXECUTE
#undef MSM_CONSTRUCTOR_HELPER_EXECUTE_SUB
+#else
+ template <class ARG0,class... ARG,class=typename ::boost::disable_if<typename ::boost::proto::is_expr<ARG0>::type >::type>
+ state_machine<A0,A1,A2,A3,A4
+ >(ARG0&& t0,ARG&&... t)
+ :Derived(std::forward<ARG0>(t0), std::forward<ARG>(t)...)
+ ,m_events_queue()
+ ,m_deferred_events_queue()
+ ,m_history()
+ ,m_event_processing(false)
+ ,m_is_included(false)
+ ,m_visitors()
+ ,m_substate_list()
+ {
+ ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
+ (init_states(m_states));
+ m_history.set_initial_states(m_states);
+ fill_states(this);
+ }
+ template <class Expr,class... ARG,class=typename ::boost::enable_if<typename ::boost::proto::is_expr<Expr>::type >::type>
+ state_machine<A0,A1,A2,A3,A4
+ >(Expr const& expr,ARG&&... t)
+ :Derived(std::forward<ARG>(t)...)
+ ,m_events_queue()
+ ,m_deferred_events_queue()
+ ,m_history()
+ ,m_event_processing(false)
+ ,m_is_included(false)
+ ,m_visitors()
+ ,m_substate_list()
+ {
+ BOOST_MPL_ASSERT_MSG(
+ ( ::boost::proto::matches<Expr, FoldToList>::value),
+ THE_STATES_EXPRESSION_PASSED_DOES_NOT_MATCH_GRAMMAR,
+ (FoldToList));
+ ::boost::mpl::for_each< seq_initial_states, ::boost::msm::wrap<mpl::placeholders::_1> >
+ (init_states(m_states));
+ m_history.set_initial_states(m_states);
+ set_states(expr);
+ fill_states(this);
+ }
+#endif
// assignment operator using the copy policy to decide if non_copyable, shallow or deep copying is necessary
library_sm& operator= (library_sm const& rhs)
{
- if (this != &rhs)
+ if (this != &rhs)
{
Derived::operator=(rhs);
do_copy(rhs);
}
return *this;
}
- state_machine<A0,A1,A2,A3,A4>
+ state_machine<A0,A1,A2,A3,A4>
(library_sm const& rhs)
: Derived(rhs)
{
- if (this != &rhs)
+ if (this != &rhs)
{
// initialize our list of states with the ones defined in Derived::initial_state
fill_states(this);
return true;
// if the state machine is interrupted, do not handle any event
// unless the event is the end interrupt event
- if ( is_flag_active< ::boost::msm::InterruptedFlag>() &&
+ if ( is_flag_active< ::boost::msm::InterruptedFlag>() &&
!is_flag_active< ::boost::msm::EndInterruptFlag<Event> >())
return true;
return false;
// no terminate/interrupt states detected
return false;
}
+ void do_handle_prio_msg_queue_deferred_queue(EventSource source, HandledEnum handled, ::boost::mpl::true_ const &)
+ {
+ // non-default. Handle msg queue with higher prio than deferred queue
+ if (!(EVENT_SOURCE_MSG_QUEUE & source))
+ {
+ do_post_msg_queue_helper(
+ ::boost::mpl::bool_<
+ is_no_message_queue<library_sm>::type::value>());
+ if (!(EVENT_SOURCE_DEFERRED & source))
+ {
+ handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
+ defer_helper.do_handle_deferred(HANDLED_TRUE & handled);
+ }
+ }
+ }
+ void do_handle_prio_msg_queue_deferred_queue(EventSource source, HandledEnum handled, ::boost::mpl::false_ const &)
+ {
+ // default. Handle deferred queue with higher prio than msg queue
+ if (!(EVENT_SOURCE_DEFERRED & source))
+ {
+ handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
+ defer_helper.do_handle_deferred(HANDLED_TRUE & handled);
+
+ // Handle any new events generated into the queue, but only if
+ // we're not already processing from the message queue.
+ if (!(EVENT_SOURCE_MSG_QUEUE & source))
+ {
+ do_post_msg_queue_helper(
+ ::boost::mpl::bool_<
+ is_no_message_queue<library_sm>::type::value>());
+ }
+ }
+ }
// the following functions handle pre/post-process handling of a message queue
template <class StateType,class EventType>
bool do_pre_msg_queue_helper(EventType const&, ::boost::mpl::true_ const &)
template <class StateType,class EventType>
bool do_pre_msg_queue_helper(EventType const& evt, ::boost::mpl::false_ const &)
{
- execute_return (library_sm::*pf) (EventType const& evt) =
- &library_sm::process_event;
+ execute_return (library_sm::*pf) (EventType const&, EventSource) =
+ &library_sm::process_event_internal;
+
// if we are already processing an event
if (m_event_processing)
{
// event has to be put into the queue
- transition_fct f = ::boost::bind(pf,this,evt);
- m_events_queue.m_events_queue.push_back(f);
+ m_events_queue.m_events_queue.push_back(
+ ::boost::bind(
+ pf, this, evt,
+ static_cast<EventSource>(EVENT_SOURCE_DIRECT | EVENT_SOURCE_MSG_QUEUE)));
+
return false;
}
+
// event can be handled, processing
m_event_processing = true;
return true;
}
void do_post_msg_queue_helper( ::boost::mpl::false_ const &)
{
- m_event_processing = false;
process_message_queue(this);
}
+ void do_allow_event_processing_after_transition( ::boost::mpl::true_ const &)
+ {
+ // no message queue needed
+ }
+ void do_allow_event_processing_after_transition( ::boost::mpl::false_ const &)
+ {
+ m_event_processing = false;
+ }
// the following 2 functions handle the processing either with a try/catch protection or without
template <class StateType,class EventType>
HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::true_ const &, bool is_direct_call)
template <class StateType,class EventType>
HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::false_ const &, bool is_direct_call)
{
- // when compiling without exception support there is no formal parameter "e" in the catch handler.
- // Declaring a local variable here does not hurt and will be "used" to make the code in the handler
+ // when compiling without exception support there is no formal parameter "e" in the catch handler.
+ // Declaring a local variable here does not hurt and will be "used" to make the code in the handler
// compilable although the code will never be executed.
std::exception e;
BOOST_TRY
}
// handling of deferred events
// if none is found in the SM, take the following empty main version
- template <class StateType, class Enable = int>
+ template <class StateType, class Enable = int>
struct handle_defer_helper
{
handle_defer_helper(deferred_msg_queue_helper<library_sm>& ){}
- void do_pre_handle_deferred()
- {
- }
-
- void do_post_handle_deferred(HandledEnum)
+ void do_handle_deferred(bool)
{
}
};
<StateType, typename enable_if< typename ::boost::msm::back::has_fsm_deferred_events<StateType>::type,int >::type>
{
handle_defer_helper(deferred_msg_queue_helper<library_sm>& a_queue):
- events_queue(a_queue),next_deferred_event(){}
- void do_pre_handle_deferred()
- {
- }
-
- void do_post_handle_deferred(HandledEnum handled)
- {
- if (handled == HANDLED_TRUE)
+ m_events_queue(a_queue) {}
+ void do_handle_deferred(bool new_seq=false)
+ {
+ // A new sequence is typically started upon initial entry to the
+ // state, or upon a new transition. When this occurs we want to
+ // process all previously deferred events by incrementing the
+ // correlation sequence.
+ if (new_seq)
{
- // a transition has been taken, it makes sense again to try processing waiting deferred events
- // reset all events to not tested
- for (std::size_t i = 0; i < events_queue.m_deferred_events_queue.size(); ++i)
- {
- events_queue.m_deferred_events_queue[i].second=false;
- }
- // test first event
- if (!events_queue.m_deferred_events_queue.empty())
- {
- deferred_fct next = events_queue.m_deferred_events_queue.front().first;
- events_queue.m_deferred_events_queue.pop_front();
- next();
- }
+ ++m_events_queue.m_cur_seq;
}
- else
+
+ char& cur_seq = m_events_queue.m_cur_seq;
+
+ // Iteratively process all of the events within the deferred
+ // queue upto (but not including) newly deferred events.
+ while (!m_events_queue.m_deferred_events_queue.empty())
{
- // look for next deferred event, if any
- typename deferred_events_queue_t::iterator it =
- std::find_if(events_queue.m_deferred_events_queue.begin(),
- events_queue.m_deferred_events_queue.end(),
- boost::bind(&std::pair<deferred_fct,bool>::second, _1) == false);
- if (it != events_queue.m_deferred_events_queue.end())
+ typename deferred_events_queue_t::value_type& pair =
+ m_events_queue.m_deferred_events_queue.front();
+
+ if (cur_seq != pair.second)
{
- (*it).second = true;
- deferred_fct next = (*it).first;
- events_queue.m_deferred_events_queue.erase(it);
- next();
+ break;
}
+
+ deferred_fct next = pair.first;
+ m_events_queue.m_deferred_events_queue.pop_front();
+ next();
}
}
private:
- deferred_msg_queue_helper<library_sm>& events_queue;
- deferred_fct next_deferred_event;
+ deferred_msg_queue_helper<library_sm>& m_events_queue;
};
// handling of eventless transitions
// if none is found in the SM, nothing to do
- template <class StateType, class Enable = void>
+ template <class StateType, class Enable = void>
struct handle_eventless_transitions_helper
{
handle_eventless_transitions_helper(library_sm* , bool ){}
- void process_completion_event(){}
+ void process_completion_event(EventSource = EVENT_SOURCE_DEFAULT){}
};
- // otherwise
+ // otherwise
template <class StateType>
struct handle_eventless_transitions_helper
<StateType, typename enable_if< typename ::boost::msm::back::has_fsm_eventless_transition<StateType>::type >::type>
{
handle_eventless_transitions_helper(library_sm* self_, bool handled_):self(self_),handled(handled_){}
- void process_completion_event()
+ void process_completion_event(EventSource source = EVENT_SOURCE_DEFAULT)
{
typedef typename ::boost::mpl::deref<
typename ::boost::mpl::begin<
>::type first_completion_event;
if (handled)
{
- self->process_event(first_completion_event() );
+ self->process_event_internal(
+ first_completion_event(),
+ source | EVENT_SOURCE_DIRECT);
}
}
-
+
private:
library_sm* self;
bool handled;
};
template <class StateType,class Enable=void>
- struct region_processing_helper
+ struct region_processing_helper
{
public:
region_processing_helper(library_sm* self_,HandledEnum& result_)
};
// version with visitors
template <class StateType>
- struct region_processing_helper<StateType,typename ::boost::enable_if<
- ::boost::mpl::is_sequence<typename StateType::initial_state> >::type>
+ struct region_processing_helper<StateType,typename ::boost::enable_if<
+ ::boost::mpl::is_sequence<typename StateType::initial_state> >::type>
{
private:
// process event in one region
// Main function used internally to make transitions
// Can only be called for internally (for example in an action method) generated events.
template<class Event>
- execute_return process_event_internal(Event const& evt, bool is_direct_call)
+ execute_return process_event_internal(Event const& evt,
+ EventSource source = EVENT_SOURCE_DEFAULT)
{
- HandledEnum ret_handled=HANDLED_FALSE;
// if the state machine has terminate or interrupt flags, check them, otherwise skip
if (is_event_handling_blocked_helper<Event>
( ::boost::mpl::bool_<has_fsm_blocking_states<library_sm>::type::value>() ) )
+ {
return HANDLED_TRUE;
+ }
+
// if a message queue is needed and processing is on the way
if (!do_pre_msg_queue_helper<Event>
- (evt,::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>()) )
+ (evt,::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>()))
{
// wait for the end of current processing
return HANDLED_TRUE;
}
else
{
- // prepare the next deferred event for handling
- // if one defer is found in the SM, otherwise skip
- handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
- defer_helper.do_pre_handle_deferred();
- // process event
- HandledEnum handled = this->do_process_helper<Event>
- (evt,::boost::mpl::bool_<is_no_exception_thrown<library_sm>::type::value>(),is_direct_call);
- if (handled)
- {
- ret_handled = handled;
- }
+ // Process event
+ HandledEnum handled = this->do_process_helper<Event>(
+ evt,
+ ::boost::mpl::bool_<is_no_exception_thrown<library_sm>::type::value>(),
+ (EVENT_SOURCE_DIRECT & source));
- // process completion transitions BEFORE any other event in the pool (UML Standard 2.3 15.3.14)
- handle_eventless_transitions_helper<library_sm> eventless_helper(this,(handled == HANDLED_TRUE));
- eventless_helper.process_completion_event();
+ // at this point we allow the next transition be executed without enqueing
+ // so that completion events and deferred events execute now (if any)
+ do_allow_event_processing_after_transition(
+ ::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>());
- // after handling, take care of the deferred events
- defer_helper.do_post_handle_deferred(handled);
+ // Process completion transitions BEFORE any other event in the
+ // pool (UML Standard 2.3 15.3.14)
+ handle_eventless_transitions_helper<library_sm>
+ eventless_helper(this,(HANDLED_TRUE & handled));
+ eventless_helper.process_completion_event(source);
- // now check if some events were generated in a transition and was not handled
- // because of another processing, and if yes, start handling them
- do_post_msg_queue_helper(::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>());
-
- return ret_handled;
- }
+ // After handling, take care of the deferred events, but only if
+ // we're not already processing from the deferred queue.
+ do_handle_prio_msg_queue_deferred_queue(
+ source,handled,
+ ::boost::mpl::bool_<has_event_queue_before_deferred_queue<library_sm>::type::value>());
+ return handled;
+ }
}
// minimum event processing without exceptions, queues, etc.
HandledEnum do_process_event(Event const& evt, bool is_direct_call)
{
HandledEnum handled = HANDLED_FALSE;
+
// dispatch the event to every region
region_processing_helper<Derived> helper(this,handled);
helper.process(evt);
// if the event has not been handled and we have orthogonal zones, then
- // generate an error on every active state
+ // generate an error on every active state
// for state machine states contained in other state machines, do not handle
- // but let the containing sm handle the error, unless the event was generated in this fsm
+ // but let the containing sm handle the error, unless the event was generated in this fsm
// (by calling process_event on this fsm object, is_direct_call == true)
// completion events do not produce an error
if ( (!is_contained() || is_direct_call) && !handled && !is_completion_event<Event>::type::value)
};
// helper for flag handling. Uses OR by default on orthogonal zones.
template <class Flag,bool orthogonalStates>
- struct FlagHelper
+ struct FlagHelper
{
static bool helper(library_sm const& sm,flag_handler* )
{
typename ::boost::enable_if<typename is_pseudo_exit<StateType>::type,void >::type
new_state_helper( ::boost::msm::back::dummy<2> = 0) const
{
- execute_return (ContainingSM::*pf) (typename StateType::event const& evt)=
+ execute_return (ContainingSM::*pf) (typename StateType::event const& evt)=
&ContainingSM::process_event;
- ::boost::function<execute_return (typename StateType::event const&)> fct =
+ ::boost::function<execute_return (typename StateType::event const&)> fct =
::boost::bind(pf,containing_sm,_1);
::boost::fusion::at_key<StateType>(self->m_substate_list).set_forward_fct(fct);
}
// helper used to call the correct entry/exit method
// unfortunately in O(number of states in the sub-sm) but should be better than a virtual call
- template<class Event,bool is_entry>
+ template<class Event,bool is_entry>
struct entry_exit_helper
{
entry_exit_helper(int id,Event const& e,library_sm* self_):
}
template <class StateType>
- struct find_region_id
+ struct find_region_id
{
template <int region,int Dummy=0>
struct In
{
typedef typename build_orthogonal_regions<
library_sm,
- initial_states
+ initial_states
>::type all_regions;
enum {region_index= find_region_index<all_regions,StateType>::value };
- };
+ };
enum {region_index = In<StateType::zone_index>::region_index };
};
// helper used to set the correct state as active state upon entry into a fsm
- struct direct_event_start_helper
+ struct direct_event_start_helper
{
direct_event_start_helper(library_sm* self_):self(self_){}
// this variant is for the standard case, entry due to activation of the containing FSM
typename EventType::active_state>::type >::type,
typename ::boost::mpl::and_<typename has_direct_entry<EventType>::type,
typename ::boost::mpl::not_<typename ::boost::mpl::is_sequence
- <typename EventType::active_state>::type >::type
+ <typename EventType::active_state>::type >::type
>::type>::type,void
>::type
operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<1> = 0)
typename is_pseudo_entry<typename EventType::active_state>::type >::type,
typename ::boost::mpl::and_<typename has_direct_entry<EventType>::type,
typename ::boost::mpl::is_sequence<
- typename EventType::active_state>::type
- >::type>::type,void
+ typename EventType::active_state>::type
+ >::type>::type,void
>::type
operator()(EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<2> = 0)
{
(static_cast<Derived*>(self))->on_entry(evt,fsm);
- ::boost::mpl::for_each<typename EventType::active_state,
+ ::boost::mpl::for_each<typename EventType::active_state,
::boost::msm::wrap< ::boost::mpl::placeholders::_1> >
(fork_helper<EventType>(self,evt));
// set the correct zones, the others (if any) will be default/history initialized
template<class Event>
static void do_entry(library_sm* self_,Event const& incomingEvent)
{
- self_->m_states[region_id::value] =
+ self_->m_states[region_id::value] =
self_->m_history.history_entry(incomingEvent)[region_id::value];
region_entry_exit_helper
< ::boost::mpl::int_<region_id::value+1> >::do_entry(self_,incomingEvent);
m_event_processing = false;
// look for deferred events waiting
handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
- defer_helper.do_post_handle_deferred(HANDLED_TRUE);
+ defer_helper.do_handle_deferred(true);
process_message_queue(this);
}
template <class Event,class FsmType>
#if defined (__IBMCPP__) || (defined(_MSC_VER) && (_MSC_VER < 1400))
private:
#endif
- // puts a deferred event in the queue
- void post_deferred_event(deferred_fct& deferred)
- {
- m_deferred_events_queue.m_deferred_events_queue.push_back(std::make_pair(deferred,true));
- }
// removes one event from the message queue and processes it
template <class StateType>
- void process_message_queue(StateType*,
+ void process_message_queue(StateType*,
typename ::boost::disable_if<typename is_no_message_queue<StateType>::type,void >::type* = 0)
{
- if (!m_events_queue.m_events_queue.empty())
+ // Iteratively process all events from the message queue.
+ while (!m_events_queue.m_events_queue.empty())
{
- transition_fct to_call = m_events_queue.m_events_queue.front();
+ transition_fct next = m_events_queue.m_events_queue.front();
m_events_queue.m_events_queue.pop_front();
- to_call();
+ next();
}
}
template <class StateType>
- void process_message_queue(StateType*,
+ void process_message_queue(StateType*,
typename ::boost::enable_if<typename is_no_message_queue<StateType>::type,void >::type* = 0)
{
// nothing to process
// helper function. In cases where the event is wrapped (target is a direct entry states)
// we want to send only the real event to on_entry, not the wrapper.
template <class EventType>
- static
+ static
typename boost::enable_if<typename has_direct_entry<EventType>::type,typename EventType::contained_event const& >::type
remove_direct_entry_event_wrapper(EventType const& evt,boost::msm::back::dummy<0> = 0)
{
typename ::boost::enable_if<typename is_pseudo_exit<StateType>::type,void >::type
execute_entry(StateType& astate,EventType const& evt,FsmType& fsm, ::boost::msm::back::dummy<2> = 0)
{
- // calls on_entry on the state then forward the event to the transition which should be defined inside the
+ // calls on_entry on the state then forward the event to the transition which should be defined inside the
// contained fsm
astate.on_entry(evt,fsm);
astate.forward_event(evt);
private:
template <class StateType,class Enable=void>
- struct msg_queue_helper
+ struct msg_queue_helper
{
public:
msg_queue_helper():m_events_queue(){}
};
template <class StateType>
struct msg_queue_helper<StateType,
- typename ::boost::enable_if<typename is_no_message_queue<StateType>::type >::type>
+ typename ::boost::enable_if<typename is_no_message_queue<StateType>::type >::type>
{
};
} } }// boost::msm::back
#endif //BOOST_MSM_BACK_STATEMACHINE_H
-