Giter Site home page Giter Site logo

Comments (4)

uyha avatar uyha commented on June 12, 2024 1

I modified your example to create variables instead of temporaries, it seems to make fewer copy constructor calls. You can check here. Also, maybe you can provide a Godbolt link instead of forking the project since it's easier to try out what you're talking about.

from sml.

rhaschke avatar rhaschke commented on June 12, 2024

I just noticed a small remark in the docs, stating:

`SML` states cannot have data as data is injected directly into guards/actions instead.

I don't understand what is meant by injection and I couldn't find any hint to that in the docs yet.

Anyway, if states must not comprise data members, how would you implement reusable, i.e. self-contained and configurable states? Think of data class in example/data.cpp being reused multiple times as sub states in an enclosing higher-level state machine. Where do you store the "configuration" data of a state if not in the state itself? I could not find any example illustrating this. Any help is highly welcome.

from sml.

rhaschke avatar rhaschke commented on June 12, 2024

Ok, I learned the hard way myself:

  1. states can comprise data members, but their initialization must not happen via classical constructors, but via aggregate initialization, which doesn't allow execution of user-define code during initialization.
  2. In order to achieve the latter as well, one must use Context classes, which themselves allow for custom initialization, but which are then just passed to the state via aggregate initialization.
  3. This passing is automated by SML via template magic. This process is called dependency injection.

Here is a working minimal example:

#include <boost/sml.hpp>
#include <cstdio>
#include <queue>
#include <string>

namespace sml = boost::sml;

struct next {};
struct quit {};

const auto idle = sml::state<class idle>;
const auto s1 = sml::state<class s1>;
const auto s2 = sml::state<class s2>;

struct Context {
  static int next_id;

  Context() = delete;
  // user-defined constructors
  Context(int data, const std::string& extra) : id(++next_id), data(data), extra(extra) { printf("ctor:   %d\n", id); }

  Context(const Context& c) : id(++next_id), data(c.data), extra(c.extra) { printf("copy c: %d -> %d\n", c.id, id); };
  Context(Context&& c) : id(++next_id), data(c.data), extra(std::move(c.extra)) { printf("move c: %d -> %d\n", c.id, id); };

  Context& operator=(const Context& c) = delete;
  Context& operator=(Context&& c) = delete;

  int id;
  int data;
  std::string extra;
};
int Context::next_id = 0;

int main() {
  struct sub {
    // sub must not have any user-defined constructor
    Context ctx;  // state-local data

    auto operator()() const noexcept {
      using namespace sml;
      // clang-format off
      return make_transition_table(
        * s1   + on_entry<_> / (&sub::method, process(quit{}), process(next{}))
        , s2   + on_entry<_> / (process(quit{}), process(next{}))
        , s1   + event<next> = s2
        , s2   + event<next> = s1
      );
      // clang-format on
    }
    void method() { printf("method: %d, %s (%d)\n", ctx.data, ctx.extra.c_str(), ctx.id); }
  };

  struct parent {
    sml::front::state_sm<sub>::type s;

    auto operator()() noexcept {
      using namespace sml;
      // clang-format off
      return make_transition_table(
        * idle + event<next> = s
        , s + event<quit> / [this] { printf("quitting\n"); } = X
      );
      // clang-format on
    }
  };

  Context c(42, "Hello");  // initialize context with custom ctor
  sub s{c};                // initialize sub-state by passing c via aggregate initialization

  sml::sm<parent, sml::process_queue<std::queue>> sm(s);  // inject initialized sub state into state machine
  sm.process_event(next{});
  sm.process_event(next{});  // + process(e2{})
}

from sml.

rhaschke avatar rhaschke commented on June 12, 2024

The Context must be copyable (movable is not sufficient) and it is still copied a few times:

ctor:   1
copy c: 1 -> 2
copy c: 2 -> 3
copy c: 3 -> 4
copy c: 2 -> 5
method: 42, Hello (2)
quitting

from sml.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.