diff --git a/doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc b/doc/modules/ROOT/pages/tutorial/backmp11-back-end.adoc index 04bc26b1..00cca454 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 d5832e1e..62629079 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 000aea35..98a601a1 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) + template + class deferred_event_impl : public deferred_event { - bool result = false; - auto visitor = [&result](auto& state) + public: + deferred_event_impl(StateMachine& sm, const Event& event, size_t seq_cnt) + : deferred_event(seq_cnt), m_sm(sm), m_event(event) { - using State = std::decay_t; - result |= has_state_deferred_event::value; - }; - sm.template visit(visitor); - return result; - } + } + + 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 - static bool is_event_deferred(StateMachine& sm, const Event&) + class is_event_deferred_helper { - return is_event_deferred(sm); + 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 2845637f..7447f6fe 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/detail/state_visitor.hpp b/include/boost/msm/backmp11/detail/state_visitor.hpp index 3dc928cb..e93ed5d6 100644 --- a/include/boost/msm/backmp11/detail/state_visitor.hpp +++ b/include/boost/msm/backmp11/detail/state_visitor.hpp @@ -31,9 +31,12 @@ struct copy_if_impl template typename Predicate> using copy_if = typename copy_if_impl::type; +template typename Predicate> +using state_subset = copy_if; + // State visitor implementation. // States to visit can be selected with VisitMode -// and additionally be compile-time filtered with a predicate. +// and additionally compile-time filtered with Predicate. template < typename StateMachine, typename Visitor, @@ -49,16 +52,19 @@ template < template typename Predicate> class state_visitor< StateMachine, - Visitor, Mode, + Visitor, + Mode, Predicate, - std::enable_if_t> + std::enable_if_t< + has_flag(Mode, visit_mode::active_states) && + mp11::mp_not>>::value>> { - using state_set = typename StateMachine::internal::state_set; - using state_subset = copy_if; - using state_identities = mp11::mp_transform; public: state_visitor() { + using state_identities = + mp11::mp_transform>; mp11::mp_for_each( [this](auto state_identity) { @@ -81,6 +87,7 @@ class state_visitor< } private: + using state_set = typename StateMachine::internal::state_set; using cell_t = void (*)(StateMachine&, Visitor); template @@ -121,16 +128,19 @@ template < template typename Predicate> class state_visitor< StateMachine, - Visitor, Mode, + Visitor, + Mode, Predicate, - std::enable_if_t> + std::enable_if_t< + has_flag(Mode, visit_mode::all_states) && + mp11::mp_not>>::value>> { - using state_set = typename StateMachine::internal::state_set; - using state_subset = copy_if; - using state_identities = mp11::mp_transform; public: static void visit(StateMachine& sm, Visitor visitor) { + using state_identities = + mp11::mp_transform>; mp11::mp_for_each( [&sm, &visitor](auto state_identity) { @@ -148,6 +158,25 @@ class state_visitor< } }; +template < + typename StateMachine, + typename Visitor, + visit_mode Mode, + template typename Predicate> +class state_visitor< + StateMachine, + Visitor, + Mode, + Predicate, + std::enable_if_t< + mp11::mp_empty>::value>> +{ + public: + static constexpr void visit(StateMachine&, Visitor) + { + } +}; + } // boost::msm::backmp11::detail #endif // BOOST_MSM_BACKMP11_DETAIL_STATE_VISITOR_HPP diff --git a/include/boost/msm/backmp11/favor_compile_time.hpp b/include/boost/msm/backmp11/favor_compile_time.hpp index 5fafb948..fdf5bef4 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 d5d55349..65b3cf39 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