refactor(backmp11): history handling

This commit is contained in:
Christian Granzin
2026-04-20 15:48:50 -04:00
committed by Christian Granzin
parent d09d4584e4
commit 5bd6700f9b
8 changed files with 314 additions and 261 deletions
@@ -12,126 +12,133 @@
#ifndef BOOST_MSM_BACKMP11_DETAIL_HISTORY_IMPL_HPP
#define BOOST_MSM_BACKMP11_DETAIL_HISTORY_IMPL_HPP
#include <boost/msm/backmp11/detail/metafunctions.hpp>
#include <boost/msm/front/history_policies.hpp>
#include <boost/mp11.hpp>
namespace boost::msm::backmp11::detail
{
template<typename History, int NumberOfRegions>
template <typename History, typename InitialStateIds>
class history_impl;
template <int NumberOfRegions>
class history_impl<front::no_history, NumberOfRegions>
template <typename InitialStateIds>
class history_impl<front::no_history, InitialStateIds>
{
public:
void reset_active_state_ids(const std::array<int, NumberOfRegions>& initial_state_ids)
template <typename StateMachine, typename Event>
void on_entry(StateMachine& sm, const Event&)
{
m_initial_state_ids = initial_state_ids;
}
template <class Event>
const std::array<int, NumberOfRegions>& on_entry(Event const&)
{
return m_initial_state_ids;
}
void on_exit(const std::array<int, NumberOfRegions>&)
{
// ignore
}
// this policy deletes all waiting deferred events
template <class Event>
bool clear_event_pool(Event const&) const
{
return true;
}
private:
// Allow access to private members for serialization.
template<typename T, int N>
friend void serialize(T&, history_impl<front::no_history, N>&);
std::array<int, NumberOfRegions> m_initial_state_ids;
};
template <int NumberOfRegions>
class history_impl<front::always_shallow_history, NumberOfRegions>
{
public:
void reset_active_state_ids(const std::array<int, NumberOfRegions>& initial_state_ids)
{
m_last_active_state_ids = initial_state_ids;
}
template <class Event>
const std::array<int, NumberOfRegions>& on_entry(Event const& )
{
return m_last_active_state_ids;
}
void on_exit(const std::array<int, NumberOfRegions>& active_state_ids)
{
m_last_active_state_ids = active_state_ids;
}
// the history policy keeps all deferred events until next reentry
template <class Event>
bool clear_event_pool(Event const&)const
{
return false;
}
private:
// Allow access to private members for serialization.
template<typename T, int N>
friend void serialize(T&, history_impl<front::always_shallow_history, N>&);
std::array<int, NumberOfRegions> m_last_active_state_ids;
};
template <typename... Events, int NumberOfRegions>
class history_impl<front::shallow_history<Events...>, NumberOfRegions>
{
using events_mp11 = mp11::mp_list<Events...>;
public:
void reset_active_state_ids(const std::array<int, NumberOfRegions>& initial_state_ids)
{
m_initial_state_ids = initial_state_ids;
m_last_active_state_ids = initial_state_ids;
}
template <class Event>
const std::array<int, NumberOfRegions>& on_entry(Event const&)
{
if constexpr (mp11::mp_contains<events_mp11,Event>::value)
sm.m_active_state_ids = value_array<InitialStateIds>;
if constexpr (StateMachine::event_pool_member::value)
{
return m_last_active_state_ids;
sm.get_event_pool().events.clear();
}
return m_initial_state_ids;
}
void on_exit(const std::array<int, NumberOfRegions>& active_state_ids)
template <typename StateMachine, typename Event, typename Visitor>
void on_entry(StateMachine& sm, const Event& event, Visitor&& visitor)
{
m_last_active_state_ids = active_state_ids;
// First set all active state ids...
on_entry(sm, event);
// ... then execute each state entry.
mp11::mp_for_each<InitialStateIds>(
[&sm, &visitor](auto state_id)
{
auto& state = std::get<decltype(state_id)::value>(sm.m_states);
visitor(state);
});
}
// the history policy keeps deferred events until next reentry if coming from our history event
template <class Event>
bool clear_event_pool(Event const&) const
template <typename StateMachine>
void on_exit(StateMachine&)
{
return !mp11::mp_contains<events_mp11,Event>::value;
}
private:
// Allow access to private members for serialization.
template<typename T, typename... Es, int N>
friend void serialize(T&, history_impl<front::shallow_history<Es...>, N>&);
template<typename T, typename U>
friend void serialize(T&, history_impl<front::no_history, U>&);
};
std::array<int, NumberOfRegions> m_initial_state_ids;
std::array<int, NumberOfRegions> m_last_active_state_ids;
template <typename InitialStateIds>
class history_impl<front::always_shallow_history, InitialStateIds>
{
public:
template <typename StateMachine, typename Event>
void on_entry(StateMachine& sm, const Event&)
{
sm.m_active_state_ids = m_last_active_state_ids;
}
template <typename StateMachine, typename Event, typename Visitor>
void on_entry(StateMachine& sm, const Event& event, Visitor&& visitor)
{
// First set all active state ids...
on_entry(sm, event);
// ... then execute each state entry.
sm.template visit<visit_mode::active_non_recursive>(visitor);
}
template <typename StateMachine>
void on_exit(StateMachine& sm)
{
m_last_active_state_ids = sm.m_active_state_ids;
}
private:
// Allow access to private members for serialization.
template<typename T, typename U>
friend void serialize(T&, history_impl<front::always_shallow_history, U>&);
std::array<int, mp11::mp_size<InitialStateIds>::value>
m_last_active_state_ids{value_array<InitialStateIds>};
};
template <typename... Events, typename InitialStateIds>
class history_impl<front::shallow_history<Events...>, InitialStateIds>
{
using events = mp11::mp_list<Events...>;
public:
template <typename StateMachine, typename Event>
void on_entry(StateMachine& sm, const Event&)
{
if constexpr (mp11::mp_contains<events, Event>::value)
{
sm.m_active_state_ids = m_last_active_state_ids;
}
else
{
sm.m_active_state_ids = value_array<InitialStateIds>;
if constexpr (StateMachine::event_pool_member::value)
{
sm.get_event_pool().events.clear();
}
}
}
template <typename StateMachine, typename Event, typename Visitor>
void on_entry(StateMachine& sm, const Event& event, Visitor&& visitor)
{
// First set all active state ids...
on_entry(sm, event);
// ... then execute each state entry.
sm.template visit<visit_mode::active_non_recursive>(visitor);
}
template <typename StateMachine>
void on_exit(StateMachine& sm)
{
m_last_active_state_ids = sm.m_active_state_ids;
}
private:
// Allow access to private members for serialization.
template<typename T, typename... Es, typename U>
friend void serialize(T&, history_impl<front::shallow_history<Es...>, U>&);
std::array<int, mp11::mp_size<InitialStateIds>::value>
m_last_active_state_ids{value_array<InitialStateIds>};
};
} // boost::msm::backmp11
@@ -100,7 +100,7 @@ struct value_array_impl<mp11::mp_list<Ts...>>
{
using value_type =
typename mp11::mp_front<mp11::mp_list<Ts...>>::value_type;
static constexpr value_type value[sizeof...(Ts)] {Ts::value...};
static constexpr std::array<value_type, sizeof...(Ts)> value{Ts::value...};
};
template <typename List>
static constexpr const auto& value_array = value_array_impl<List>::value;
@@ -269,7 +269,8 @@ using generate_state_set = typename generate_state_set_impl<StateMachine>::type;
template <class StateSet>
struct generate_state_map_impl
{
using indices = mp11::mp_iota<mp11::mp_size<StateSet>>;
using indices = mp11::mp_iota<
std::integral_constant<int, mp11::mp_size<StateSet>::value>>;
using type = mp11::mp_transform_q<
mp11::mp_bind<mp11::mp_list, mp11::_1, mp11::_2>,
StateSet,
@@ -180,6 +180,11 @@ class state_machine_base : public FrontEnd
static constexpr int nr_regions = mp11::mp_size<initial_states>::value;
using state_set = generate_state_set<state_machine_base>;
using state_map = generate_state_map<state_set>;
template <typename State>
using get_state_id =
detail::get_state_id<state_map, State>;
using submachines = mp11::mp_copy_if<state_set, is_composite>;
};
@@ -217,9 +222,12 @@ class state_machine_base : public FrontEnd
private:
using state_set = typename internal::state_set;
using state_map = typename internal::state_map;
static constexpr int nr_regions = internal::nr_regions;
using active_state_ids_t = std::array<int, nr_regions>;
using initial_state_identities = mp11::mp_transform<mp11::mp_identity, typename internal::initial_states>;
using initial_state_ids =
mp11::mp_transform<internal::template get_state_id,
typename internal::initial_states>;
using compile_policy = typename config_t::compile_policy;
using compile_policy_impl = detail::compile_policy_impl<compile_policy>;
@@ -232,6 +240,9 @@ class state_machine_base : public FrontEnd
template <class, class, class>
friend class state_machine_base;
template <typename, typename>
friend class history_impl;
template <typename StateMachine>
friend struct transition_table_impl;
@@ -268,8 +279,8 @@ class state_machine_base : public FrontEnd
using fsm_final_event =
mp11::mp_eval_or<stopping, get_final_event, front_end_t>;
using state_map = generate_state_map<state_set>;
using history_impl = detail::history_impl<typename front_end_t::history, nr_regions>;
using history_impl = detail::history_impl<typename front_end_t::history,
initial_state_ids>;
using context_member =
optional_instance<context_t*,
@@ -319,7 +330,7 @@ class state_machine_base : public FrontEnd
visit_if<visit_mode::all_recursive,
visitor_t::template predicate>(visitor);
}
reset_active_state_ids();
m_active_state_ids = value_array<initial_state_ids>;
}
// Construct with a context and
@@ -660,19 +671,6 @@ class state_machine_base : public FrontEnd
return compile_policy_impl::is_end_interrupt_event(*this, event);
}
// Helpers used to reset the state machine.
void reset_active_state_ids()
{
size_t index = 0;
mp11::mp_for_each<initial_state_identities>(
[this, &index](auto state_identity)
{
using State = typename decltype(state_identity)::type;
m_active_state_ids[index++] = get_state_id<State>();
});
m_history.reset_active_state_ids(m_active_state_ids);
}
// Main function used internally to process events.
// Explicitly not inline, because code size can significantly increase if
// this method is inlined in all existing process_info variants.
@@ -1008,25 +1006,8 @@ class state_machine_base : public FrontEnd
{
preprocess_entry(event, fsm);
// First set all active state ids...
m_active_state_ids = m_history.on_entry(event);
// ... then execute each state entry.
state_entry_visitor<Event> visitor{self(), event};
if constexpr (std::is_same_v<typename front_end_t::history,
front::no_history>)
{
mp11::mp_for_each<initial_state_identities>(
[this, &visitor](auto state_identity)
{
using State = typename decltype(state_identity)::type;
auto& state = this->get_state<State>();
visitor(state);
});
}
else
{
visit<visit_mode::active_non_recursive>(visitor);
}
m_history.on_entry(self(), event, visitor);
postprocess_entry();
}
@@ -1044,7 +1025,7 @@ class state_machine_base : public FrontEnd
// First set all active state ids...
if constexpr (!all_regions_defined)
{
m_active_state_ids = m_history.on_entry(event);
m_history.on_entry(self(), event);
}
mp11::mp_for_each<state_identities>(
[this](auto state_identity)
@@ -1116,15 +1097,7 @@ class state_machine_base : public FrontEnd
// Then call our own exit.
(static_cast<front_end_t*>(this))->on_exit(event, fsm);
// Give the history a chance to handle this (or not).
m_history.on_exit(this->m_active_state_ids);
// History decides what happens with the event pool.
if (m_history.clear_event_pool(event))
{
if constexpr (event_pool_member::value)
{
get_event_pool().events.clear();
}
}
m_history.on_exit(self());
}
derived_t& self()
+8 -10
View File
@@ -182,16 +182,14 @@ void serialize(Archive& ar,
mp11::tuple_for_each(sm.m_states, serialize_state<Archive>(ar));
}
template<typename T, int N>
void serialize(T& ar, detail::history_impl<front::no_history, N>& history)
template<typename T, typename InitialStateIds>
void serialize(T&, detail::history_impl<front::no_history, InitialStateIds>&)
{
ar & history.m_initial_state_ids;
}
template<typename T, typename... Es, int N>
void serialize(T& ar, detail::history_impl<front::shallow_history<Es...>, N>& history)
template<typename T, typename... Es, typename InitialStateIds>
void serialize(T& ar, detail::history_impl<front::shallow_history<Es...>, InitialStateIds>& history)
{
ar & history.m_initial_state_ids;
ar & history.m_last_active_state_ids;
}
@@ -210,17 +208,17 @@ void serialize(Archive& ar,
msm::backmp11::detail::serialize(ar, sm);
}
template<typename T, int N>
template<typename T, typename InitialStateIds>
void serialize(T& ar,
msm::backmp11::detail::history_impl<msm::front::no_history, N>& history,
msm::backmp11::detail::history_impl<msm::front::no_history, InitialStateIds>& history,
const unsigned int /*version*/)
{
msm::backmp11::detail::serialize(ar, history);
}
template<typename T, typename... Es, int N>
template<typename T, typename... Es, typename InitialStateIds>
void serialize(T& ar,
msm::backmp11::detail::history_impl<msm::front::shallow_history<Es...>, N>& history,
msm::backmp11::detail::history_impl<msm::front::shallow_history<Es...>, InitialStateIds>& history,
const unsigned int /*version*/)
{
msm::backmp11::detail::serialize(ar, history);
+160
View File
@@ -0,0 +1,160 @@
// Copyright 2025 Christian Granzin
// Copyright 2010 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_NONSTANDALONE_TEST
#define BOOST_TEST_MODULE backmp11_history_test
#endif
#include <boost/test/unit_test.hpp>
// back-end
#include "Backmp11.hpp"
//front-end
#include "FrontCommon.hpp"
#include "Utils.hpp"
namespace msm = boost::msm;
namespace mp11 = boost::mp11;
using namespace msm::front;
using namespace msm::backmp11;
namespace
{
// Events.
struct EnterSubmachine {};
struct EnterSubmachineWithoutHistory {};
struct ExitSubmachine {};
struct EnterSubstate1 {};
struct DeferredEvent {};
// States.
struct State0 : public test::StateBase {};
struct Substate0 : public test::StateBase
{
using deferred_events = mp11::mp_list<DeferredEvent>;
};
struct Substate1 : public test::StateBase
{
using deferred_events = mp11::mp_list<DeferredEvent>;
};
struct default_config : state_machine_config
{
};
struct favor_compile_time_config : default_config
{
using compile_policy = favor_compile_time;
};
template <typename History, typename Config = default_config>
struct hierarchical_state_machine
{
struct Submachine_ : test::StateMachineBase_<Submachine_>
{
using history = History;
using initial_state = Substate0;
using transition_table = mp11::mp_list<
Row<Substate0, EnterSubstate1, Substate1>,
Row<Substate0, DeferredEvent , none >
>;
};
using Submachine = StateMachine<Submachine_, Config>;
struct UpperMachine_ : test::StateMachineBase_<UpperMachine_>
{
using initial_state = State0;
using transition_table = mp11::mp_list<
Row<State0 , EnterSubmachine , Submachine>,
Row<State0 , EnterSubmachineWithoutHistory, Submachine>,
Row<Submachine, ExitSubmachine , State0 >
>;
};
using UpperMachine = StateMachine<UpperMachine_, Config>;
};
using TestMachinesAlwaysShallowHistory = boost::mpl::vector<
hierarchical_state_machine<always_shallow_history>,
hierarchical_state_machine<always_shallow_history, favor_compile_time_config>
>;
BOOST_AUTO_TEST_CASE_TEMPLATE(always_shallow_history, TestMachine, TestMachinesAlwaysShallowHistory)
{
using StateMachine = typename TestMachine::UpperMachine;
using Submachine = typename TestMachine::Submachine;
StateMachine state_machine;
auto& submachine = state_machine.template get_state<Submachine>();
state_machine.start();
BOOST_REQUIRE(state_machine.template is_state_active<State0>());
state_machine.process_event(EnterSubmachine{});
BOOST_REQUIRE(state_machine.template is_state_active<Substate0>());
// Push to submachine's event pool explicitly to test clearance.
submachine.process_event(DeferredEvent{});
BOOST_REQUIRE(submachine.get_pending_events().size() == 1);
state_machine.process_event(EnterSubstate1{});
BOOST_REQUIRE(state_machine.template is_state_active<Substate1>());
// Re-entry with history
state_machine.process_event(ExitSubmachine{});
BOOST_REQUIRE(state_machine.template is_state_active<State0>());
state_machine.process_event(EnterSubmachine{});
BOOST_REQUIRE(state_machine.template is_state_active<Substate1>());
BOOST_REQUIRE(submachine.get_pending_events().size() == 1);
}
using history = shallow_history<EnterSubmachine>;
using TestMachinesShallowHistory = boost::mpl::vector<
hierarchical_state_machine<history>,
hierarchical_state_machine<history, favor_compile_time_config>
>;
BOOST_AUTO_TEST_CASE_TEMPLATE(shallow_history, TestMachine, TestMachinesShallowHistory)
{
using StateMachine = typename TestMachine::UpperMachine;
using Submachine = typename TestMachine::Submachine;
StateMachine state_machine;
auto& submachine = state_machine.template get_state<Submachine>();
state_machine.start();
BOOST_REQUIRE(state_machine.template is_state_active<State0>());
state_machine.process_event(EnterSubmachine{});
BOOST_REQUIRE(state_machine.template is_state_active<Substate0>());
// Push to submachine's event pool explicitly to test clearance.
submachine.process_event(DeferredEvent{});
BOOST_REQUIRE(submachine.get_pending_events().size() == 1);
state_machine.process_event(EnterSubstate1{});
BOOST_REQUIRE(state_machine.template is_state_active<Substate1>());
// Re-entry with history
state_machine.process_event(ExitSubmachine{});
BOOST_REQUIRE(state_machine.template is_state_active<State0>());
state_machine.process_event(EnterSubmachine{});
BOOST_REQUIRE(state_machine.template is_state_active<Substate1>());
BOOST_REQUIRE(submachine.get_pending_events().size() == 1);
// Re-entry without history
state_machine.process_event(ExitSubmachine{});
BOOST_REQUIRE(state_machine.template is_state_active<State0>());
state_machine.process_event(EnterSubmachineWithoutHistory{});
BOOST_REQUIRE(state_machine.template is_state_active<Substate0>());
BOOST_REQUIRE(submachine.get_pending_events().size() == 0);
}
} // namespace
+1
View File
@@ -84,6 +84,7 @@ add_executable(boost_msm_cxx17_tests
Backmp11Deferred.cpp
Backmp11EntryExit.cpp
Backmp11FunctorApi.cpp
Backmp11History.cpp
Backmp11ManyDeferTransitions.cpp
Backmp11RootSm.cpp
Backmp11Transitions.cpp
+2 -1
View File
@@ -82,8 +82,9 @@ test-suite msm-unit-tests-cxxstd17
[ run Backmp11Context.cpp ]
[ run Backmp11CopyMove.cpp ]
[ run Backmp11Deferred.cpp ]
[ run Backmp11FunctorApi.cpp ]
[ run Backmp11EntryExit.cpp ]
[ run Backmp11FunctorApi.cpp ]
[ run Backmp11History.cpp ]
[ run Backmp11ManyDeferTransitions.cpp ]
[ run Backmp11RootSm.cpp ]
[ run Backmp11Transitions.cpp ]
+18 -106
View File
@@ -8,14 +8,16 @@
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// back-end
#include "BackCommon.hpp"
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#ifndef BOOST_MSM_NONSTANDALONE_TEST
#define BOOST_TEST_MODULE serialize_with_history_test
#endif
#include <boost/test/unit_test.hpp>
// back-end
#include "BackCommon.hpp"
//front-end
#include "FrontCommon.hpp"
// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
@@ -44,11 +46,11 @@ namespace
std::string name;
};
template<template <typename...> class Back, typename Policy = void>
template <template <typename...> class Back, typename Policy = void>
struct hierarchical_state_machine
{
// front-end: define the FSM structure
struct player_ : public msm::front::state_machine_def<player_>
struct player_ : public msm::front::test::StateMachineBase_<player_>
{
BOOST_MSM_TEST_DEFINE_DEPENDENT_TEMPLATES(player_)
@@ -60,84 +62,37 @@ namespace
can_close_drawer_counter(0)
{}
// The list of FSM states
struct Empty : public msm::front::state<>
struct Empty : msm::front::test::StateBase
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {++entry_counter;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {++exit_counter;}
int entry_counter;
int exit_counter;
};
struct Open : public msm::front::state<>
struct Open : msm::front::test::StateBase
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {++entry_counter;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {++exit_counter;}
int entry_counter;
int exit_counter;
};
// sm_ptr still supported but deprecated as functors are a much better way to do the same thing
struct Stopped : public msm::front::state<>
struct Stopped : msm::front::test::StateBase
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {++entry_counter;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {++exit_counter;}
int entry_counter;
int exit_counter;
};
struct Playing_ : public msm::front::state_machine_def<Playing_>
struct Playing_ : public msm::front::test::StateMachineBase_<Playing_>
{
BOOST_MSM_TEST_DEFINE_DEPENDENT_TEMPLATES(Playing_)
// History for backmp11
using history = msm::front::shallow_history<end_pause>;
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {++entry_counter;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {++exit_counter;}
int entry_counter;
int exit_counter;
unsigned int start_next_song_counter;
unsigned int start_prev_song_guard_counter;
Playing_():
start_next_song_counter(0),
start_prev_song_guard_counter(0)
{}
unsigned int start_next_song_counter{};
unsigned int start_prev_song_guard_counter{};
// The list of FSM states
struct Song1 : public msm::front::state<>
struct Song1 : msm::front::test::StateBase
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {++entry_counter;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {++exit_counter;}
int entry_counter;
int exit_counter;
};
struct Song2 : public msm::front::state<>
struct Song2 : msm::front::test::StateBase
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {++entry_counter;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {++exit_counter;}
int entry_counter;
int exit_counter;
};
struct Song3 : public msm::front::state<>
struct Song3 : msm::front::test::StateBase
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {++entry_counter;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {++exit_counter;}
int entry_counter;
int exit_counter;
};
// the initial state. Must be defined
typedef Song1 initial_state;
@@ -158,25 +113,13 @@ namespace
g_row < Song3 , PreviousSong, Song2 ,&pl::start_prev_song_guard>
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const&, FSM&,int)
{
BOOST_FAIL("no_transition called!");
}
};
// back-end
typedef Back<Playing_,Policy,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
// state not defining any entry or exit
struct Paused : public msm::front::state<>
struct Paused : msm::front::test::StateBase
{
template <class Event,class FSM>
void on_entry(Event const&,FSM& ) {++entry_counter;}
template <class Event,class FSM>
void on_exit(Event const&,FSM& ) {++exit_counter;}
int entry_counter;
int exit_counter;
};
// the initial state of the player SM. Must be defined
@@ -223,43 +166,12 @@ namespace
a_row < Paused , open_close , Open , &p::stop_and_open >
// +---------+-------------+---------+---------------------+----------------------+
> {};
// Replaces the default no-transition response.
template <class FSM,class Event>
void no_transition(Event const&, FSM&,int)
{
BOOST_FAIL("no_transition called!");
}
// init counters
template <class Event,class FSM>
void on_entry(Event const&,FSM& fsm)
{
fsm.template get_state<typename player_::Stopped&>().entry_counter=0;
fsm.template get_state<typename player_::Stopped&>().exit_counter=0;
fsm.template get_state<typename player_::Open&>().entry_counter=0;
fsm.template get_state<typename player_::Open&>().exit_counter=0;
fsm.template get_state<typename player_::Empty&>().entry_counter=0;
fsm.template get_state<typename player_::Empty&>().exit_counter=0;
fsm.template get_state<typename player_::Playing&>().entry_counter=0;
fsm.template get_state<typename player_::Playing&>().exit_counter=0;
fsm.template get_state<typename player_::Playing&>().template get_state<typename player_::Playing::Song1&>().entry_counter=0;
fsm.template get_state<typename player_::Playing&>().template get_state<typename player_::Playing::Song1&>().exit_counter=0;
fsm.template get_state<typename player_::Playing&>().template get_state<typename player_::Playing::Song2&>().entry_counter=0;
fsm.template get_state<typename player_::Playing&>().template get_state<typename player_::Playing::Song2&>().exit_counter=0;
fsm.template get_state<typename player_::Playing&>().template get_state<typename player_::Playing::Song3&>().entry_counter=0;
fsm.template get_state<typename player_::Playing&>().template get_state<typename player_::Playing::Song3&>().exit_counter=0;
fsm.template get_state<typename player_::Paused&>().entry_counter=0;
fsm.template get_state<typename player_::Paused&>().exit_counter=0;
}
};
typedef Back<player_, Policy> player;
};
// Pick a back-end
typedef get_hierarchical_test_machines<hierarchical_state_machine> test_machines;
// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
BOOST_AUTO_TEST_CASE_TEMPLATE( serialize_with_history_test, test_machine, test_machines )
{
typename test_machine::player p;