2
0
mirror of https://github.com/boostorg/msm.git synced 2026-01-19 04:22:11 +00:00

First backmp11 version (#4)

First version of the backmp11 backend.

Contains:
- favor_runtime_speed policy that mainly replaces MPL with Mp11
- favor_compile_time that uses a new mechanism with dispatch tables per state
This commit is contained in:
Christian Granzin
2025-04-15 14:32:20 +02:00
committed by GitHub
parent 7753fa0170
commit 2d87fa9145
54 changed files with 5183 additions and 93 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/.cache
/.vscode
/build
/cmp_*.cpp
/format.cpp

View File

@@ -6,6 +6,12 @@
cmake_minimum_required(VERSION 3.5...3.16)
project(boost_msm VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
# Temporary settings for development, need to be cleaned up later.
# Required for testing puml frontend
# set(CMAKE_CXX_STANDARD 20)
# Required due to bug in clang19
# add_compile_options("-Wno-missing-template-arg-list-after-template-kw")
# add_compile_options("-ftime-trace")
add_library(boost_msm INTERFACE)
add_library(Boost::msm ALIAS boost_msm)
@@ -34,8 +40,6 @@ target_link_libraries(boost_msm
)
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
enable_testing()
add_subdirectory(test)
endif()

View File

@@ -0,0 +1,63 @@
# Boost MSM backmp11 backend
The new backend `backmp11` is a new backwards-compatible backend that has the following goals:
- reduce compilation runtime and RAM usage
- reduce state machine runtime
It is named after the metaprogramming library Boost Mp11, the main contributor to the optimizations:
It replaces usages of MPL with Mp11 to get rid of the C++03 emulation of variadic templates.
This backend contains additional optimizations that are further described below.
## How to use it
The backend and both its policies `favor_runtime_speed` and `favor_compile_time` should be compatible with existing code. Required replacements to try it out:
- use `boost::msm::backmp11::state_machine` in place of `boost::msm::back::state_machine` and
- use `boost::msm::backmp11::favor_compile_time` in place of `boost::msm::back::favor_compile_time`
When using the `favor_compile_time` policy, a different macro to generate missing parts of a SM is needed:
- use `BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(<fsmname>)` in place of `BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(<fsmname>)`
## General optimizations
- Replacement of CPU-intensive calls due to C++03 recursion from MPL to Mp11
- Applied type punning where useful (to reduce template instantiations, e.g. std::deque & other things around the dispatch table)
## Optimizations applied to the `favor_runtime_speed` policy
Summary:
- Optimized cell initialization with initializer arrays (to reduce template instantiations)
- TODO: double-check optimization
- Default-initialized everything and afterwards only defer transition cells
## Optimizations applied to the `favor_compile_time` policy
Once an event is given to the FSM for processing, it is immediately converted to `any` and processing continues with this `any` event.
The structure of the dispatch table has been reworked, one dispatch table is created per state as a hash map.
The state dispatch tables are designed to directly work with the `any` event, they use the event's type index via its `type()` function as hash value.
This mechanism enables SMs to forward events to sub-SMs without requiring additional template instantiations just for forwarding as was needed with the `process_any_event` mechanism.
The new mechanism renders the `process_any_event` function obsolete and enables **forwarding of events to sub-SMs in O(1) complexity instead of O(N)**.
Summary:
- Use one dispatch table per state to reduce compiler processing time
- The algorithms for procesing the STT and states are optimized to go through rows and states only once
- These dispatch tables are hash tables with type_id as key
- Apply type erasure with boost::any as early as possible and do further processing only with any events
- each dispatch table only has to cover the events it's handling, no template instantiations required for forwarding events to sub-SMs
- Use `std::any` if C++17 is available (up to 30% runtime impact because of small value optimization in `std::any`)
## Learnings:
- If only a subset needs to be processed, prefer copy_if & transform over fold
- Selecting a template-based function overload in Mp11 seems more efficient than using enable_if/disable_if
## TODOs:
- Consider trying out the tuple impl from SML

View File

@@ -0,0 +1,38 @@
// 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_COMMON_TYPES_H
#define BOOST_MSM_BACKMP11_COMMON_TYPES_H
#include <boost/msm/back/common_types.hpp>
namespace boost { namespace msm { namespace backmp11
{
using back::HandledEnum;
using back::HANDLED_FALSE;
using back::HANDLED_TRUE;
using back::HANDLED_GUARD_REJECT;
using back::HANDLED_DEFERRED;
using back::execute_return;
using back::EVENT_SOURCE_DEFAULT;
using back::EVENT_SOURCE_DIRECT;
using back::EVENT_SOURCE_DEFERRED;
using back::EVENT_SOURCE_MSG_QUEUE;
using back::EventSource;
}}} // namespace boost::msm::backmp11
#endif // BOOST_MSM_BACKMP11_COMMON_TYPES_H

View File

@@ -0,0 +1,413 @@
// 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_DISPATCH_TABLE_H
#define BOOST_MSM_BACKMP11_DISPATCH_TABLE_H
#include <cstdint>
#include <utility>
#include <boost/mp11.hpp>
#include <boost/mp11/mpl_list.hpp>
#include <boost/mpl/reverse_fold.hpp>
#include <boost/mpl/greater.hpp>
#include <boost/mpl/filter_view.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/advance.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/msm/event_traits.hpp>
#include <boost/msm/back/traits.hpp>
#include <boost/msm/back/default_compile_policy.hpp>
#include <boost/msm/backmp11/metafunctions.hpp>
#include <boost/msm/backmp11/common_types.hpp>
namespace boost { namespace msm { namespace backmp11
{
// Value used to initialize a cell of the dispatch table
template<typename Cell>
struct init_cell_value
{
size_t index;
Cell address;
};
template<size_t v1, typename Cell, Cell v2>
struct init_cell_constant
{
static constexpr init_cell_value<Cell> value = {v1, v2};
};
// Type-punned init cell value to suppress redundant template instantiations
typedef HandledEnum (*generic_cell)();
struct generic_init_cell_value
{
size_t index;
generic_cell address;
};
// Helper to create an array of init cell values for table initialization
template<typename Cell, typename InitCellConstants, std::size_t... I>
static const init_cell_value<Cell>* const get_init_cells_impl(mp11::index_sequence<I...>)
{
static constexpr init_cell_value<Cell> values[] {mp11::mp_at_c<InitCellConstants, I>::value...};
return values;
}
template<typename Cell, typename InitCellConstants>
static const generic_init_cell_value* const get_init_cells()
{
return reinterpret_cast<const generic_init_cell_value*>(
get_init_cells_impl<Cell, InitCellConstants>(mp11::make_index_sequence<mp11::mp_size<InitCellConstants>::value>{}));
}
template<typename CompilePolicy>
struct cell_initializer;
template<>
struct cell_initializer<favor_runtime_speed>
{
static void init(generic_cell* entries, const generic_init_cell_value* array, size_t size)
{
for (size_t i=0; i<size; i++)
{
const auto& item = array[i];
entries[item.index] = item.address;
}
}
};
template<typename Fsm, typename State, typename Event>
struct table_index
{
using type = mp11::mp_if<
mp11::mp_or<
mp11::mp_not<is_same<State, Fsm>>,
typename has_state_delayed_event<State, Event>::type
>,
mp11::mp_size_t<get_state_id<typename create_stt<Fsm>::type, State>::value + 1>,
mp11::mp_size_t<0>
>;
};
template<typename Fsm, typename State>
struct table_index<Fsm, State, void>
{
using type = mp11::mp_if<
mp11::mp_not<is_same<State, Fsm>>,
mp11::mp_size_t<get_state_id<typename create_stt<Fsm>::type, State>::value + 1>,
mp11::mp_size_t<0>
>;
};
template<typename Fsm, typename State, typename Event = void>
using get_table_index = typename table_index<Fsm, State, Event>::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, class Stt, class CompilePolicy>
class dispatch_table;
template<class Fsm, class Stt>
class dispatch_table<Fsm, Stt, favor_runtime_speed>
{
public:
// Dispatch function for a specific event.
template<class Event>
using cell = HandledEnum (*)(Fsm&, int,int,Event const&);
// Dispatch an event.
template<class Event>
static HandledEnum dispatch(Fsm& fsm, int region_id, int state_id, const Event& event)
{
return event_dispatch_table<Event>::instance().entries[state_id+1](fsm, region_id, 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)
{
return event_dispatch_table<Event>::instance().entries[0](fsm, region_id, 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_mp11 state_set_mp11;
BOOST_STATIC_CONSTANT(int, max_state = (mp11::mp_size<state_set_mp11>::value));
// Dispatch table for a specific event.
template<class Event>
class event_dispatch_table
{
public:
using cell = cell<Event>;
// The singleton instance.
static const event_dispatch_table& instance() {
static event_dispatch_table table;
return table;
}
private:
// initialize the dispatch table for a given Event and Fsm
event_dispatch_table()
{
// Initialize cells for no transition
for (size_t i=0;i<max_state+1; i++)
{
entries[i] = &Fsm::call_no_transition;
}
// Initialize cells for defer transition
typedef mp11::mp_copy_if<
typename generate_state_set<Stt>::state_set_mp11,
state_filter_predicate
> filtered_states;
typedef mp11::mp_transform<
preprocess_state,
filtered_states
> preprocessed_states;
cell_initializer::init(
reinterpret_cast<generic_cell*>(entries),
get_init_cells<cell, preprocessed_states>(),
mp11::mp_size<preprocessed_states>::value
);
// build chaining rows for rows coming from the same state and the current event
// first we build a map of sequence for every source
// in reverse order so that the frow's are handled first (UML priority)
typedef mp11::mp_fold<
mp11::mp_copy_if<
typename to_mp_list<Stt>::type,
event_filter_predicate
>,
mp11::mp_list<>,
map_updater
> map_of_row_seq;
// and then build chaining rows for all source states having more than 1 row
typedef mp11::mp_transform<
row_chainer,
map_of_row_seq
> chained_rows;
typedef mp11::mp_transform<
preprocess_row,
chained_rows
> chained_and_preprocessed_rows;
// Go back and fill in cells for matching transitions.
cell_initializer::init(
reinterpret_cast<generic_cell*>(entries),
get_init_cells<cell, chained_and_preprocessed_rows>(),
mp11::mp_size<chained_and_preprocessed_rows>::value
);
}
// 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
{
typedef State current_state_type;
typedef AnEvent 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 & )
{
// if at least one guard rejected, this will be ignored, otherwise will generate an error
return HANDLED_FALSE;
}
template <class Sequence>
static
HandledEnum
execute(Fsm& fsm, int region_index , int state, 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 (HANDLED_TRUE!=res && 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,
::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 ((HANDLED_FALSE==sub_res) && (HANDLED_GUARD_REJECT==res) )
return 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)
{
// forward to helper
return execute_helper::template execute<Seq>(fsm,region_index,state,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
{
// 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
enum { number_frows = boost::mp11::mp_count_if<typename Entry::second, has_is_frow>::value };
//erases the first NumberToDelete rows
template<class Sequence, int NumberToDelete>
struct erase_first_rows
{
typedef typename ::boost::mpl::erase<
typename Entry::second,
typename ::boost::mpl::begin<Sequence>::type,
typename ::boost::mpl::advance<
typename ::boost::mpl::begin<Sequence>::type,
::boost::mpl::int_<NumberToDelete> >::type
>::type type;
};
// if we have more than 1 frow with this event (not allowed), delete the spare
typedef typename ::boost::mpl::eval_if<
typename ::boost::mpl::bool_< number_frows >= 2 >::type,
erase_first_rows<typename Entry::second,number_frows-1>,
::boost::mpl::identity<typename Entry::second>
>::type filtered_stt;
typedef chain_row<filtered_stt,Event,
typename Entry::first > type;
};
// helper for lazy evaluation in eval_if of change_frow_event
template <class Transition,class NewEvent>
struct replace_event
{
typedef typename Transition::template replace_event<NewEvent>::type type;
};
// changes the event type for a frow to the event we are dispatching
// this helps ensure that an event does not get processed more than once because of frows and base events.
template <class FrowTransition>
struct change_frow_event
{
typedef typename ::boost::mp11::mp_if_c<
has_is_frow<FrowTransition>::type::value,
replace_event<FrowTransition,Event>,
boost::mp11::mp_identity<FrowTransition>
>::type type;
};
template <class Transition>
struct convert_event_and_forward
{
static HandledEnum execute(Fsm& fsm, int region_index, int state, Event const& evt)
{
typename Transition::transition_event forwarded(evt);
return Transition::execute(fsm,region_index,state,forwarded);
}
};
using init_cell_value = init_cell_value<cell>;
template<size_t v1, cell v2>
using init_cell_constant = init_cell_constant<v1, cell, v2>;
template<cell v>
using cell_constant = std::integral_constant<cell, v>;
using cell_initializer = cell_initializer<favor_runtime_speed>;
// Helpers for state processing
template<typename State>
using state_filter_predicate = typename has_state_delayed_event<State, Event>::type;
template<typename State, typename fsm=Fsm>
using preprocess_state = init_cell_constant<get_table_index<Fsm, State, Event>::value, &fsm::defer_transition>;
// Helpers for row processing
// First operation (fold)
template <typename T>
using event_filter_predicate = mp11::mp_and<
mp11::mp_not<has_not_real_row_tag<T>>,
mp11::mp_or<
is_base_of<typename T::transition_event, Event>,
typename is_kleene_event<typename T::transition_event>::type
>
>;
template <typename M, typename Key, typename Value>
using push_map_value = mp11::mp_push_front<
mp11::mp_second<mp11::mp_map_find<M, Key>>,
Value>;
template<typename M, typename T>
using map_updater = mp11::mp_map_replace<
M,
mp11::mp_list<
typename T::current_state_type,
mp11::mp_eval_if_c<
!mp11::mp_map_contains<M, typename T::current_state_type>::value,
// first row on this source state, make a list with 1 element
mp11::mp_list<typename change_frow_event<T>::type>,
// list already exists, add the row
push_map_value,
M,
typename T::current_state_type,
typename change_frow_event<T>::type
>
>
>;
// Second operation (transform)
template<typename T>
using to_mpl_map_entry = mpl::pair<
mp11::mp_first<T>,
mp11::mp_second<T>
>;
template<typename T>
using row_chainer = mp11::mp_if_c<
(mp11::mp_size<typename to_mp_list<mp11::mp_second<T>>::type>::value > 1),
// we need row chaining
typename make_chain_row_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 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 Transition::current_state_type>::value,
// Address of the execute function
mp11::mp_eval_if_c<
is_kleene_event<typename Transition::transition_event>::type::value,
cell_constant<
&convert_event_and_forward<Transition>::execute
>,
preprocess_row_helper,
Transition
>::value
>;
// data members
public:
// max_state+1, because 0 is reserved for this fsm (internal transitions)
cell entries[max_state+1];
};
};
}}} // boost::msm::backmp11
#endif //BOOST_MSM_BACKMP11_DISPATCH_TABLE_H

View File

@@ -0,0 +1,328 @@
// 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_FAVOR_COMPILE_TIME_H
#define BOOST_MSM_BACKMP11_FAVOR_COMPILE_TIME_H
#if __cplusplus >= 201703L
#include <any>
#endif
#include <deque>
#include <typeindex>
#include <unordered_map>
#include <utility>
#include <boost/mpl/filter_view.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/msm/common.hpp>
#include <boost/msm/backmp11/metafunctions.hpp>
#include <boost/msm/back/common_types.hpp>
#include <boost/msm/backmp11/dispatch_table.hpp>
namespace boost { namespace msm { namespace backmp11
{
#define BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(fsmname) \
template<> \
const fsmname::sm_dispatch_table& fsmname::sm_dispatch_table::instance() \
{ \
static dispatch_table table; \
return table; \
}
struct favor_compile_time
{
typedef int compile_policy;
typedef ::boost::mpl::false_ add_forwarding_rows;
#if __cplusplus >= 201703L
typedef std::any any_event;
#else
typedef boost::any any_event;
#endif
};
template <class Event>
struct is_completion_event<Event, favor_compile_time>
{
static bool value(const Event& event)
{
return (event.type() == boost::typeindex::type_id<front::none>());
}
};
template<typename Stt>
struct get_real_rows
{
template<typename Transition>
using is_real_row = mp11::mp_not<typename has_not_real_row_tag<Transition>::type>;
typedef mp11::mp_copy_if<Stt, is_real_row> type;
};
// Convert an event to a type index.
template<class Event>
inline std::type_index to_type_index()
{
return std::type_index{typeid(Event)};
}
// Helper class to manage end interrupt events.
class end_interrupt_event_helper
{
public:
template<class Fsm>
end_interrupt_event_helper(const Fsm& fsm)
{
mp11::mp_for_each<mp11::mp_transform<mp11::mp_identity, typename Fsm::event_set_mp11>>(
init_helper<Fsm>{fsm, m_is_flag_active_functions});
}
bool is_end_interrupt_event(const favor_compile_time::any_event& event) const
{
auto it = m_is_flag_active_functions.find(event.type());
if (it != m_is_flag_active_functions.end())
{
return (it->second)();
}
return false;
}
private:
using map = std::unordered_map<std::type_index, std::function<bool()>>;
template<typename Fsm>
class init_helper
{
public:
init_helper(const Fsm& fsm, map& is_flag_active_functions)
: m_fsm(fsm), m_is_flag_active_functions(is_flag_active_functions) {}
template<typename Event>
void operator()(mp11::mp_identity<Event>)
{
using Flag = EndInterruptFlag<Event>;
const Fsm* fsm = &m_fsm;
m_is_flag_active_functions[to_type_index<Event>()] =
[fsm](){return fsm->template is_flag_active<Flag>();};
}
private:
const Fsm& m_fsm;
map& m_is_flag_active_functions;
};
map m_is_flag_active_functions;
};
struct chain_row
{
using any_event = favor_compile_time::any_event;
template<typename Fsm>
HandledEnum operator()(Fsm& fsm, int region, int state, any_event const& evt) const
{
typedef HandledEnum (*real_cell)(Fsm&, int, int, any_event const&);
HandledEnum res = HANDLED_FALSE;
typename std::deque<generic_cell>::const_iterator it = one_state.begin();
while (it != one_state.end() && (res != HANDLED_TRUE && res != HANDLED_DEFERRED ))
{
auto fnc = reinterpret_cast<real_cell>(reinterpret_cast<void*>(*it));
HandledEnum handled = (*fnc)(fsm,region,state,evt);
// reject is considered as erasing an error (HANDLED_FALSE)
if ((HANDLED_FALSE==handled) && (HANDLED_GUARD_REJECT==res) )
res = HANDLED_GUARD_REJECT;
else
res = handled;
++it;
}
return res;
}
// Use a deque with a generic type to avoid unnecessary template instantiations.
std::deque<generic_cell> one_state;
};
// 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, class Stt>
struct dispatch_table<Fsm, Stt, favor_compile_time>
{
using any_event = favor_compile_time::any_event;
public:
// Dispatch an event.
static HandledEnum dispatch(Fsm& fsm, int region_id, int state_id, const any_event& event)
{
return instance().m_state_dispatch_tables[state_id+1].dispatch(fsm, region_id, state_id, event);
}
// Dispatch an event to the FSM's internal table.
static HandledEnum dispatch_internal(Fsm& fsm, int region_id, int state_id, const any_event& event)
{
return instance().m_state_dispatch_tables[0].dispatch(fsm, region_id, state_id, event);
}
private:
// Adapter for calling a row's execute function.
template<typename Event, typename Row>
static HandledEnum convert_and_execute(Fsm& fsm, int region_id, int state_id, const any_event& event)
{
return Row::execute(fsm, region_id, state_id, *any_cast<Event>(&event));
}
// Dispatch table for one state.
class state_dispatch_table
{
public:
// Initialize the table for the given state.
template<typename State>
void init()
{
// Fill in cells for deferred events.
mp11::mp_for_each<mp11::mp_transform<mp11::mp_identity, to_mp_list_t<typename State::deferred_events>>>(
deferred_event_init_helper{m_entries});
init_call_submachine<State>();
}
template<typename State>
typename ::boost::enable_if<is_composite_state<State>, void>::type
init_call_submachine()
{
m_call_submachine = [](Fsm& fsm, const any_event& evt)
{
return (fsm.template get_state<State&>()).process_event_internal(evt);
};
}
template<typename State>
typename ::boost::disable_if<is_composite_state<State>, void>::type
init_call_submachine()
{
}
template<typename Event>
chain_row& get_chain_row()
{
return m_entries[to_type_index<Event>()];
}
// Dispatch an event.
HandledEnum dispatch(Fsm& fsm, int region_id, int state_id, const any_event& event) const
{
HandledEnum handled = HANDLED_FALSE;
if (m_call_submachine)
{
handled = m_call_submachine(fsm, event);
if (handled)
{
return handled;
}
}
auto it = m_entries.find(event.type());
if (it != m_entries.end())
{
handled = (it->second)(fsm, region_id, state_id, event);
}
return handled;
}
private:
class deferred_event_init_helper
{
public:
deferred_event_init_helper(std::unordered_map<std::type_index, chain_row>& entries)
: m_entries(entries) {}
template<typename Event>
void operator()(mp11::mp_identity<Event>)
{
auto& chain_row = m_entries[to_type_index<Event>()];
chain_row.one_state.push_front(reinterpret_cast<generic_cell>(&Fsm::template defer_transition<any_event>));
}
private:
std::unordered_map<std::type_index, chain_row>& m_entries;
};
std::unordered_map<std::type_index, chain_row> m_entries;
// Special functor if the state is a composite
std::function<HandledEnum(Fsm&, const any_event&)> m_call_submachine;
};
class row_init_helper
{
public:
row_init_helper(state_dispatch_table* state_dispatch_tables)
: m_state_dispatch_tables(state_dispatch_tables) {}
template<typename Row>
void operator()(Row)
{
using Event = typename Row::transition_event;
using StateId = get_state_id<Stt, typename Row::current_state_type>;
auto& chain_row = m_state_dispatch_tables[StateId::value+1].template get_chain_row<Event>();
chain_row.one_state.push_front(reinterpret_cast<generic_cell>(&convert_and_execute<Event, Row>));
}
private:
state_dispatch_table* m_state_dispatch_tables;
};
class state_init_helper
{
public:
state_init_helper(state_dispatch_table* state_dispatch_tables)
: m_state_dispatch_tables(state_dispatch_tables) {}
template<typename State>
void operator()(mp11::mp_identity<State>)
{
m_state_dispatch_tables[get_state_id<Stt, State>::value+1].template init<State>();
}
private:
state_dispatch_table* m_state_dispatch_tables;
};
// Filter a state to check whether state-specific initialization
// needs to be performed.
template<typename State>
using state_filter_predicate = mp11::mp_or<
mp11::mp_not<mp11::mp_empty<to_mp_list_t<typename State::deferred_events>>>,
is_composite_state<State>
>;
dispatch_table()
{
// Execute row-specific initializations.
mp11::mp_for_each<typename get_real_rows<Stt>::type>(
row_init_helper(m_state_dispatch_tables));
// Execute state-specific initializations.
using filtered_states = mp11::mp_copy_if<state_set_mp11, state_filter_predicate>;
mp11::mp_for_each<mp11::mp_transform<mp11::mp_identity, filtered_states>>(
state_init_helper(m_state_dispatch_tables));
}
// The singleton instance.
static const dispatch_table& instance();
// Compute the maximum state value in the sm so we know how big
// to make the table
typedef typename generate_state_set<Stt>::state_set_mp11 state_set_mp11;
BOOST_STATIC_CONSTANT(int, max_state = (mp11::mp_size<state_set_mp11>::value));
state_dispatch_table m_state_dispatch_tables[max_state+1];
};
}}} // boost::msm::backmp11
#endif //BOOST_MSM_BACKMP11_FAVOR_COMPILE_TIME_H

View File

@@ -0,0 +1,206 @@
// 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_HISTORY_POLICIES_H
#define BOOST_MSM_BACKMP11_HISTORY_POLICIES_H
#include <boost/msm/backmp11/metafunctions.hpp>
namespace boost { namespace msm { namespace backmp11
{
// policy classes
// Default: no history used
template <int NumberOfRegions>
class NoHistoryImpl
{
public:
NoHistoryImpl(){}
~NoHistoryImpl(){}
void set_initial_states(int* const initial_states)
{
for (int i=0;i<NumberOfRegions;++i)
m_initialStates[i] = initial_states[i];
}
void history_exit(int* const )
{
// ignore
}
// returns the state where the state machine should be at start
template <class Event>
const int* history_entry(Event const& )
{
// always come back to the original state
return m_initialStates;
}
NoHistoryImpl<NumberOfRegions>& operator=(NoHistoryImpl<NumberOfRegions> const& rhs)
{
for (int i=0; i<NumberOfRegions;++i)
{
m_initialStates[i] = rhs.m_initialStates[i];
}
return *this;
}
// this policy deletes all waiting deferred events
template <class Event>
bool process_deferred_events(Event const&)const
{
return false;
}
template<class Archive>
void serialize(Archive & ar, const unsigned int)
{
ar & m_initialStates;
}
private:
int m_initialStates[NumberOfRegions];
};
// not UML standard. Always activates history, no matter which event generated the transition
template <int NumberOfRegions>
class AlwaysHistoryImpl
{
public:
AlwaysHistoryImpl(){}
~AlwaysHistoryImpl(){}
void set_initial_states(int* const initial_states)
{
for (int i=0;i<NumberOfRegions;++i)
m_initialStates[i] = initial_states[i];
}
void history_exit(int* const current_states)
{
for (int i=0;i<NumberOfRegions;++i)
m_initialStates[i] = current_states[i];
}
// returns the state where the state machine should be at start
template <class Event>
const int* history_entry(Event const& )
{
// always load back the last active state
return m_initialStates;
}
AlwaysHistoryImpl<NumberOfRegions>& operator=(AlwaysHistoryImpl<NumberOfRegions> const& rhs)
{
for (int i=0; i<NumberOfRegions;++i)
{
m_initialStates[i] = rhs.m_initialStates[i];
}
return *this;
}
// the history policy keeps all deferred events until next reentry
template <class Event>
bool process_deferred_events(Event const&)const
{
return true;
}
template<class Archive>
void serialize(Archive & ar, const unsigned int)
{
ar & m_initialStates;
}
private:
int m_initialStates[NumberOfRegions];
};
// UML Shallow history. For deep history, just use this policy for all the contained state machines
template <class Events,int NumberOfRegions>
class ShallowHistoryImpl
{
typedef typename to_mp_list<Events>::type EventsMp11;
public:
ShallowHistoryImpl(){}
~ShallowHistoryImpl(){}
void set_initial_states(int* const initial_states)
{
for (int i=0;i<NumberOfRegions;++i)
{
m_currentStates[i] = initial_states[i];
m_initialStates[i] = initial_states[i];
}
}
void history_exit(int* const current_states)
{
for (int i=0;i<NumberOfRegions;++i)
m_currentStates[i] = current_states[i];
}
// returns the state where the state machine should be at start
template <class Event>
const int* history_entry(Event const&)
{
if (mp11::mp_contains<EventsMp11,Event>::value)
{
return m_currentStates;
}
// not one of our events, no history
return m_initialStates;
}
ShallowHistoryImpl<Events,NumberOfRegions>& operator=(ShallowHistoryImpl<Events,NumberOfRegions> const& rhs)
{
for (int i=0; i<NumberOfRegions;++i)
{
m_initialStates[i] = rhs.m_initialStates[i];
m_currentStates[i] = rhs.m_currentStates[i];
}
return *this;
}
// the history policy keeps deferred events until next reentry if coming from our history event
template <class Event>
bool process_deferred_events(Event const&)const
{
return mp11::mp_contains<EventsMp11,Event>::value;
}
template<class Archive>
void serialize(Archive & ar, const unsigned int)
{
ar & m_initialStates;
ar & m_currentStates;
}
private:
int m_initialStates[NumberOfRegions];
int m_currentStates[NumberOfRegions];
};
struct NoHistory
{
typedef int history_policy;
template <int NumberOfRegions>
struct apply
{
typedef NoHistoryImpl<NumberOfRegions> type;
};
};
struct AlwaysHistory
{
typedef int history_policy;
template <int NumberOfRegions>
struct apply
{
typedef AlwaysHistoryImpl<NumberOfRegions> type;
};
};
template <class Events>
struct ShallowHistory
{
typedef int history_policy;
template <int NumberOfRegions>
struct apply
{
typedef ShallowHistoryImpl<Events,NumberOfRegions> type;
};
};
}}} // boost::msm::backmp11
#endif //BOOST_MSM_BACKMP11_HISTORY_POLICIES_H

View File

@@ -0,0 +1,951 @@
// 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 "boost/msm/front/completion_event.hpp"
#include <algorithm>
#include <boost/mp11.hpp>
#include <boost/mp11/mpl_list.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/count_if.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/has_key.hpp>
#include <boost/mpl/insert.hpp>
#include <boost/mpl/next_prior.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/is_sequence.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/insert_range.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/copy_if.hpp>
#include <boost/mpl/back_inserter.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/fusion/include/insert_range.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/msm/row_tags.hpp>
// mpl_graph graph implementation and depth first search
#include <boost/msm/mpl_graph/incidence_list_graph.hpp>
#include <boost/msm/mpl_graph/depth_first_search.hpp>
#include <boost/msm/back/traits.hpp>
#include <boost/msm/back/default_compile_policy.hpp>
namespace boost { namespace msm { namespace backmp11
{
using back::favor_runtime_speed;
template <typename Sequence, typename Range>
struct set_insert_range
{
typedef typename ::boost::mpl::fold<
Range,Sequence,
::boost::mpl::insert< ::boost::mpl::placeholders::_1, ::boost::mpl::placeholders::_2 >
>::type type;
};
// returns the current state type of a transition
template <class Transition>
struct transition_source_type
{
typedef typename Transition::current_state_type type;
};
// returns the target state type of a transition
template <class Transition>
struct transition_target_type
{
typedef typename Transition::next_state_type type;
};
// Helper to convert a MPL sequence to Mp11
template<typename T>
struct to_mp_list
{
typedef typename mpl::copy<T, mpl::back_inserter<mp11::mp_list<>>>::type type;
};
template<typename ...T>
struct to_mp_list<mp11::mp_list<T...>>
{
typedef mp11::mp_list<T...> type;
};
template<typename ...T>
using to_mp_list_t = typename to_mp_list<T...>::type;
template <class stt>
struct generate_state_set;
template <class Fsm>
struct get_active_state_switch_policy_helper
{
typedef typename Fsm::active_state_switch_policy type;
};
template <class Iter>
struct get_active_state_switch_policy_helper2
{
typedef typename boost::mpl::deref<Iter>::type Fsm;
typedef typename Fsm::active_state_switch_policy type;
};
// returns the active state switching policy
template <class Fsm>
struct get_active_state_switch_policy
{
typedef typename ::boost::mpl::find_if<
typename Fsm::configuration,
has_active_state_switch_policy< ::boost::mpl::placeholders::_1 > >::type iter;
typedef typename ::boost::mpl::eval_if<
typename ::boost::is_same<
iter,
typename ::boost::mpl::end<typename Fsm::configuration>::type
>::type,
get_active_state_switch_policy_helper<Fsm>,
get_active_state_switch_policy_helper2< iter >
>::type type;
};
// returns a mpl::vector containing the init states of a state machine
template <class States>
struct get_initial_states
{
typedef typename ::boost::mpl::if_<
::boost::mpl::is_sequence<States>,
States,
typename ::boost::mpl::push_back< ::boost::mpl::vector0<>,States>::type >::type type;
};
// returns a mpl::int_ containing the size of a region. If the argument is not a sequence, returns 1
template <class region>
struct get_number_of_regions
{
typedef typename mpl::if_<
::boost::mpl::is_sequence<region>,
::boost::mpl::size<region>,
::boost::mpl::int_<1> >::type type;
};
// builds a mpl::vector of initial states
//TODO remove duplicate from get_initial_states
template <class region>
struct get_regions_as_sequence
{
typedef typename ::boost::mpl::if_<
::boost::mpl::is_sequence<region>,
region,
typename ::boost::mpl::push_back< ::boost::mpl::vector0<>,region>::type >::type type;
};
template <class ToCreateSeq>
struct get_explicit_creation_as_sequence
{
typedef typename ::boost::mpl::if_<
::boost::mpl::is_sequence<ToCreateSeq>,
ToCreateSeq,
typename ::boost::mpl::push_back< ::boost::mpl::vector0<>,ToCreateSeq>::type >::type type;
};
// returns true for composite states
template <class State>
struct is_composite_state
{
enum {value = has_composite_tag<State>::type::value};
typedef typename has_composite_tag<State>::type type;
};
// 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 <class stt>
struct generate_state_set
{
typedef typename to_mp_list<stt>::type stt_mp11;
// first add the source states
template<typename V, typename T>
using set_push_source_state = mp11::mp_set_push_back<
V,
typename T::current_state_type
>;
typedef typename mp11::mp_fold<
typename to_mp_list<stt>::type,
mp11::mp_list<>,
set_push_source_state
> source_state_set_mp11;
// then add the target states
template<typename V, typename T>
using set_push_target_state = mp11::mp_set_push_back<
V,
typename T::next_state_type
>;
typedef typename mp11::mp_fold<
stt_mp11,
source_state_set_mp11,
set_push_target_state
> state_set_mp11;
};
// extends a state set to a map with key=state and value=id
template <class stt>
struct generate_state_map
{
typedef typename generate_state_set<stt>::state_set_mp11 state_set;
typedef mp11::mp_iota<mp11::mp_size<state_set>> indices;
typedef mp11::mp_transform_q<
mp11::mp_bind<mp11::mp_list, mp11::_1, mp11::_2>,
state_set,
indices
> type;
};
// filters the state set to contain only composite states
template <class stt>
struct generate_composite_state_set
{
typedef typename generate_state_set<stt>::state_set_mp11 state_set;
template<typename State>
using is_composite = typename is_composite_state<State>::type;
typedef mp11::mp_copy_if<
state_set,
is_composite
> type;
};
// returns the id of a given state
template <class stt,class State>
struct get_state_id
{
typedef mp11::mp_second<mp11::mp_map_find<
typename generate_state_map<stt>::type,
State
>> type;
static constexpr typename type::value_type value = type::value;
};
// iterates through the transition table and generate a set containing all the events
template <class stt>
struct generate_event_set
{
typedef typename to_mp_list<stt>::type stt_mp11;
template<typename V, typename T>
using event_set_pusher = mp11::mp_set_push_back<
V,
typename T::transition_event
>;
typedef mp11::mp_fold<
typename to_mp_list<stt>::type,
mp11::mp_list<>,
event_set_pusher
> event_set_mp11;
};
// extends an event set to a map with key=event and value=id
template <class stt>
struct generate_event_map
{
typedef typename generate_event_set<stt>::event_set_mp11 event_set;
typedef mp11::mp_iota<mp11::mp_size<event_set>> indices;
typedef mp11::mp_transform_q<
mp11::mp_bind<mp11::mp_list, mp11::_1, mp11::_2>,
event_set,
indices
> type;
};
// returns the id of a given event
template <class stt,class Event>
struct get_event_id
{
typedef mp11::mp_second<mp11::mp_map_find<
typename generate_event_map<stt>::type,
Event
>> type;
enum {value = type::value};
};
// returns a mpl::bool_<true> if State has Event as deferred event
template <class State, class Event>
struct has_state_delayed_event
{
typedef typename mp11::mp_contains<
typename to_mp_list<typename State::deferred_events>::type,
Event
> type;
};
// returns a mpl::bool_<true> if State has any deferred event
template <class State>
struct has_state_delayed_events
{
typedef typename mp11::mp_not<mp11::mp_empty<
typename to_mp_list<typename State::deferred_events>::type
>> type;
};
// 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;
};
// metafunctions used to find out if a state is entry, exit or something else
template <class State>
struct is_pseudo_entry
{
typedef typename ::boost::mpl::if_< typename has_pseudo_entry<State>::type,
::boost::mpl::bool_<true>,::boost::mpl::bool_<false>
>::type type;
};
// says if a state is an exit pseudo state
template <class State>
struct is_pseudo_exit
{
typedef typename has_pseudo_exit<State>::type type;
};
// says if a state is an entry pseudo state or an explicit entry
template <class State>
struct is_direct_entry
{
typedef typename ::boost::mpl::if_< typename has_explicit_entry_state<State>::type,
::boost::mpl::bool_<true>, ::boost::mpl::bool_<false>
>::type type;
};
//converts a "fake" (simulated in a state_machine_ description )state into one which will really get created
template <class StateType,class CompositeType>
struct convert_fake_state
{
// converts a state (explicit entry) into the state we really are going to create (explicit<>)
typedef typename ::boost::mpl::if_<
typename is_direct_entry<StateType>::type,
typename CompositeType::template direct<StateType>,
typename ::boost::mpl::identity<StateType>::type
>::type type;
};
template <class StateType>
struct get_explicit_creation
{
typedef typename StateType::explicit_creation type;
};
template <class StateType>
struct get_wrapped_entry
{
typedef typename StateType::wrapped_entry type;
};
// 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 <class StateType>
struct get_wrapped_state
{
typedef typename ::boost::mpl::eval_if<
typename has_wrapped_entry<StateType>::type,
get_wrapped_entry<StateType>,
::boost::mpl::identity<StateType> >::type type;
};
template <class Derived>
struct create_stt
{
//typedef typename Derived::transition_table stt;
typedef typename Derived::real_transition_table Stt;
// get the state set
typedef typename generate_state_set<Stt>::state_set_mp11 states;
// transform the initial region(s) in a sequence
typedef typename get_regions_as_sequence<typename Derived::initial_state>::type init_states;
// iterate through the initial states and add them in the stt if not already there
template<typename V, typename T>
using states_pusher = mp11::mp_if_c<
mp11::mp_set_contains<states, T>::value,
V,
mp11::mp_push_back<
V,
not_a_row<typename get_wrapped_state<T>::type>
>
>;
typedef typename mp11::mp_fold<
typename to_mp_list<init_states>::type,
typename to_mp_list<Stt>::type,
states_pusher
> with_init;
// do the same for states marked as explicitly created
typedef typename get_explicit_creation_as_sequence<
typename ::boost::mpl::eval_if<
typename has_explicit_creation<Derived>::type,
get_explicit_creation<Derived>,
::boost::mpl::vector0<> >::type
>::type fake_explicit_created;
typedef typename
::boost::mpl::transform<
fake_explicit_created,convert_fake_state< ::boost::mpl::placeholders::_1,Derived> >::type explicit_created;
typedef typename mp11::mp_fold<
typename to_mp_list<explicit_created>::type,
with_init,
states_pusher
> type;
};
// returns the transition table of a Composite state
template <class Composite>
struct get_transition_table
{
typedef typename create_stt<Composite>::type type;
};
// recursively builds an internal table including those of substates, sub-substates etc.
// variant for submachines
template <class StateType,class IsComposite>
struct recursive_get_internal_transition_table
{
// get the composite's internal table
typedef typename StateType::internal_transition_table composite_table;
// and for every substate (state of submachine), recursively get the internal transition table
typedef typename generate_state_set<typename StateType::stt>::state_set_mp11 composite_states;
template<typename V, typename T>
using append_recursive_internal_transition_table = mp11::mp_append<
V,
typename recursive_get_internal_transition_table<T, typename has_composite_tag<T>::type>::type
>;
typedef typename mp11::mp_fold<
composite_states,
typename to_mp_list<composite_table>::type,
append_recursive_internal_transition_table
> type;
};
// stop iterating on leafs (simple states)
template <class StateType>
struct recursive_get_internal_transition_table<StateType, ::boost::mpl::false_ >
{
typedef typename to_mp_list<
typename StateType::internal_transition_table
>::type 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 <class Composite>
struct recursive_get_transition_table
{
// get the transition table of the state if it's a state machine
template<typename T>
using get_transition_table_mp11 = typename get_transition_table<T>::type;
typedef typename mp11::mp_eval_if_c<
!has_composite_tag<Composite>::type::value,
mp11::mp_list<>,
get_transition_table_mp11,
Composite
> org_table;
typedef typename generate_state_set<org_table>::state_set_mp11 states;
// and for every substate, recursively get the transition table if it's a state machine
template<typename V, typename T>
using append_recursive_transition_table = mp11::mp_append<
V,
typename recursive_get_transition_table<T>::type
>;
typedef typename mp11::mp_fold<
states,
org_table,
append_recursive_transition_table> type;
};
// metafunction used to say if a SM has pseudo exit states
template <class Derived>
struct has_fsm_deferred_events
{
typedef typename create_stt<Derived>::type Stt;
typedef typename generate_state_set<Stt>::state_set_mp11 state_set_mp11;
template<typename T>
using has_activate_deferred_events_mp11 = typename has_activate_deferred_events<T>::type;
template<typename T>
using has_state_delayed_events_mp11 = typename has_state_delayed_events<T>::type;
typedef typename mp11::mp_or<
typename has_activate_deferred_events<Derived>::type,
mp11::mp_any_of<
typename to_mp_list<typename Derived::configuration>::type,
has_activate_deferred_events_mp11
>,
mp11::mp_any_of<
state_set_mp11,
has_state_delayed_events_mp11
>
> type;
};
struct favor_compile_time;
// returns a mpl::bool_<true> if State has any delayed event
template <class Event, class CompilePolicy>
struct is_completion_event;
template <class Event>
struct is_completion_event<Event, favor_runtime_speed>
{
typedef typename ::boost::mpl::if_<
has_completion_event<Event>,
::boost::mpl::bool_<true>,
::boost::mpl::bool_<false> >::type type;
static constexpr bool value(const Event&)
{
return type::value;
}
};
// metafunction used to say if a SM has eventless transitions
template <class Derived>
struct has_fsm_eventless_transition
{
typedef typename create_stt<Derived>::type Stt;
typedef typename generate_event_set<Stt>::event_set_mp11 event_list;
typedef mp11::mp_any_of<event_list, has_completion_event> type;
};
template <class Derived>
struct find_completion_events
{
typedef typename create_stt<Derived>::type Stt;
typedef typename generate_event_set<Stt>::event_set_mp11 event_list;
template<typename T>
using has_completion_event_mp11 = typename has_completion_event<T>::type;
typedef typename mp11::mp_copy_if<
event_list,
has_completion_event_mp11
> type;
};
template <class Transition>
struct make_vector
{
typedef ::boost::mpl::vector<Transition> type;
};
template< typename Entry >
struct get_first_element_pair_second
{
typedef typename ::boost::mpl::front<typename Entry::second>::type type;
};
//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 <class State,class ContainingSM>
struct get_owner
{
typedef typename ::boost::mpl::if_<
typename ::boost::mpl::not_<typename ::boost::is_same<typename State::owner,
ContainingSM >::type>::type,
typename State::owner,
State >::type type;
};
template <class Sequence,class ContainingSM>
struct get_fork_owner
{
typedef typename ::boost::mpl::front<Sequence>::type seq_front;
typedef typename ::boost::mpl::if_<
typename ::boost::mpl::not_<
typename ::boost::is_same<typename seq_front::owner,ContainingSM>::type>::type,
typename seq_front::owner,
seq_front >::type type;
};
template <class StateType,class ContainingSM>
struct make_exit
{
typedef typename ::boost::mpl::if_<
typename is_pseudo_exit<StateType>::type ,
typename ContainingSM::template exit_pt<StateType>,
typename ::boost::mpl::identity<StateType>::type
>::type type;
};
template <class StateType,class ContainingSM>
struct make_entry
{
typedef typename ::boost::mpl::if_<
typename is_pseudo_entry<StateType>::type ,
typename ContainingSM::template entry_pt<StateType>,
typename ::boost::mpl::if_<
typename is_direct_entry<StateType>::type,
typename ContainingSM::template direct<StateType>,
typename ::boost::mpl::identity<StateType>::type
>::type
>::type type;
};
// metafunction used to say if a SM has pseudo exit states
template <class StateType>
struct has_exit_pseudo_states_helper
{
typedef typename StateType::stt Stt;
typedef typename generate_state_set<Stt>::type state_list;
typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
state_list,is_pseudo_exit< ::boost::mpl::placeholders::_1> >::value != 0> type;
};
template <class StateType>
struct has_exit_pseudo_states
{
typedef typename ::boost::mpl::eval_if<typename is_composite_state<StateType>::type,
has_exit_pseudo_states_helper<StateType>,
::boost::mpl::bool_<false> >::type type;
};
// builds flags (add internal_flag_list and flag_list). internal_flag_list is used for terminate/interrupt states
template <class StateType>
struct get_flag_list
{
typedef typename mp11::mp_append<
typename to_mp_list<typename StateType::flag_list>::type,
typename to_mp_list<typename StateType::internal_flag_list>::type
> type;
};
template <class StateType>
struct is_state_blocking
{
template<typename T>
using has_event_blocking_flag_mp11 = typename has_event_blocking_flag<T>::type;
typedef typename mp11::mp_any_of<
typename get_flag_list<StateType>::type,
has_event_blocking_flag_mp11
> type;
};
// returns a mpl::bool_<true> if fsm has an event blocking flag in one of its substates
template <class StateType>
struct has_fsm_blocking_states
{
typedef typename create_stt<StateType>::type Stt;
typedef typename generate_state_set<Stt>::state_set_mp11 state_set_mp11;
template<typename T>
using is_state_blocking_mp11 = typename is_state_blocking<T>::type;
typedef typename mp11::mp_any_of<
state_set_mp11,
is_state_blocking_mp11
> type;
};
template <class StateType>
struct is_no_exception_thrown
{
typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
typename StateType::configuration,
has_no_exception_thrown< ::boost::mpl::placeholders::_1 > >::value != 0> found;
typedef typename ::boost::mpl::or_<
typename has_no_exception_thrown<StateType>::type,
found
>::type type;
};
template <class StateType>
struct is_no_message_queue
{
typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
typename StateType::configuration,
has_no_message_queue< ::boost::mpl::placeholders::_1 > >::value != 0> found;
typedef typename ::boost::mpl::or_<
typename has_no_message_queue<StateType>::type,
found
>::type type;
};
template <class StateType>
struct is_active_state_switch_policy
{
typedef ::boost::mpl::bool_< ::boost::mpl::count_if<
typename StateType::configuration,
has_active_state_switch_policy< ::boost::mpl::placeholders::_1 > >::value != 0> found;
typedef typename ::boost::mpl::or_<
typename has_active_state_switch_policy<StateType>::type,
found
>::type type;
};
template <class StateType>
struct get_initial_event
{
typedef typename StateType::initial_event type;
};
template <class StateType>
struct get_final_event
{
typedef typename StateType::final_event type;
};
template <class TransitionTable, class InitState>
struct build_one_orthogonal_region
{
template<typename Row>
struct row_to_incidence :
mp11::mp_list<
::boost::mpl::pair<
typename Row::next_state_type,
typename Row::transition_event>,
typename Row::current_state_type,
typename Row::next_state_type
> {};
typedef typename mp11::mp_transform<
row_to_incidence,
typename to_mp_list<TransitionTable>::type
> transition_incidence_list;
typedef ::boost::msm::mpl_graph::incidence_list_graph<transition_incidence_list>
transition_graph;
struct preordering_dfs_visitor :
::boost::msm::mpl_graph::dfs_default_visitor_operations
{
template<typename Node, typename Graph, typename State>
struct discover_vertex :
::boost::mpl::insert<State, Node>
{};
};
typedef typename mpl::first<
typename ::boost::msm::mpl_graph::depth_first_search<
transition_graph,
preordering_dfs_visitor,
::boost::mpl::set<>,
InitState
>::type
>::type type;
};
template <class Fsm>
struct find_entry_states
{
typedef mp11::mp_copy_if<
typename Fsm::substate_list,
has_explicit_entry_state
> type;
};
template <class Set1, class Set2>
struct is_common_element
{
typedef typename ::boost::mpl::fold<
Set1, ::boost::mpl::false_,
::boost::mpl::if_<
::boost::mpl::has_key<
Set2,
::boost::mpl::placeholders::_2
>,
::boost::mpl::true_,
::boost::mpl::placeholders::_1
>
>::type type;
};
template <class EntryRegion, class AllRegions>
struct add_entry_region
{
typedef typename ::boost::mpl::transform<
AllRegions,
::boost::mpl::if_<
is_common_element<EntryRegion, ::boost::mpl::placeholders::_1>,
set_insert_range< ::boost::mpl::placeholders::_1, EntryRegion>,
::boost::mpl::placeholders::_1
>
>::type type;
};
// build a vector of regions states (as a set)
// one set of states for every region
template <class Fsm, class InitStates>
struct build_orthogonal_regions
{
typedef typename
::boost::mpl::fold<
InitStates, ::boost::mpl::vector0<>,
::boost::mpl::push_back<
::boost::mpl::placeholders::_1,
build_one_orthogonal_region< typename Fsm::stt, ::boost::mpl::placeholders::_2 > >
>::type without_entries;
typedef typename
::boost::mpl::fold<
typename find_entry_states<Fsm>::type, ::boost::mpl::vector0<>,
::boost::mpl::push_back<
::boost::mpl::placeholders::_1,
build_one_orthogonal_region< typename Fsm::stt, ::boost::mpl::placeholders::_2 > >
>::type only_entries;
typedef typename ::boost::mpl::fold<
only_entries , without_entries,
add_entry_region< ::boost::mpl::placeholders::_2, ::boost::mpl::placeholders::_1>
>::type type;
};
template <class GraphAsSeqOfSets, class StateType>
struct find_region_index
{
typedef typename
::boost::mpl::fold<
GraphAsSeqOfSets, ::boost::mpl::pair< ::boost::mpl::int_< -1 > /*res*/, ::boost::mpl::int_<0> /*counter*/ >,
::boost::mpl::if_<
::boost::mpl::has_key< ::boost::mpl::placeholders::_2, StateType >,
::boost::mpl::pair<
::boost::mpl::second< ::boost::mpl::placeholders::_1 >,
::boost::mpl::next< ::boost::mpl::second< ::boost::mpl::placeholders::_1 > >
>,
::boost::mpl::pair<
::boost::mpl::first< ::boost::mpl::placeholders::_1 >,
::boost::mpl::next< ::boost::mpl::second< ::boost::mpl::placeholders::_1 > >
>
>
>::type result_pair;
typedef typename ::boost::mpl::first<result_pair>::type type;
enum {value = type::value};
};
template <class Fsm>
struct check_regions_orthogonality
{
typedef typename build_orthogonal_regions< Fsm,typename Fsm::initial_states>::type regions;
typedef typename mp11::mp_apply<
mp11::mp_plus,
mp11::mp_transform<
mp11::mp_size,
typename to_mp_list<regions>::type
>
> number_of_states_in_regions;
typedef typename ::boost::mpl::fold<
regions,mpl::set0<>,
set_insert_range<
::boost::mpl::placeholders::_1,
::boost::mpl::placeholders::_2 >
>::type one_big_states_set;
enum {states_in_regions_raw = number_of_states_in_regions::value};
enum {cumulated_states_in_regions_raw = ::boost::mpl::size<one_big_states_set>::value};
};
template <class Fsm>
struct check_no_unreachable_state
{
typedef typename check_regions_orthogonality<Fsm>::one_big_states_set states_in_regions;
typedef typename set_insert_range<
states_in_regions,
typename ::boost::mpl::eval_if<
typename has_explicit_creation<Fsm>::type,
get_explicit_creation<Fsm>,
::boost::mpl::vector0<>
>::type
>::type with_explicit_creation;
enum {states_in_fsm = ::boost::mpl::size< typename Fsm::substate_list >::value};
enum {cumulated_states_in_regions = ::boost::mpl::size< with_explicit_creation >::value};
};
// helper to find out if a SM has an active exit state and is therefore waiting for exiting
template <class StateType,class OwnerFct,class FSM>
inline
typename ::boost::enable_if<typename ::boost::mpl::and_<typename is_composite_state<FSM>::type,
typename is_pseudo_exit<StateType>::type>,bool >::type
is_exit_state_active(FSM& fsm)
{
typedef typename OwnerFct::type Composite;
//typedef typename create_stt<Composite>::type stt;
typedef typename Composite::stt stt;
int state_id = get_state_id<stt,StateType>::type::value;
Composite& comp = fsm.template get_state<Composite&>();
return (std::find(comp.current_state(),comp.current_state()+Composite::nr_regions::value,state_id)
!=comp.current_state()+Composite::nr_regions::value);
}
template <class StateType,class OwnerFct,class FSM>
inline
typename ::boost::disable_if<typename ::boost::mpl::and_<typename is_composite_state<FSM>::type,
typename is_pseudo_exit<StateType>::type>,bool >::type
is_exit_state_active(FSM&)
{
return false;
}
// transformation metafunction to end interrupt flags
template <class Event>
struct transform_to_end_interrupt
{
typedef boost::msm::EndInterruptFlag<Event> type;
};
// transform a sequence of events into another one of EndInterruptFlag<Event>
template <class Events>
struct apply_end_interrupt_flag
{
typedef typename
::boost::mpl::transform<
Events,transform_to_end_interrupt< ::boost::mpl::placeholders::_1> >::type type;
};
// returns a mpl vector containing all end interrupt events if sequence, otherwise the same event
template <class Event>
struct get_interrupt_events
{
typedef typename ::boost::mpl::eval_if<
::boost::mpl::is_sequence<Event>,
apply_end_interrupt_flag<Event>,
boost::mpl::vector1<boost::msm::EndInterruptFlag<Event> > >::type type;
};
template <class Events>
struct build_interrupt_state_flag_list
{
typedef ::boost::mpl::vector<boost::msm::InterruptedFlag> first_part;
typedef typename ::boost::mpl::insert_range<
first_part,
typename ::boost::mpl::end< first_part >::type,
Events
>::type type;
};
}}} // boost::msm::backmp11
#endif // BOOST_MSM_BACKMP11_METAFUNCTIONS_H

File diff suppressed because it is too large Load Diff

View File

@@ -20,6 +20,12 @@ struct wrap{};
// tag to use in grammars where states are seen (init_<<, states_<<...)
struct state_tag{};
// helper to print types within metafunctions
// TODO:
// Remove again
template <typename... Ts>
struct [[deprecated]] print_types {};
} } // boost::msm
#endif //BOOST_MSM_COMMON_H

View File

@@ -36,7 +36,6 @@
#include <boost/mpl/filter_view.hpp>
#include <boost/mpl/transform_view.hpp>
#include <boost/mpl/equal.hpp>
#include <boost/type_traits.hpp>
namespace boost {

View File

@@ -181,3 +181,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<my_machine_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -105,3 +105,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(anonymous_and_guard_test2, MyStateMachine, MyState
BOOST_CHECK_MESSAGE(sm.current_state()[0] == 0, "Running should be active");
BOOST_CHECK_MESSAGE(sm.current_state()[1] == 3, "Completed should be active");
}
using backmp11_fsm = boost::msm::backmp11::state_machine<Bug, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -164,3 +164,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<my_machine_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -11,15 +11,28 @@
// back-end
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/back/favor_compile_time.hpp>
#include <boost/msm/backmp11/state_machine.hpp>
#include <boost/msm/backmp11/favor_compile_time.hpp>
#include <boost/msm/back11/state_machine.hpp>
template<typename Front>
using get_test_machines = boost::mpl::vector<
boost::msm::back::state_machine<Front>,
boost::msm::back::state_machine<Front, boost::msm::back::favor_compile_time>,
boost::msm::backmp11::state_machine<Front>,
boost::msm::backmp11::state_machine<Front, boost::msm::backmp11::favor_compile_time>,
boost::msm::back11::state_machine<Front>
>;
template <template <template <typename...> class, typename = void> class hierarchical>
using get_hierarchical_test_machines = boost::mpl::vector<
hierarchical<boost::msm::back::state_machine>,
hierarchical<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical<boost::msm::backmp11::state_machine>,
hierarchical<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>,
hierarchical<boost::msm::back11::state_machine>
>;
#define BOOST_MSM_TEST_DEFINE_DEPENDENT_TEMPLATES(frontname) \
using base = msm::front::state_machine_def<frontname>; \
template<typename T1, class Event, typename T2> \
@@ -43,11 +56,3 @@ using get_test_machines = boost::mpl::vector<
typename T2, \
bool (frontname::*guard)(Event const&) \
> using g_row = typename base::template g_row<T1, Event, T2, guard>;
// template<typename State, typename Fsm>
// State& get_state(Fsm&& fsm)
// {
// return fsm.template get_state<State&>();
// }

View File

@@ -263,3 +263,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<my_machine_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -1,18 +1,12 @@
file(GLOB SOURCES "*.cpp")
# TODO:
# Fully install boost to test Serialize
list(FILTER SOURCES EXCLUDE REGEX "Serialize|BigWithFunctors")
# list(FILTER SOURCES INCLUDE REGEX "Anonymous")
# list(FILTER SOURCES EXCLUDE REGEX "xyz")
# list(FILTER SOURCES INCLUDE REGEX "xyz")
add_executable(msm_test
${SOURCES}
# Anonymous.cpp
# AnonymousEuml.cpp
# AnonymousAndGuard.cpp
# BigWithFunctors.cpp
# CompositeMachine.cpp
# Entries.cpp
main.cpp
)
target_include_directories(msm_test PRIVATE ../include)
find_package(boost_serialization)
target_link_libraries(msm_test Boost::serialization)
target_compile_definitions(msm_test PRIVATE "BOOST_MSM_NONSTANDALONE_TEST")

View File

@@ -150,11 +150,7 @@ namespace
typedef Back<player_, Policy> player;
};
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical_state_machine<boost::msm::back11::state_machine>
> test_machines;
typedef get_hierarchical_test_machines<hierarchical_state_machine> test_machines;
// static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
@@ -295,3 +291,8 @@ using back0 = hierarchical_state_machine<boost::msm::back::state_machine, boost:
using back1 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::Playing_type;
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back0);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
using backmp11_0 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_0);
using backmp11_1 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::Playing_type;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_1);

View File

@@ -245,11 +245,7 @@ namespace
typedef Back<player_, Policy> player;
};
// Pick a back-end
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical_state_machine<boost::msm::back11::state_machine>
> test_machines;
typedef get_hierarchical_test_machines<hierarchical_state_machine> test_machines;
// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
@@ -359,3 +355,8 @@ using back0 = hierarchical_state_machine<boost::msm::back::state_machine, boost:
using back1 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::player_::Playing;
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back0);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
using backmp11_0 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_0);
using backmp11_1 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player_::Playing;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_1);

View File

@@ -207,3 +207,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -226,11 +226,8 @@ namespace
};
typedef Back<Fsm_, Policy> Fsm;
};
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical_state_machine<boost::msm::back11::state_machine>
> test_machines;
typedef get_hierarchical_test_machines<hierarchical_state_machine> test_machines;
// static char const* const state_names[] = { "State1", "SubFsm2","State2" };
@@ -311,3 +308,8 @@ using back0 = hierarchical_state_machine<boost::msm::back::state_machine, boost:
using back1 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::Fsm_::SubFsm2;
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back0);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
using backmp11_0 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::Fsm;
using backmp11_1 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::Fsm_::SubFsm2;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_0);
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_1);

View File

@@ -357,3 +357,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -246,12 +246,7 @@ namespace
typedef Back<player_, Policy> player;
};
// Pick a back-end
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical_state_machine<boost::msm::back11::state_machine>
> test_machines;
typedef get_hierarchical_test_machines<hierarchical_state_machine> test_machines;
// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
@@ -370,4 +365,9 @@ namespace
using back0 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::player;
using back1 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::player_::Playing;
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back0);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
using backmp11_0 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_0);
using backmp11_1 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player_::Playing;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_1);

View File

@@ -103,3 +103,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<Sm1_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -136,3 +136,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -316,11 +316,7 @@ namespace
typedef Back<player_, Policy> player;
};
// Pick a back-end
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical_state_machine<boost::msm::back11::state_machine>
> test_machines;
typedef get_hierarchical_test_machines<hierarchical_state_machine> test_machines;
//static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
@@ -503,4 +499,9 @@ namespace
using back0 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::player;
using back1 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::player_::Playing;
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back0);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
using backmp11_0 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_0);
using backmp11_1 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player_::Playing;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_1);

View File

@@ -323,11 +323,7 @@ namespace
typedef Back<player_, Policy> player;
};
// Pick a back-end
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical_state_machine<boost::msm::back11::state_machine>
> test_machines;
typedef get_hierarchical_test_machines<hierarchical_state_machine> test_machines;
//static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
@@ -510,4 +506,9 @@ namespace
using back0 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::player;
using back1 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::player_::Playing;
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back0);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
using backmp11_0 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_0);
using backmp11_1 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player_::Playing;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_1);

View File

@@ -343,6 +343,7 @@ namespace
// Pick a back-end
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::backmp11::state_machine>,
hierarchical_state_machine<boost::msm::back11::state_machine>
> test_machines;

View File

@@ -155,7 +155,9 @@ namespace
// Pick a back-end
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical_state_machine<boost::msm::backmp11::state_machine>,
hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>
// TODO:
// Investigate reason for test failure in back11.
// hierarchical_state_machine<boost::msm::back11::state_machine>
@@ -374,4 +376,9 @@ namespace
using back0 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::player;
using back1 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::Playing_type;
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back0);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
using backmp11_0 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_0);
using backmp11_1 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::Playing_type;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_1);

View File

@@ -185,9 +185,9 @@ namespace boost::msm::front::puml {
struct Action<by_name("resume_playback2")>
{
template <class EVT, class FSM, class SourceState, class TargetState>
void operator()(EVT& e, FSM&, SourceState&, TargetState&)
void operator()(EVT const& e, FSM&, SourceState&, TargetState&)
{
++e.cpt_;
++(*const_cast<EVT*>(&e)).cpt_;
}
};
template<>
@@ -229,9 +229,9 @@ namespace boost::msm::front::puml {
struct Action<by_name("TestFct")>
{
template <class EVT, class FSM, class SourceState, class TargetState>
void operator()(EVT& e, FSM& fsm, SourceState&, TargetState&)
void operator()(EVT const& e, FSM& fsm, SourceState&, TargetState&)
{
++e.cpt_;
++(*const_cast<EVT*>(&e)).cpt_;
++fsm.test_fct_counter;
}
};

View File

@@ -308,3 +308,5 @@ namespace
// this is to get rid of warning because p is not const
// BOOST_CLASS_TRACKING(player, boost::serialization::track_never)
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -213,3 +213,6 @@ namespace
// at the risk of a programming error creating duplicate objects.
// this is to get rid of warning because p is not const
// BOOST_CLASS_TRACKING(player, boost::serialization::track_never)
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -252,11 +252,7 @@ namespace
typedef Back<player_, Policy> player;
};
// Pick a back-end
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical_state_machine<boost::msm::back11::state_machine>
> test_machines;
typedef get_hierarchical_test_machines<hierarchical_state_machine> test_machines;
// static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
@@ -381,4 +377,9 @@ namespace
using back0 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::player;
using back1 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::player_::Playing;
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back0);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
using backmp11_0 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_0);
using backmp11_1 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::player_::Playing;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_1);

View File

@@ -134,11 +134,7 @@ namespace
typedef Back<Fsm_, Policy> Fsm;
};
// typedef msm::back11::state_machine<Fsm_> Fsm;
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical_state_machine<boost::msm::back11::state_machine>
> test_machines;
typedef get_hierarchical_test_machines<hierarchical_state_machine> test_machines;
BOOST_AUTO_TEST_CASE_TEMPLATE(set_states_test, test_machine, test_machines)
@@ -165,4 +161,9 @@ namespace
using back0 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::Fsm;
using back1 = hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>::SubFsm;
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back0);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(back1);
using backmp11_0 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::Fsm;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_0);
using backmp11_1 = hierarchical_state_machine<boost::msm::backmp11::state_machine, boost::msm::backmp11::favor_compile_time>::SubFsm;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_1);

View File

@@ -194,3 +194,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -194,3 +194,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -273,3 +273,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -252,3 +252,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -329,3 +329,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -14,7 +14,7 @@
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/puml/puml.hpp>
#include <PumlCommon.hpp>
#include "PumlCommon.hpp"
#ifndef BOOST_MSM_NONSTANDALONE_TEST
#define BOOST_TEST_MODULE simple_internal_with_puml
@@ -154,3 +154,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -254,3 +254,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -129,9 +129,9 @@ namespace
struct TestFct
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT& e, FSM& fsm,SourceState& ,TargetState& )
void operator()(EVT const& e, FSM& fsm,SourceState& ,TargetState& )
{
++e.cpt_;
++(*const_cast<EVT*>(&e)).cpt_;
++fsm.test_fct_counter;
}
};
@@ -182,9 +182,9 @@ namespace
struct resume_playback
{
template <class EVT,class FSM,class SourceState,class TargetState>
void operator()(EVT& e,FSM& ,SourceState& ,TargetState& )
void operator()(EVT const& e,FSM& ,SourceState& ,TargetState& )
{
++e.cpt_;
++(*const_cast<EVT*>(&e)).cpt_;
}
};
struct stop_and_open
@@ -363,3 +363,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -14,7 +14,7 @@
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/puml/puml.hpp>
#include <PumlCommon.hpp>
#include "PumlCommon.hpp"
#ifndef BOOST_MSM_NONSTANDALONE_TEST
#define BOOST_TEST_MODULE simple_with_puml_test
@@ -134,3 +134,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -14,7 +14,7 @@
//front-end
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/puml/puml.hpp>
#include <PumlCommon.hpp>
#include "PumlCommon.hpp"
#ifndef BOOST_MSM_NONSTANDALONE_TEST
#define BOOST_TEST_MODULE string_terminate_puml_test
@@ -92,3 +92,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<front_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -171,4 +171,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<my_machine_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -248,12 +248,7 @@ namespace
typedef Back<player_, Policy> player;
};
// Pick a back-end
// typedef msm::back::state_machine<player_> player;
typedef boost::mpl::vector<
hierarchical_state_machine<boost::msm::back::state_machine>,
hierarchical_state_machine<boost::msm::back::state_machine, boost::msm::back::favor_compile_time>,
hierarchical_state_machine<boost::msm::back11::state_machine>
> test_machines;
typedef get_hierarchical_test_machines<hierarchical_state_machine> test_machines;
BOOST_AUTO_TEST_CASE_TEMPLATE( test_constructor, test_machine, test_machines )

View File

@@ -115,3 +115,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<bistable_switch_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -193,4 +193,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -154,4 +154,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -157,4 +157,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -167,4 +167,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<player_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -137,4 +137,5 @@ namespace
}
}
using backmp11_fsm = boost::msm::backmp11::state_machine<MyMachineFrontend, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

View File

@@ -149,3 +149,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(transition_skipping_test, top, tops)
BOOST_CHECK_MESSAGE(msm.current_state()[0] == 2, "other2 should be active"); //Open
}
using backmp11_fsm = boost::msm::backmp11::state_machine<top_, boost::msm::backmp11::favor_compile_time>;
BOOST_MSM_BACKMP11_GENERATE_DISPATCH_TABLE(backmp11_fsm);

2
test/main.cpp Normal file
View File

@@ -0,0 +1,2 @@
#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>