refactor(backmp11): various topics

This commit is contained in:
Christian Granzin
2026-02-23 14:21:29 -05:00
committed by Christian Granzin
parent 428cbad053
commit 79067cf6e0
14 changed files with 1272 additions and 1461 deletions
@@ -15,7 +15,7 @@ It offers a significant improvement in runtime and memory usage, as can be seen
| back | 14 | 815 | 68 | 2.8
| back_favor_compile_time | 17 | 775 | 226 | 3.5
| back11 | 37 | 2682 | 84 | 2.8
| backmp11 | 3 | 211 | 29 | 0.7
| backmp11 | 3 | 209 | 29 | 0.7
| backmp11_favor_compile_time | 3 | 195 | 43 | 6.0
| sml | 5 | 234 | 57 | 0.3
|=======================================================================================================
@@ -28,9 +28,9 @@ It offers a significant improvement in runtime and memory usage, as can be seen
| | Compile time / sec | Compile RAM / MB | Binary size / kB | Runtime / sec
| back | 49 | 2165 | 230 | 13.2
| back_favor_compile_time | 55 | 1704 | 911 | > 300
| backmp11 | 8 | 354 | 85 | 3.4
| backmp11_favor_compile_time | 5 | 262 | 100 | 20.4
| backmp11_favor_compile_time_multi_cu | 5 | ~863 | 100 | 20.8
| backmp11 | 8 | 348 | 83 | 3.4
| backmp11_favor_compile_time | 5 | 261 | 97 | 20.6
| backmp11_favor_compile_time_multi_cu | 4 | ~863 | 97 | 21.4
| sml | 18 | 543 | 422 | 5.4
|================================================================================================================
+7 -7
View File
@@ -9,8 +9,8 @@
// 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
#ifndef BOOST_MSM_BACKMP11_COMMON_TYPES_HPP
#define BOOST_MSM_BACKMP11_COMMON_TYPES_HPP
#include <any>
#include <cstdint>
@@ -111,11 +111,11 @@ static constexpr process_result handled_true_or_deferred =
// Event occurrences are placed in an event pool for later processing.
class event_occurrence
{
using process_fnc_t = std::optional<process_result> (*)(
using process_fn_t = std::optional<process_result> (*)(
event_occurrence&, void* /*sm*/, uint16_t /*seq_cnt*/);
public:
event_occurrence(process_fnc_t process_fnc) : m_process_fnc(process_fnc)
event_occurrence(process_fn_t process_fn) : m_process_fn(process_fn)
{
}
@@ -125,7 +125,7 @@ class event_occurrence
template <typename StateMachine>
std::optional<process_result> try_process(StateMachine& sm, uint16_t seq_cnt)
{
return m_process_fnc(*this, static_cast<void*>(&sm), seq_cnt);
return m_process_fn(*this, static_cast<void*>(&sm), seq_cnt);
}
void mark_for_deletion()
@@ -139,7 +139,7 @@ class event_occurrence
}
private:
process_fnc_t m_process_fnc{};
process_fn_t m_process_fn{};
// Flag set when this event has been processed and can be erased.
// Deletion is deferred to allow the use of std::deque,
// which provides better cache locality and lower per-element overhead.
@@ -188,4 +188,4 @@ struct compile_policy_impl;
} // namespace detail
} // namespace boost::msm::backmp11
#endif // BOOST_MSM_BACKMP11_COMMON_TYPES_H
#endif // BOOST_MSM_BACKMP11_COMMON_TYPES_HPP
@@ -1,61 +0,0 @@
// 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 <cstddef>
#include <boost/mp11.hpp>
#include <boost/msm/backmp11/common_types.hpp>
namespace boost { namespace msm { namespace backmp11
{
namespace detail
{
// Value used to initialize a cell of the dispatch table
template<typename Cell>
struct init_cell_value
{
size_t index;
Cell cell;
};
template<size_t index, typename Cell, Cell cell>
struct init_cell_constant
{
using value_type = init_cell_value<Cell>;
static constexpr value_type value = {index, cell};
};
// Type-punned init cell value to suppress redundant template instantiations.
using generic_cell = void(*)();
using generic_init_cell_value = init_cell_value<generic_cell>;
// Class that handles the initialization of dispatch table entries.
struct dispatch_table_initializer
{
static void execute(generic_cell* cells, const generic_init_cell_value* values, size_t values_size)
{
for (size_t i = 0; i < values_size; i++)
{
const auto& item = values[i];
cells[item.index] = item.cell;
}
}
};
} // detail
}}} // boost::msm::backmp11
#endif //BOOST_MSM_BACKMP11_DISPATCH_TABLE_H
@@ -9,16 +9,15 @@
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MSM_BACKMP11_DETAIL_FAVOR_RUNTIME_SPEED_H
#define BOOST_MSM_BACKMP11_DETAIL_FAVOR_RUNTIME_SPEED_H
#ifndef BOOST_MSM_BACKMP11_DETAIL_FAVOR_RUNTIME_SPEED_HPP
#define BOOST_MSM_BACKMP11_DETAIL_FAVOR_RUNTIME_SPEED_HPP
#include <boost/msm/backmp11/detail/metafunctions.hpp>
#include <boost/msm/backmp11/detail/dispatch_table.hpp>
#include <boost/msm/backmp11/detail/state_visitor.hpp>
#include <boost/msm/backmp11/detail/transition_table.hpp>
#include <boost/msm/backmp11/event_traits.hpp>
namespace boost { namespace msm { namespace backmp11
namespace boost::msm::backmp11
{
struct favor_runtime_speed
@@ -172,8 +171,6 @@ struct compile_policy_impl<
}
private:
using cell_t = process_result (*)(StateMachine&, int /*region_id*/, Event const&);
// All dispatch tables are friend with each other to check recursively
// whether forward transitions are required.
template <class, typename>
@@ -360,78 +357,39 @@ struct compile_policy_impl<
{
using base = dispatch_base;
public:
template <typename... Ts>
struct mp_indexed_dispatch_impl
{
using list = mp11::mp_list<Ts...>;
static constexpr std::size_t size = sizeof...(Ts);
template <typename F>
static constexpr process_result invoke(int state_id, F&& func)
{
return dispatch(state_id, func,
std::make_index_sequence<size>{});
}
private:
// For position I in the list, get the corresponding state_id
// at compile time.
template <std::size_t I>
static constexpr int state_id_at =
StateMachine::template get_state_id<
typename mp11::mp_at_c<list, I>::current_state_type>();
// Single case handler: invoke func with the I-th transition
template <std::size_t I, typename F>
static constexpr process_result handle_case(F& func)
{
return func(mp11::mp_at_c<list, I>{});
}
// Generate branches comparing state_id against compile-time
// state_id_at<I> for each position I in the list.
template <typename F, std::size_t... Is>
static constexpr process_result dispatch(int state_id, F& func,
std::index_sequence<Is...>)
{
process_result result = process_result::HANDLED_FALSE;
// Each branch compares the runtime state_id against the
// compile-time state_id of the I-th transition.
// State IDs may be non-contiguous (e.g., 0, 2, 5).
(void)((state_id == state_id_at<Is> &&
(result = handle_case<Is>(func), true)) || ...);
return result;
}
};
template <typename L, typename F>
static constexpr process_result mp_indexed_dispatch(int state_id, F&& func)
{
return mp11::mp_apply<mp_indexed_dispatch_impl, L>::invoke(
state_id, std::forward<F>(func));
}
static inline process_result dispatch(StateMachine& sm, int region_id,
const Event& event)
{
const int state_id = sm.m_active_state_ids[region_id];
return mp_indexed_dispatch<typename base::merged_transitions>(state_id,
[&sm, region_id, &event](auto transition) -> process_result
process_result result = process_result::HANDLED_FALSE;
mp11::mp_for_each<typename base::merged_transitions>(
[&sm, region_id, &event, state_id, &result](auto transition)
{
using Transition = decltype(transition);
using TransitionEvent =
typename Transition::transition_event;
if constexpr (!is_kleene_event<TransitionEvent>::value)
using SourceState =
typename Transition::current_state_type;
constexpr int source_state_id =
StateMachine::template get_state_id<SourceState>();
if (state_id == source_state_id)
{
return Transition::execute(sm, region_id, event);
if constexpr (!is_kleene_event<
TransitionEvent>::value)
{
result =
Transition::execute(sm, region_id, event);
}
else
{
result =
base::template convert_event_and_execute<
Transition>(sm, region_id, event);
}
}
else
{
return base::template
convert_event_and_execute<Transition>(
sm, region_id, event);
}
});
}
);
return result;
}
};
@@ -440,6 +398,9 @@ struct compile_policy_impl<
: public dispatch_base
{
using base = dispatch_base;
using cell_t = process_result (*)(StateMachine&, int /*region_id*/,
Event const&);
public:
static process_result dispatch(
StateMachine& sm, int region_id, const Event& event)
@@ -557,7 +518,7 @@ struct compile_policy_impl<
};
} // detail
}}} // boost::msm::backmp11
} // boost::msm::backmp11
#endif // BOOST_MSM_BACKMP11_DETAIL_FAVOR_RUNTIME_SPEED_H
#endif // BOOST_MSM_BACKMP11_DETAIL_FAVOR_RUNTIME_SPEED_HPP
@@ -9,18 +9,14 @@
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MSM_BACKMP11_HISTORY_IMPL_H
#define BOOST_MSM_BACKMP11_HISTORY_IMPL_H
#ifndef BOOST_MSM_BACKMP11_DETAIL_HISTORY_IMPL_HPP
#define BOOST_MSM_BACKMP11_DETAIL_HISTORY_IMPL_HPP
#include <boost/msm/front/history_policies.hpp>
#include <boost/mp11.hpp>
namespace boost::msm::backmp11
namespace boost::msm::backmp11::detail
{
namespace detail
{
// Implementations for history policies.
template<typename History, int NumberOfRegions>
class history_impl;
@@ -138,8 +134,6 @@ public:
std::array<int, NumberOfRegions> m_last_active_state_ids;
};
} // detail
} // boost::msm::backmp11
#endif // BOOST_MSM_BACKMP11_HISTORY_IMPL_H
#endif // BOOST_MSM_BACKMP11_DETAIL_HISTORY_IMPL_HPP
@@ -9,8 +9,8 @@
// 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
#ifndef BOOST_MSM_BACKMP11_DETAIL_METAFUNCTIONS_HPP
#define BOOST_MSM_BACKMP11_DETAIL_METAFUNCTIONS_HPP
#include <boost/mp11.hpp>
#include <boost/mp11/mpl_list.hpp>
@@ -36,10 +36,7 @@ namespace boost::mpl
struct is_sequence;
}
namespace boost { namespace msm { namespace backmp11
{
namespace detail
namespace boost::msm::backmp11::detail
{
// Call a functor on all elements of List, until the functor returns true.
@@ -336,8 +333,6 @@ struct is_state_blocking_impl
template<typename T>
using is_state_blocking = typename is_state_blocking_impl<T>::type;
} // detail
} // boost::msm::backmp11::detail
}}} // boost::msm::backmp11
#endif // BOOST_MSM_BACKMP11_METAFUNCTIONS_H
#endif // BOOST_MSM_BACKMP11_DETAIL_METAFUNCTIONS_HPP
File diff suppressed because it is too large Load Diff
@@ -12,7 +12,6 @@
#ifndef BOOST_MSM_BACKMP11_DETAIL_STATE_VISITOR_HPP
#define BOOST_MSM_BACKMP11_DETAIL_STATE_VISITOR_HPP
#include <boost/msm/backmp11/detail/dispatch_table.hpp>
#include <boost/msm/backmp11/detail/metafunctions.hpp>
#include <boost/msm/backmp11/state_machine_config.hpp>
@@ -197,61 +196,27 @@ class state_visitor_impl<
{
if (sm.m_running)
{
const state_visitor_impl& self = instance();
for (const int state_id : sm.m_active_state_ids)
using state_identities = mp11::mp_transform<
mp11::mp_identity,
typename base::states_to_traverse>;
for (const int active_state_id : sm.m_active_state_ids)
{
self.dispatch(sm, state_id, visitor);
mp11::mp_for_each<state_identities>(
[&sm, &visitor, active_state_id](auto state_identity)
{
using State =
typename decltype(state_identity)::type;
constexpr int state_id =
StateMachine::template get_state_id<State>();
if (active_state_id == state_id)
{
base::template accept<Mode, State>(sm, visitor);
}
});
}
}
}
}
// Bug: Clang 17 complains about private member if this method is private.
template <typename State>
static void accept(StateMachine& sm, Visitor& visitor)
{
base::template accept<Mode, State>(sm, visitor);
}
private:
using state_set = typename StateMachine::internal::state_set;
using cell_t = void (*)(StateMachine&, Visitor&);
template <size_t index, cell_t cell>
using init_cell_constant = init_cell_constant<index, cell_t, cell>;
template <typename State>
using get_init_cell_constant = init_cell_constant<
StateMachine::template get_state_id<State>(),
&accept<State>>;
state_visitor_impl()
{
using init_cell_constants = mp11::mp_transform<
get_init_cell_constant,
typename base::states_to_traverse>;
dispatch_table_initializer::execute(
reinterpret_cast<generic_cell*>(m_cells),
reinterpret_cast<const generic_init_cell_value*>(
value_array<init_cell_constants>),
mp11::mp_size<init_cell_constants>::value);
}
void dispatch(StateMachine& sm, int state_id, Visitor& visitor) const
{
const cell_t& cell = m_cells[state_id];
if (cell)
{
(*cell)(sm, visitor);
}
}
static const state_visitor_impl& instance()
{
static const state_visitor_impl instance;
return instance;
}
cell_t m_cells[mp11::mp_size<state_set>::value]{};
};
template <
@@ -325,15 +290,27 @@ class event_deferral_visitor
"The visitor must have at least one state to visit");
if (sm.m_running)
{
const event_deferral_visitor& self = instance();
for (const int state_id : sm.m_active_state_ids)
using state_identities = mp11::mp_transform<
mp11::mp_identity,
typename visit_set::states_to_traverse>;
for (const int active_state_id : sm.m_active_state_ids)
{
self.dispatch(sm, state_id, visitor);
mp11::mp_for_each<state_identities>(
[&sm, &visitor, active_state_id](auto state_identity)
{
using State = typename decltype(state_identity)::type;
constexpr int state_id =
StateMachine::template get_state_id<State>();
if (active_state_id == state_id)
{
accept<State>(sm, visitor);
}
});
}
}
}
// Bug: Clang 17 complains about private member if this method is private.
private:
template <typename State>
static void accept(StateMachine& sm, Visitor& visitor)
{
@@ -353,46 +330,6 @@ class event_deferral_visitor
submachine_visitor::visit(state, visitor);
}
}
private:
using state_set = typename StateMachine::internal::state_set;
using cell_t = void (*)(StateMachine&, Visitor&);
template <size_t index, cell_t cell>
using init_cell_constant = init_cell_constant<index, cell_t, cell>;
template <typename State>
using get_init_cell_constant = init_cell_constant<
StateMachine::template get_state_id<State>(),
&accept<State>>;
event_deferral_visitor()
{
using init_cell_constants = mp11::mp_transform<
get_init_cell_constant,
typename visit_set::states_to_traverse>;
dispatch_table_initializer::execute(
reinterpret_cast<generic_cell*>(m_cells),
reinterpret_cast<const generic_init_cell_value*>(
value_array<init_cell_constants>),
mp11::mp_size<init_cell_constants>::value);
}
void dispatch(StateMachine& sm, int state_id, Visitor& visitor) const
{
const cell_t& cell = m_cells[state_id];
if (cell)
{
(*cell)(sm, visitor);
}
}
static const event_deferral_visitor& instance()
{
static const event_deferral_visitor instance;
return instance;
}
cell_t m_cells[mp11::mp_size<state_set>::value]{};
};
// Predefined visitor functors used in backmp11.
@@ -499,12 +436,7 @@ class init_state_visitor
{
if constexpr (has_exit_pseudostate_be_tag<State>::value)
{
state.set_forward_fct(
[&root_sm = m_root_sm](typename State::event const& event)
{
return root_sm.enqueue_event(event);
}
);
state.template init<RootSm>();
}
if constexpr (has_state_machine_tag<State>::value)
@@ -213,7 +213,7 @@ struct transition_table_impl
if constexpr (has_exit_pseudostate_be_tag<Target>::value)
{
// Execute the second part of the compound transition.
target.forward_event(event);
target.forward_event(sm.m_root_sm, event);
}
}
}
+3 -3
View File
@@ -9,8 +9,8 @@
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MSM_BACKMP11_EVENT_TRAITS_H
#define BOOST_MSM_BACKMP11_EVENT_TRAITS_H
#ifndef BOOST_MSM_BACKMP11_EVENT_TRAITS_HPP
#define BOOST_MSM_BACKMP11_EVENT_TRAITS_HPP
#include <boost/msm/kleene_event.hpp>
#include <any>
@@ -35,4 +35,4 @@ using std::any_cast;
} // boost::msm::backmp11
#endif //BOOST_MSM_EVENT_TRAITS_H
#endif //BOOST_MSM_EVENT_TRAITS_HPP
@@ -9,17 +9,15 @@
// 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
#ifndef BOOST_MSM_BACKMP11_FAVOR_COMPILE_TIME_HPP
#define BOOST_MSM_BACKMP11_FAVOR_COMPILE_TIME_HPP
#include <functional>
#include <typeindex>
#include <unordered_map>
#include <vector>
#include <boost/msm/front/completion_event.hpp>
#include <boost/msm/backmp11/detail/metafunctions.hpp>
#include <boost/msm/backmp11/detail/dispatch_table.hpp>
#include <boost/msm/backmp11/detail/state_visitor.hpp>
#include <boost/msm/backmp11/detail/transition_table.hpp>
#include <boost/msm/backmp11/event_traits.hpp>
@@ -39,7 +37,7 @@
} \
} // boost::msm::backmp11::detail
namespace boost { namespace msm { namespace backmp11
namespace boost:: msm::backmp11
{
struct favor_compile_time
@@ -54,6 +52,9 @@ namespace detail
template <>
struct compile_policy_impl<favor_compile_time>
{
// Type-punned init cell value to suppress redundant template instantiations.
using generic_cell = void(*)();
// GCC cannot recognize the parameter pack in the array's initializer.
#if !defined(__GNUC__) || defined(__clang__)
// Convert a list with integral constants of the same value_type to a value array
@@ -80,11 +81,23 @@ struct compile_policy_impl<favor_compile_time>
return event;
}
template<typename Statemachine>
static bool is_end_interrupt_event(Statemachine& sm, const any_event& event)
template<typename StateMachine>
static bool is_end_interrupt_event(const StateMachine& sm, const any_event& event)
{
static end_interrupt_event_helper helper{sm};
return helper.is_end_interrupt_event(event);
using event_set = generate_event_set<
typename StateMachine::front_end_t::transition_table>;
bool result{false};
mp11::mp_for_each<mp11::mp_transform<mp11::mp_identity, event_set>>(
[&sm, &event, &result](auto event_identity)
{
using Event = typename decltype(event_identity)::type;
using Flag = EndInterruptFlag<Event>;
if (event.type() == typeid(Event))
{
result = sm.template is_flag_active<Flag>();
}
});
return result;
}
// Dispatch table for event deferral checks.
@@ -185,39 +198,6 @@ struct compile_policy_impl<favor_compile_time>
return std::type_index{typeid(Event)};
}
// Helper class to manage end interrupt events.
class end_interrupt_event_helper
{
public:
template<class StateMachine>
end_interrupt_event_helper(const StateMachine& sm)
{
using event_set = generate_event_set<
typename StateMachine::front_end_t::transition_table>;
mp11::mp_for_each<mp11::mp_transform<mp11::mp_identity, event_set>>(
[this, &sm](auto event_identity)
{
using Event = typename decltype(event_identity)::type;
using Flag = EndInterruptFlag<Event>;
m_is_flag_active_functions[to_type_index<Event>()] =
[&sm](){return sm.template is_flag_active<Flag>();};
});
}
bool is_end_interrupt_event(const 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()>>;
map m_is_flag_active_functions;
};
// Class used to build a chain of transitions for a given event and state.
// Allows transition conflicts.
@@ -553,6 +533,6 @@ compile_policy_impl<favor_compile_time>::dispatch_table<StateMachine, any_event>
#endif
} // detail
}}} // boost::msm::backmp11
} // boost::msm::backmp11
#endif //BOOST_MSM_BACKMP11_FAVOR_COMPILE_TIME_H
#endif //BOOST_MSM_BACKMP11_FAVOR_COMPILE_TIME_HPP
File diff suppressed because it is too large Load Diff
@@ -9,8 +9,8 @@
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MSM_BACKMP11_STATE_MACHINE_CONFIG_H
#define BOOST_MSM_BACKMP11_STATE_MACHINE_CONFIG_H
#ifndef BOOST_MSM_BACKMP11_STATE_MACHINE_CONFIG_HPP
#define BOOST_MSM_BACKMP11_STATE_MACHINE_CONFIG_HPP
#include <deque>
@@ -102,4 +102,4 @@ struct function_pointer_array {};
} // namespace boost::msm::backmp11
#endif // BOOST_MSM_BACKMP11_STATE_MACHINE_CONFIG_H
#endif // BOOST_MSM_BACKMP11_STATE_MACHINE_CONFIG_HPP
+2 -1
View File
@@ -9,7 +9,8 @@
"State"
],
"maintainers": [
"Christophe Henry <christophe.j.henry -at- googlemail.com>"
"Christophe Henry <christophe.j.henry -at- googlemail.com>",
"Christian Granzin"
],
"cxxstd": "03"
}