Skip to content

Instantly share code, notes, and snippets.

@yossioo
Created April 7, 2020 22:06
Show Gist options
  • Save yossioo/5c4d47fb5ede909621d4fb5bde30d5b3 to your computer and use it in GitHub Desktop.
Save yossioo/5c4d47fb5ede909621d4fb5bde30d5b3 to your computer and use it in GitHub Desktop.
Simple state machine in C++
#include <iostream>
#include <functional>
#include <vector>
class StateMachine
{
public:
StateMachine() = default;
~StateMachine() = default;
void addState(const std::string &_state_name, const std::function<void()> &_in_state = []() {},
const std::function<void()> &_on_enter = []() {},
const std::function<void()> &_on_exit = []() {})
{
++this->n_states;
this->state_names.emplace_back(_state_name);
this->on_enter.emplace_back(_on_enter);
this->in_state.emplace_back(_in_state);
this->on_exit.emplace_back(_on_exit);
}
void spinOnce()
{
if (n_states > 0)
{
if (current_state == next_state)
{
in_state[current_state]();
}
else
{
if (current_state >= 0)
{
on_exit[current_state]();
}
on_enter[next_state]();
current_state = next_state;
in_state[current_state]();
}
}
else
{
throw std::out_of_range("No states, StateMachine can't spin.");
}
}
void setNextState(const std::string &new_state_name)
{
for (std::size_t i = 0; i < this->state_names.size(); ++i)
{
if (this->state_names[i] == new_state_name)
{
setNextState(i);
return;
}
}
throw std::invalid_argument(new_state_name + " is not one of the states.");
}
void setNextState(int new_state_num)
{
if (new_state_num > this->n_states)
{
char buff[100];
sprintf(buff, "Can't change to state %d.", new_state_num);
throw std::out_of_range(buff);
}
this->next_state = new_state_num;
}
[[nodiscard]] int getCurrentState() const
{
return current_state;
}
[[nodiscard]] std::string getStateName(int state_num) const
{
return state_names[state_num];
}
[[nodiscard]] std::string getCurrentStateName() const
{
return state_names[this->current_state];
}
private:
int n_states = 0;
int current_state = -1;
int next_state = 0;
std::vector<std::string> state_names;
std::vector<std::function<void()>> on_enter;
std::vector<std::function<void()>> in_state;
std::vector<std::function<void()>> on_exit;
};
int main()
{
StateMachine SM;
int a = 0;
SM.addState("COUNTING",
[&a]() { a = a + 1; },
[]() { printf("Starting to count\n"); },
[]() { printf("Done counting\n"); });
SM.addState("IDLE",
[]() {},
[]() { printf("Now I wait\n"); },
[]() { printf("Time to work!!!\n"); });
std::cout << SM.getStateName(0) << std::endl;
for (int i = 0; i < 3; ++i)
{
SM.spinOnce();
std::cout << a << std::endl;
}
SM.setNextState("IDLE");
std::cout << "SM changed to " << SM.getCurrentStateName() << std::endl;
SM.spinOnce();
SM.setNextState(0);
for (int i = 0; i < 2; ++i)
{
SM.spinOnce();
std::cout << a << std::endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment