From 0387da02f243c29e7b5e2810b9e556cde0c75a85 Mon Sep 17 00:00:00 2001 From: Julian Meyers Date: Mon, 22 May 2023 18:14:34 -0500 Subject: [PATCH] Adds handling information about events added to the process_queue --- example/defer_and_process.cpp | 9 +++++---- include/boost/sml.hpp | 11 ++++++----- test/ft/actions_process.cpp | 26 +++++++++++++------------- test/ft/actions_process_n_defer.cpp | 12 ++++++------ 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/example/defer_and_process.cpp b/example/defer_and_process.cpp index fe35dd2c..65b54b2f 100644 --- a/example/defer_and_process.cpp +++ b/example/defer_and_process.cpp @@ -25,7 +25,7 @@ struct defer_and_process { return make_transition_table( *"idle"_s + event / defer , "idle"_s + event = "s1"_s - , "s1"_s + event = "s2"_s + , "s1"_s + event / process(e2{}) = "s2"_s , "s2"_s + event / process(e4{}) , "s2"_s + event = X ); @@ -40,12 +40,13 @@ int main() { sm; /// defer_queue policy to enable deferred events using std::queue assert(sm.is("idle"_s)); - sm.process_event(e1{}); + assert(sm.process_event(e1{})); assert(sm.is("idle"_s)); - sm.process_event(e2{}); /// triggers idle -> s1 and s1 -> s2 (via deferred e1) + assert(!sm.process_event(e2{})); /// triggers idle -> s1 and s1 -> s2 (via deferred e1) + /// additionally triggers e2 again which is unhandled so it returns false assert(sm.is("s2"_s)); - sm.process_event(e3{}); /// triggers s2.process(e4) -> X (via processed e4) + assert(sm.process_event(e3{})); /// triggers s2.process(e4) -> X (via processed e4) assert(sm.is(sml::X)); } diff --git a/include/boost/sml.hpp b/include/boost/sml.hpp index ca00ff43..11838947 100644 --- a/include/boost/sml.hpp +++ b/include/boost/sml.hpp @@ -1426,13 +1426,14 @@ struct sm_impl : aux::conditional_t::value, aux: const auto lock = thread_safety_.create_lock(); (void)lock; bool handled = process_internal_events(event, deps, subs); + bool queued_handled = true; do { do { while (process_internal_events(anonymous{}, deps, subs)) { } } while (process_defer_events(deps, subs, handled, aux::type>{}, events_t{})); - } while (process_queued_events(deps, subs, aux::type>{}, events_t{})); - return handled; + } while (process_queued_events(deps, subs, queued_handled, aux::type>{}, events_t{})); + return handled && queued_handled; } constexpr void initialize(const aux::type_list<> &) {} template @@ -1639,7 +1640,7 @@ struct sm_impl : aux::conditional_t::value, aux: return processed_events; } template - constexpr bool process_queued_events(TDeps &, TSubs &, const aux::type &, const aux::type_list &) { + constexpr bool process_queued_events(TDeps &, TSubs &, bool &, const aux::type &, const aux::type_list &) { return false; } template @@ -1654,13 +1655,13 @@ struct sm_impl : aux::conditional_t::value, aux: #endif } template - bool process_queued_events(TDeps &deps, TSubs &subs, const aux::type &, const aux::type_list &) { + bool process_queued_events(TDeps &deps, TSubs &subs, bool &queued_handled, const aux::type &, const aux::type_list &) { using dispatch_table_t = bool (sm_impl::*)(TDeps &, TSubs &, const void *); const static dispatch_table_t dispatch_table[__BOOST_SML_ZERO_SIZE_ARRAY_CREATE(sizeof...(TEvents))] = { &sm_impl::process_event_no_queue...}; bool wasnt_empty = !process_.empty(); while (!process_.empty()) { - (this->*dispatch_table[process_.front().id])(deps, subs, process_.front().data); + queued_handled &= (this->*dispatch_table[process_.front().id])(deps, subs, process_.front().data); process_.pop(); } return wasnt_empty; diff --git a/test/ft/actions_process.cpp b/test/ft/actions_process.cpp index 90f9dd2f..31d9c642 100644 --- a/test/ft/actions_process.cpp +++ b/test/ft/actions_process.cpp @@ -85,26 +85,26 @@ test process_event_from_substate = [] { expect(sm.is(idle)); expect(sm.is)>(s1)); - sm.process_event(e1{}); + expect(sm.process_event(e1{})); expect(sm.is(sml::state)); expect(sm.is)>(s1)); expect(!c_.a_called); - sm.process_event(e1{}); + expect(sm.process_event(e1{})); expect(sm.is(sml::state)); expect(sm.is)>(s2)); expect(!c_.a_called); - sm.process_event(e2{}); // + process(e3{}) + expect(!sm.process_event(e2{})); // + process(e3{}) + process(e2{}) expect(sm.is(sml::state)); expect(sm.is)>(s3)); expect(!c_.a_called); - sm.process_event(e3{}); + expect(sm.process_event(e3{})); expect(sm.is(sml::state)); expect(sm.is)>(sml::X)); - sm.process_event(e4{}); + expect(sm.process_event(e4{})); expect(1 == c_.a_called); }; @@ -148,7 +148,7 @@ test queue_and_internal_process_events = [] { return make_transition_table( * idle + on_entry / process(e1()) , s1 <= idle + event - , s2 <= s1 + , s2 <= s1 / process(e1()) // This process is unhandled, but the state machine still transitions to s2 , s2 + on_entry<_> / process(e2()) , s3 <= s2 + event , X <= s3 @@ -186,7 +186,7 @@ test queue_process_reaction = [] { sml::sm> sm{}; - sm.process_event(e1()); + expect(!sm.process_event(e1())); // e3 was unexpected so it returns false expect(sm.is(sml::X)); const c& c_ = sm; @@ -209,7 +209,7 @@ test mix_process_and_internal = [] { sml::sm> sm{}; - sm.process_event(e1{}); + expect(sm.process_event(e1{})); expect(sm.is(sml::X)); }; @@ -242,11 +242,11 @@ test process_event_sent_from_substate = [] { expect(sm.is(idle, s2)); expect(sm.is)>(s1)); - sm.process_event(e1{}); + expect(sm.process_event(e1{})); expect(sm.is(sml::state, s2)); expect(sm.is)>(s1)); - sm.process_event(e1{}); // + process(e2{}) + expect(sm.process_event(e1{})); // + process(e2{}) expect(sm.is(sml::X, sml::X)); expect(sm.is)>(sml::X)); }; @@ -279,10 +279,10 @@ test process_event_of_substate = [] { expect(sm.is(idle)); expect(sm.is)>(s1)); - sm.process_event(e1{}); + expect(sm.process_event(e1{})); expect(sm.is(sml::state)); - sm.process_event(e2{}); // + process(e2{}) + expect(sm.process_event(e2{})); // + process(e2{}) expect(sm.is(sml::state)); expect(sm.is)>(sml::X)); }; @@ -327,7 +327,7 @@ test process_between_substates = [] { expect(sm.is)>(s1)); expect(sm.is)>(s2)); - sm.process_event(e1{}); + expect(sm.process_event(e1{})); expect(sm.is(sml::X, sml::X)); expect(sm.is)>(sml::X)); expect(sm.is)>(sml::X)); diff --git a/test/ft/actions_process_n_defer.cpp b/test/ft/actions_process_n_defer.cpp index f5df2a05..387fcb65 100644 --- a/test/ft/actions_process_n_defer.cpp +++ b/test/ft/actions_process_n_defer.cpp @@ -62,7 +62,7 @@ test mix_process_n_defer = [] { , s3 + event / defer = s4 , s4 + event = s5 , s5 = s6 - , s6 + on_entry<_> / process(e3{}) + , s6 + on_entry<_> / (process(e1{}), process(e3{})) // e1 is not handled , s6 + event = s7 , s7 = X ); @@ -70,7 +70,7 @@ test mix_process_n_defer = [] { } }; // internal, defer, process, defer, internal, process, internal sml::sm, sml::defer_queue> sm{}; - sm.process_event(e1{}); + expect(!sm.process_event(e1{})); expect(sm.is(sml::X)); }; @@ -105,10 +105,10 @@ test process_n_defer_again = [] { std::string calls; sml::sm, sml::defer_queue> sm{calls}; - sm.process_event(e1{}); - sm.process_event(e1{}); - sm.process_event(e1{}); - sm.process_event(e3{}); + expect(sm.process_event(e1{})); + expect(sm.process_event(e1{})); + expect(sm.process_event(e1{})); + expect(sm.process_event(e3{})); expect(calls == ""); sm.process_event(e2{}); std::cout << calls << "\n";