From 155b3ef6d66641008ee5ed01cd9ed4ac082e00fe Mon Sep 17 00:00:00 2001 From: Christian Granzin Date: Thu, 18 Dec 2025 19:05:15 -0500 Subject: [PATCH] refactor(backmp11): more efficient defer and enqueue handling --- .../pages/tutorial/backmp11-back-end.adoc | 10 +- include/boost/msm/backmp11/common_types.hpp | 89 ++++++++++++++- .../backmp11/detail/favor_runtime_speed.hpp | 103 +++++++++++------- .../msm/backmp11/detail/metafunctions.hpp | 8 +- .../boost/msm/backmp11/favor_compile_time.hpp | 60 +++++----- include/boost/msm/backmp11/state_machine.hpp | 73 +++++++------ 6 files changed, 233 insertions(+), 110 deletions(-) diff --git a/doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc b/doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc index 04bc26b..00cca45 100644 --- a/doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc +++ b/doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc @@ -21,8 +21,8 @@ It offers a significant reduction in compilation time and RAM usage, as can be s | back | 18 | 953 | 7 | back_favor_compile_time | 21 | 1000 | 8 | back11 | 43 | 2794 | 7 -| backmp11 | 3 | 239 | 3 -| backmp11_favor_compile_time | 3 | 220 | 13 +| backmp11 | 3 | 229 | 3 +| backmp11_favor_compile_time | 3 | 220 | 8 | sml | 12 | 363 | 3 |======================================================================= @@ -34,9 +34,9 @@ It offers a significant reduction in compilation time and RAM usage, as can be s | | Compile / sec | RAM / MB | Runtime / sec | back | 68 | 2849 | 23 | back_favor_compile_time | 80 | 2551 | 261 -| backmp11 | 11 | 472 | 10 -| backmp11_favor_compile_time | 7 | 288 | 40 -| backmp11_favor_compile_time_multi_cu | 5 | ~919 | 40 +| backmp11 | 10 | 438 | 11 +| backmp11_favor_compile_time | 7 | 288 | 26 +| backmp11_favor_compile_time_multi_cu | 5 | ~919 | 26 | sml | 48 | 1128 | 11 |================================================================================ diff --git a/include/boost/msm/backmp11/common_types.hpp b/include/boost/msm/backmp11/common_types.hpp index d5832e1..6262907 100644 --- a/include/boost/msm/backmp11/common_types.hpp +++ b/include/boost/msm/backmp11/common_types.hpp @@ -14,6 +14,7 @@ #include #include +#include namespace boost { namespace msm { namespace backmp11 { @@ -23,8 +24,7 @@ using process_result = back::HandledEnum; using any_event = std::any; // Selector for the visit mode. -// Can be active_states or all_states in recursive -// or non-recursive mode. +// Can be active_states or all_states in recursive or non-recursive mode. enum class visit_mode { // State selection (mutually exclusive). @@ -51,6 +51,39 @@ constexpr visit_mode operator|(visit_mode lhs, visit_mode rhs) namespace detail { +class enqueued_event +{ + public: + virtual ~enqueued_event() = default; + + // Process the event. + virtual process_result process() = 0; +}; + +class deferred_event +{ + public: + virtual ~deferred_event() = default; + + // Process the event. + virtual process_result process() = 0; + + // Report whether the event is currently deferred. + virtual bool is_deferred() const = 0; + + // Get the sequence counter of the event. + size_t get_seq_cnt() const + { + return m_seq_cnt; + } + + protected: + deferred_event(size_t seq_cnt) : m_seq_cnt(seq_cnt) {} + + private: + size_t m_seq_cnt; +}; + using EventSource = back::EventSourceEnum; using back::HandledEnum; @@ -62,7 +95,57 @@ constexpr EventSource operator|(EventSource lhs, EventSource rhs) ); } -} +// Minimal implementation of a unique_ptr. +// Used to keep header dependencies to a minimum +// (from C++20 the memory header includes ostream). +template +class basic_unique_ptr +{ + public: + explicit basic_unique_ptr(T* ptr) : m_ptr(ptr) + { + } + + ~basic_unique_ptr() + { + delete m_ptr; + } + + basic_unique_ptr(const basic_unique_ptr&) = delete; + basic_unique_ptr& operator=(const basic_unique_ptr&) = delete; + + basic_unique_ptr(basic_unique_ptr&& other) : m_ptr(other.m_ptr) + { + other.m_ptr = nullptr; + } + + basic_unique_ptr& operator=(basic_unique_ptr&& other) + { + delete m_ptr; + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + } + + T* get() const + { + return m_ptr; + } + + T& operator*() const + { + return *m_ptr; + } + + T* operator->() const + { + return m_ptr; + } + + private: + T* m_ptr; +}; + +} // namespace detail }}} // namespace boost::msm::backmp11 diff --git a/include/boost/msm/backmp11/detail/favor_runtime_speed.hpp b/include/boost/msm/backmp11/detail/favor_runtime_speed.hpp index 000aea3..98a601a 100644 --- a/include/boost/msm/backmp11/detail/favor_runtime_speed.hpp +++ b/include/boost/msm/backmp11/detail/favor_runtime_speed.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_FAVOR_RUNTIME_SPEED_H -#define BOOST_MSM_BACKMP11_FAVOR_RUNTIME_SPEED_H +#ifndef BOOST_MSM_BACKMP11_DETAIL_FAVOR_RUNTIME_SPEED_H +#define BOOST_MSM_BACKMP11_DETAIL_FAVOR_RUNTIME_SPEED_H #include #include @@ -62,22 +62,65 @@ struct compile_policy_impl return sm.process_event_internal_impl(event, source); } - template - static bool is_event_deferred(StateMachine& sm) - { - bool result = false; - auto visitor = [&result](auto& state) - { - using State = std::decay_t; - result |= has_state_deferred_event::value; - }; - sm.template visit(visitor); - return result; - } template - static bool is_event_deferred(StateMachine& sm, const Event&) + class deferred_event_impl : public deferred_event { - return is_event_deferred(sm); + public: + deferred_event_impl(StateMachine& sm, const Event& event, size_t seq_cnt) + : deferred_event(seq_cnt), m_sm(sm), m_event(event) + { + } + + process_result process() override + { + return process_event_internal( + m_sm, + m_event, + EventSource::EVENT_SOURCE_DEFERRED); + } + + bool is_deferred() const override + { + return is_event_deferred(m_sm, m_event); + } + + private: + StateMachine& m_sm; + Event m_event; + }; + + template + using has_deferred_event = mp11::mp_contains< + to_mp_list_t, + Event + >; + + template + class is_event_deferred_helper + { + public: + static bool execute(const StateMachine& sm) + { + bool result = false; + auto visitor = [&result](const auto& /*state*/) + { + result = true; + }; + sm.template visit_if(visitor); + return result; + } + + private: + template + using defers_event = has_deferred_event; + }; + + template + static bool is_event_deferred(const StateMachine& sm, const Event&) + { + using helper = is_event_deferred_helper; + return helper::execute(sm); } template @@ -117,22 +160,9 @@ struct compile_policy_impl static void do_defer_event(StateMachine& sm, const Event& event) { auto& deferred_events = sm.get_deferred_events(); - deferred_events.queue.push_back( - { - [&sm, event]() - { - return process_event_internal( - sm, - event, - EventSource::EVENT_SOURCE_DEFERRED); - }, - [&sm]() - { - return is_event_deferred(sm); - }, - deferred_events.cur_seq_cnt - } - ); + deferred_events.queue.push_back(basic_unique_ptr{ + new deferred_event_impl( + sm, event, deferred_events.cur_seq_cnt)}); } struct cell_initializer @@ -147,13 +177,6 @@ struct compile_policy_impl } }; - // returns a mp11::mp_bool if State has Event as deferred event - template - using has_state_deferred_event = mp11::mp_contains< - to_mp_list_t, - Event - >; - template struct table_index { @@ -483,4 +506,4 @@ struct compile_policy_impl }}} // boost::msm::backmp11 -#endif //BOOST_MSM_BACKMP11_FAVOR_RUNTIME_SPEED_H +#endif // BOOST_MSM_BACKMP11_DETAIL_FAVOR_RUNTIME_SPEED_H diff --git a/include/boost/msm/backmp11/detail/metafunctions.hpp b/include/boost/msm/backmp11/detail/metafunctions.hpp index 2845637..7447f6f 100644 --- a/include/boost/msm/backmp11/detail/metafunctions.hpp +++ b/include/boost/msm/backmp11/detail/metafunctions.hpp @@ -202,10 +202,16 @@ struct get_event_id }; template -using has_state_deferred_events = mp11::mp_not< +using has_deferred_events = mp11::mp_not< mp11::mp_empty> >; +template +using has_deferred_event = mp11::mp_contains< + to_mp_list_t, + Event + >; + // Template used to create dummy entries for initial states not found in the stt. template< typename T1 > struct not_a_row diff --git a/include/boost/msm/backmp11/favor_compile_time.hpp b/include/boost/msm/backmp11/favor_compile_time.hpp index 5fafb94..fdf5bef 100644 --- a/include/boost/msm/backmp11/favor_compile_time.hpp +++ b/include/boost/msm/backmp11/favor_compile_time.hpp @@ -73,6 +73,33 @@ struct compile_policy_impl return sm.process_event_internal_impl(event, source); } + template + class deferred_event_impl : public deferred_event + { + public: + deferred_event_impl(StateMachine& sm, const any_event& event, size_t seq_cnt) + : deferred_event(seq_cnt), m_sm(sm), m_event(event) + { + } + + process_result process() override + { + return process_event_internal( + m_sm, + m_event, + EventSource::EVENT_SOURCE_DEFERRED); + } + + bool is_deferred() const override + { + return is_event_deferred(m_sm, m_event); + } + + private: + StateMachine& m_sm; + any_event m_event; + }; + template static const std::unordered_set& get_deferred_event_type_indices() { @@ -94,43 +121,26 @@ struct compile_policy_impl } template - static bool is_event_deferred(StateMachine& sm, std::type_index type_index) + static bool is_event_deferred(const StateMachine& sm, const any_event& event) { + const std::type_index type_index = event.type(); bool result = false; - auto visitor = [&result, &type_index](auto& state) { + auto visitor = [&result, type_index](auto& state) { using State = std::decay_t; - auto& set = get_deferred_event_type_indices(); + const auto& set = get_deferred_event_type_indices(); result |= (set.find(type_index) != set.end()); }; - sm.template visit(visitor); + sm.template visit_if(visitor); return result; } - template - static bool is_event_deferred(StateMachine& sm, const any_event& event) - { - return is_event_deferred(sm, event.type()); - } template static void defer_event(StateMachine& sm, any_event const& event) { auto& deferred_events = sm.get_deferred_events(); - deferred_events.queue.push_back( - { - [&sm, event]() - { - return process_event_internal( - sm, - event, - EventSource::EVENT_SOURCE_DEFERRED); - }, - [&sm, type_index = std::type_index{event.type()}]() - { - return is_event_deferred(sm, type_index); - }, - deferred_events.cur_seq_cnt - } - ); + deferred_events.queue.push_back(basic_unique_ptr{ + new deferred_event_impl(sm, event, deferred_events.cur_seq_cnt)}); } template diff --git a/include/boost/msm/backmp11/state_machine.hpp b/include/boost/msm/backmp11/state_machine.hpp index d5d5534..65b3cf3 100644 --- a/include/boost/msm/backmp11/state_machine.hpp +++ b/include/boost/msm/backmp11/state_machine.hpp @@ -38,10 +38,10 @@ #include #include -#include #include #include #include +#include #include namespace boost { namespace msm { namespace backmp11 @@ -74,7 +74,7 @@ class state_machine_base : public FrontEnd using front_end_t = FrontEnd; using derived_t = Derived; using events_queue_t = typename config_t::template - queue_container>; + queue_container>; // Event that describes the SM is starting. // Used when the front-end does not define an initial_event. @@ -578,17 +578,7 @@ class state_machine_base : public FrontEnd // define the dispatch table used for event dispatch using sm_dispatch_table = typename compile_policy_impl::template dispatch_table; - struct deferred_event_t - { - std::function process_event; - std::function is_event_deferred; - // Deferred events are added with a correlation sequence that helps to - // identify when an event was added. - // Newly deferred events will not be considered for procesing - // within the same sequence. - size_t seq_cnt; - }; - using deferred_events_queue_t = std::list; + using deferred_events_queue_t = std::list>; struct deferred_events_t { @@ -596,7 +586,7 @@ class state_machine_base : public FrontEnd size_t cur_seq_cnt; }; using has_any_deferred_event = - mp11::mp_any_of; + mp11::mp_any_of; using deferred_events_member = optional_instance(); } - template - bool is_event_deferred(const Event& event) const - { - return compile_policy_impl::is_event_deferred(*this, event); - } - // Visit states with a compile-time filter (reduces template instantiations). template