I designed this state machine using boost::sml
struct LooperStateMachine {
auto operator()() const {
using namespace sml;
return make_transition_table(
*"beggining"_s + event<heel> / onRecordFirstLoop.value() = "recording_first_loop"_s,
"recording_first_loop"_s + event<heel>[is_heel_valid] / onRecordLoops.value() = "recording_other_loops_and_playing"_s,
"recording_first_loop"_s + event<toe>[is_toe_valid] / onPlayLoops.value() = "playing_loops"_s,
"playing_loops"_s + event<toe>[is_toe_valid]/onStopPlayingLoops.value() = "stopped"_s,
"playing_loops"_s + event<heel>[is_heel_valid]/onRecordLoops.value() = "recording_other_loops_and_playing"_s,
"recording_other_loops_and_playing"_s + event<toe>[is_toe_valid] / onPlayLoops.value() = "playing_loops"_s,
"stopped"_s + event<toe>[is_toe_valid] / onClearLoops.value() = "beggining"_s,
"stopped"_s + event<heel>[is_heel_valid] / onSaveLoops.value() = "stopped"_s
);
}
std::optional<std::function<void()>> onClearLoops;
std::optional<std::function<void()>> onSaveLoops;
std::optional<std::function<void()>> onPlayLoops;
std::optional<std::function<void()>> onRecordLoops;
std::optional<std::function<void()>> onRecordFirstLoop;
std::optional<std::function<void()>> onStopPlayingLoops;
};
However, to use it, the sm
auto instantiates it:
int main() {
using namespace sml;
sm<LooperStateMachine> sm;
So I don't get a chance to set my functions.
How can I set the functions?
To your literal question you might just provide a default constructor/NSMI. However I get that you want to be able to "dynamically" switch out these action "hooks".
About injecting the function hooks, the docs say:
SML states cannot have data as data is injected directly into guards/actions instead
This gave me the idea to separate your runtime state from the state machine:
Aside: optional functions are redundant,
function<>
can already be value-less and has a convenient conversion to bool fdr that, just likeoptional<>
.
#include <boost/sml.hpp>
#include <functional>
#include <iostream>
namespace sml = boost::sml;
namespace looping {
struct heel { };
struct toe { };
static auto is_heel_valid = []() { return false; };
static auto is_toe_valid = []() { return false; };
using DynamicAction = std::function<void()>;
struct Hooks {
DynamicAction onClearLoops;
DynamicAction onSaveLoops;
DynamicAction onPlayLoops;
DynamicAction onRecordLoops;
DynamicAction onRecordFirstLoop;
DynamicAction onStopPlayingLoops;
};
static auto onClearLoops = [](Hooks &hooks) { if (hooks.onClearLoops) hooks.onClearLoops(); };
static auto onSaveLoops = [](Hooks &hooks) { if (hooks.onSaveLoops) hooks.onSaveLoops(); };
static auto onPlayLoops = [](Hooks &hooks) { if (hooks.onPlayLoops) hooks.onPlayLoops(); };
static auto onRecordLoops = [](Hooks &hooks) { if (hooks.onRecordLoops) hooks.onRecordLoops(); };
static auto onRecordFirstLoop = [](Hooks &hooks) { if (hooks.onRecordFirstLoop) hooks.onRecordFirstLoop(); };
static auto onStopPlayingLoops = [](Hooks &hooks) { if (hooks.onStopPlayingLoops) hooks.onStopPlayingLoops(); };
struct LooperStateMachine {
auto operator()() const {
using namespace sml;
return make_transition_table(
*"beginning"_s + event<heel> / onRecordFirstLoop = "recording_first_loop"_s,
"recording_first_loop"_s + event<heel>[is_heel_valid] / onRecordLoops = "recording_other_loops_and_playing"_s,
"recording_first_loop"_s + event<toe>[is_toe_valid] / onPlayLoops = "playing_loops"_s,
"playing_loops"_s + event<toe>[is_toe_valid]/onStopPlayingLoops = "stopped"_s,
"playing_loops"_s + event<heel>[is_heel_valid]/onRecordLoops = "recording_other_loops_and_playing"_s,
"recording_other_loops_and_playing"_s + event<toe>[is_toe_valid] / onPlayLoops = "playing_loops"_s,
"stopped"_s + event<toe>[is_toe_valid] / onClearLoops = "beginning"_s,
"stopped"_s + event<heel>[is_heel_valid] / onSaveLoops = "stopped"_s
);
}
};
}
int main() {
looping::Hooks hooks;
hooks.onClearLoops = [] { std::cout << "Clearing them\n"; };
sml::sm<looping::LooperStateMachine> sm(hooks);
}
Disclaimer: I have only the flimsiest understanding of this library. I find it to be a mind bender to get to grips with, but in an increasingly positive way.