boost-ext / sml

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

[feature] defer #4

Closed kris-jusiak closed 8 years ago

redboltz commented 8 years ago

Hi, thank you for writing a great library. I'm using Boost.MSM now and suffering from a long compile time. I watched C++Now 2016 Video and slides. I am deeply impressed at a great compile-time, performance of msm-lite.

If defer is supported, I can migrate some of my project from Boost.MSM to msm-lite. I really want to defer functionality.

I found #if defined(BOOST_MSM_LITE_DEFER_LIMIT_SIZE) in the code. I'm not sure but it implies the length of deferred queue is fixed size. Is that right? If you provide a variable length version, for example using std::deque, it is matched to my use case.

My use case is a kind of networking server. The server has a state machine. In some transitional state, received events should be deferred. And the number of events is difficult to predict. After leaving the transitional state, then deferred event are processed. That is why I need a variable length version.

Do you have any plan to support that?

kris-jusiak commented 8 years ago

Thanks @redboltz

By default, defer, most likely, will be using a simple circular array (therefore BOOST_MSM_LITE_DEFER_LIMIT_SIZE). Nevertheless, there will be an option to change it to use std::deque or any other container and use it with a variable length too (via policies).

redboltz commented 8 years ago

@krzysztof-jusiak thank you for the response.

By default, defer, most likely, will be using a simple circular array (therefore BOOST_MSM_LITE_DEFER_LIMIT_SIZE).

I understand.

Nevertheless, there will be an option to change it to use std::deque or any other container and use it with a variable length too (via policies).

Sounds good. I'm looking forward to using the functionality :)

kris-jusiak commented 8 years ago

implemented in the newest master. Tests are -> here https://github.com/boost-experimental/msm-lite/blob/master/test/ft/ft_defer.cpp.

Closing it for now as I'm trying to clean up issues a bit. Please, reopen if it's not working as expected. Thanks!

BTW. test cases from http://redboltz.wikidot.com/deferred-events seem to work, but defo there are some cases which aren't covered properly.

redboltz commented 8 years ago

Thank you for implementing defer functionality!

I've double checked using my example http://redboltz.wikidot.com/deferred-events

I implemented the first state machine diagram as follows:

#include <cassert>
#include <queue>
#include "boost/sml.hpp"

namespace sml = boost::sml;

struct e1 {};
struct e2 {};

struct defer_test {
    auto operator()() const noexcept {
        using namespace sml;
        // clang-format off
        return make_transition_table(
            *"s1"_s + event<e1> / defer
            , "s1"_s + event<e2> = "s2"_s
            , "s2"_s + event<e1> / defer
            , "s2"_s + event<e2> = "s3"_s
            , "s3"_s + event<e1> = "s4"_s
            , "s4"_s + event<e1> = "s5"_s
            , "s5"_s + event<e1> = "s6"_s
        );
        // clang-format on
    }
};

int main() {
    using namespace sml;

    sm<defer_test, sml::defer_queue<std::queue>> sm;
    assert(sm.is("s1"_s));

    sm.process_event(e1{}); // defer
    assert(sm.is("s1"_s));

    sm.process_event(e1{}); // defer again
    assert(sm.is("s1"_s));

    sm.process_event(e2{}); // transition to s2 by e2, and then deferred e1s should still be deferred.
    assert(sm.is("s2"_s));

    sm.process_event(e2{}); // transition to s3 by e2, and then transition to s4, s5 by deferred e1s
    assert(sm.is("s5"_s));
}

The code corresponding to the second state machine diagram is follows:

#include <cassert>
#include <queue>
#include "boost/sml.hpp"

namespace sml = boost::sml;

struct e1 {};
struct e2 {};

struct defer_test {
    auto operator()() const noexcept {
        using namespace sml;
        // clang-format off
        return make_transition_table(
            *"s1"_s + event<e1> / defer
            , "s1"_s + event<e2> = "s2"_s
            , "s2"_s + event<e1> = "s5"_s
            , "s2"_s = "s3"_s
            , "s3"_s + event<e1> = "s4"_s
        );
        // clang-format on
    }
};

int main() {
    using namespace sml;

    sm<defer_test, sml::defer_queue<std::queue>> sm;
    assert(sm.is("s1"_s));

    sm.process_event(e1{}); // defer
    assert(sm.is("s1"_s));

    sm.process_event(e2{});
    assert(sm.is("s4"_s));
}

Both work as I expected.

kris-jusiak commented 8 years ago

Awesome! thanks for checking @redboltz. Sorry for taking so long, though.