Skip to content

Entering a previously visited composite of a compisite state re-enters its last active substate #495

@ken-voly

Description

@ken-voly

The problem seems to be similar to #55. The initial state of a substate of a substate does not get entered if that state has been left previously. See the following diagram and code:

#include <boost/sml.hpp>
#include <cassert>
#include <iostream>

namespace sml = boost::sml;


/******************** Events ********************/
struct activate {};
struct deactivate {};

struct print_sub1_entry {
    void operator()() {
        std::cout << "sub1 entry\n";
    }
} print_sub1_entry;

struct print_sub2_entry {
    void operator()() {
        std::cout << "sub2 entry\n";
    }
} print_sub2_entry;

struct print_sub3_entry {
    void operator()() {
        std::cout << "sub3 entry\n";
    }
} print_sub3_entry;

struct print_other_substate_entry {
    void operator()() {
        std::cout << "other_substate entry\n";
    }
} print_other_substate_entry;


/******************** States ********************/
struct sub2 {
    struct other_substate {};
    struct sub3 {};

    auto operator()() const {
        using namespace sml;

        return make_transition_table(
             *state<sub3> + sml::on_entry<_> / print_sub3_entry
            , state<sub3> = state<other_substate>

            , state<other_substate> + sml::on_entry<_> / print_other_substate_entry
        );
    }
};

struct sub1 {
    struct sub1_otherstate {};

    auto operator()() const {
        using namespace sml;

        return make_transition_table(
             *state<sub2> + sml::on_entry<_> / print_sub2_entry
        );
    }
};

// Top level state machine
struct state_machine {
    struct inactive {};

    auto operator()() const {
        using namespace sml;

        return make_transition_table(
             *state<inactive> + event<activate> = state<sub1>

            , state<sub1> + sml::on_entry<_> / print_sub1_entry
            , state<sub1> + event<deactivate> = state<inactive>
        );
    }
};


struct my_logger {
  template <class SM, class TEvent>
  void log_process_event(const TEvent&) {
  }

  template <class SM, class TGuard, class TEvent>
  void log_guard(const TGuard&, const TEvent&, bool result) {
  }

  template <class SM, class TAction, class TEvent>
  void log_action(const TAction&, const TEvent&) {
  }

  template <class SM, class TSrcState, class TDstState>
  void log_state_change(const TSrcState& src, const TDstState& dst) {
    printf("[%s][transition] %s -> %s\n", sml::aux::get_type_name<SM>(), src.c_str(), dst.c_str());
  }
};


int main() {
  my_logger logger;
  sml::sm<state_machine, sml::logger<my_logger>> sm{logger};
  //sml::sm<state_machine> sm;

  using namespace sml;

  std::cout << "All sub state entry actions should toggle" << std::endl;
  sm.process_event(activate{});

  std::cout << "\nDeactivating\n";
  sm.process_event(deactivate{});

  std::cout << "\nAll sub state entry actions should toggle again" << std::endl;
  sm.process_event(activate{});
}

Expected Behavior

All sub state entry actions should toggle
[state_machine][transition] inactive -> sub1
sub1 entry
sub2 entry
sub3 entry
[sub2][transition] sub3 -> other_substate
other_substate entry

Deactivating
[state_machine][transition] sub1 -> inactive

All sub state entry actions should toggle again
[state_machine][transition] inactive -> sub1
sub1 entry
sub2 entry
sub3 entry
[sub2][transition] sub3 -> other_substate
other_substate entry

Actual Behavior

Actual Output

All sub state entry actions should toggle
[state_machine][transition] inactive -> sub1
sub1 entry
sub2 entry
sub3 entry
[sub2][transition] sub3 -> other_substate
other_substate entry

Deactivating
[state_machine][transition] sub1 -> inactive

All sub state entry actions should toggle again
[state_machine][transition] inactive -> sub1
sub1 entry
sub2 entry
other_substate entry

Missing Output

Sub3 is not entered and the we don't see the following output the second time an activate event is generated.

sub3 entry
[sub2][transition] sub3 -> other_substate

Steps to Reproduce the Problem

Compile and run the program.

  • c++14 or c++17
  • optimizations on or off

Specifications

  • Version: 1.1.4
  • OS: Ubuntu 20.4
  • Compiler: g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions