Skip to content

Instantly share code, notes, and snippets.

@rpj
Last active March 25, 2019 09:49
Show Gist options
  • Save rpj/e35114f09ee7fd27a085 to your computer and use it in GitHub Desktop.
Save rpj/e35114f09ee7fd27a085 to your computer and use it in GitHub Desktop.
Example implementation of a state machine
// 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