Last active
March 25, 2019 09:49
-
-
Save rpj/e35114f09ee7fd27a085 to your computer and use it in GitHub Desktop.
Example implementation of a state machine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This example implements a very simple state machine | |
// with two states, Foo and Bar. The machine alternates | |
// between these two states until the machine's context | |
// (here just an integer) reaches the "goal" value, | |
// given by the user on the command line. The wrinkle | |
// is in the user function provided to the machine: if | |
// it returns true (a 50/50 random chance to do so), | |
// the state decrements the machine context, effectively | |
// lengthening the run of the machine randomly. | |
#include <cstddef> | |
#include <cstdlib> | |
#include <cstdio> | |
#include <map> | |
#include <mutex> | |
#include <string> | |
#include <lib/fsm/fsm.h> | |
enum class States { | |
Foo = 0, | |
Bar = 1 | |
}; | |
struct MachineContext { | |
public: | |
int num = 0; | |
}; | |
using MyUserFunc = std::function<int(void)>; | |
using ContextPtr = std::shared_ptr<MachineContext>; | |
using MyMachine = Machine<States, MyUserFunc, ContextPtr>; | |
using StateType = MyMachine::State; | |
class MySimpleState : public StateType { | |
public: | |
MySimpleState(StateType::EnumType state, StateType::EnumType next, std::string name) : | |
state_(state), next_(next), name_(name) | |
{ } | |
const std::string &name() const { return static_cast<const std::string&>(name_); } | |
StateType::EnumType state() override { return state_; } | |
StateType::EnumType process(MyMachine &m) override | |
{ | |
MachineContext *ctx = static_cast<MachineContext*>(m.context().get()); | |
printf("%s process, context is %d.\n", name_.c_str(), ctx->num++); | |
if (m.userFunction()()) { | |
m.context().get()->num--; | |
} | |
return next_; | |
} | |
private: | |
StateType::EnumType state_; | |
StateType::EnumType next_; | |
std::string name_; | |
}; | |
int main(int c, char **v) | |
{ | |
if (c < 2) { | |
printf("Must supply goal number as sole argument.\n"); | |
exit(-1); | |
} | |
MyMachine machine {States::Foo}; | |
ContextPtr ctxptr(new MachineContext); | |
MachineContext *mctx = reinterpret_cast<MachineContext*>(ctxptr.get()); | |
machine.setContext(ctxptr); | |
mctx->num = 1; | |
MyMachine::StatePtr init {new MySimpleState(States::Foo, States::Bar, "Foo state")}; | |
MyMachine::StatePtr idle {new MySimpleState(States::Bar, States::Foo, "Bar state")}; | |
machine.registerState(init); | |
machine.registerState(idle); | |
machine.setErrorHandler([](MyMachine &m, MyMachine::EnumType s) { | |
printf("Machine errored!\n"); | |
}); | |
machine.setUserFunction([]() -> bool { return static_cast<bool>(random() % 2); }); | |
while (mctx->num <= atoi(v[1]) && machine) { | |
if (!machine.step()) { | |
break; | |
} | |
sleep(1); | |
} | |
if (!machine) { | |
printf("Machine errored!\n"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment