boost-ext / sml

C++14 State Machine library
https://boost-ext.github.io/sml
Boost Software License 1.0
1.14k stars 177 forks source link

chained anonymous transitions not executing #179

Open dsiroky opened 6 years ago

dsiroky commented 6 years ago

This state machine:

struct my_machine
{
  auto operator()() const noexcept
  {
    using namespace sml;
    return make_transition_table(
        *"start"_s = "A"_s
        ,"A"_s = "B"_s
        ,"B"_s = "C"_s

        ,"start"_s + sml::on_entry<_> / [] { std::cout << "s" << '\n'; }
        ,"A"_s + sml::on_entry<_> / [] { std::cout << "a" << '\n'; }
        ,"B"_s + sml::on_entry<_> / [] { std::cout << "b" << '\n'; }
        ,"C"_s + sml::on_entry<_> / [] { std::cout << "c" << '\n'; }
      );
  }
};

prints only

s
a

on its construction however it should go through all states without waiting.

dsiroky commented 6 years ago

I've now noticed that there is a related PR. I can offer few more tests: https://github.com/dsiroky/sml/commit/fa042ee65326d70b236f5abcab7a6db14d3e91c6

dsiroky commented 6 years ago

More observations from my experiments. If I apply this:

--- a/include/boost/sml.hpp
+++ b/include/boost/sml.hpp
@@ -1269,6 +1269,9 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:
     const auto handled =
         process_event_noexcept<get_event_mapping_t<get_generic_t<TEvent>, mappings>>(event, deps, subs, has_exceptions{});
 #endif
+    process_internal_events(anonymous{}, deps, subs);
+    process_internal_events(anonymous{}, deps, subs);
+    process_internal_events(anonymous{}, deps, subs);
     process_internal_events(anonymous{}, deps, subs);
     process_defer_events(deps, subs, handled, aux::type<defer_queue_t<TEvent>>{}, events_t{});
     process_queued_events(deps, subs, aux::type<process_queue_t<TEvent>>{}, events_t{});
@@ -1292,6 +1295,9 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:
   void start(TDeps &deps, TSubs &subs) {
     process_internal_events(on_entry<_, initial>{}, deps, subs);
     process_internal_events(anonymous{}, deps, subs);
+    process_internal_events(anonymous{}, deps, subs);
+    process_internal_events(anonymous{}, deps, subs);
+    process_internal_events(anonymous{}, deps, subs);

then it starts working correctly for non-composite SM. For composite SM it will not process anonymous transitions in the sub-machine. However if I add on_entry action for the sub-machine initial state then it all works like a charm.