Program Listing for File KPStateMachine.hpp¶
↰ Return to documentation for file (src/KPStateMachine.hpp)
#pragma once
#include <KPSubject.hpp>
#include <KPStateMachineObserver.hpp>
#include <unordered_map>
class KPState;
class KPStateMachine : public KPComponent, public KPSubject<KPStateMachineObserver> {
private:
using Middleware = std::function<void(int)>;
using StateName = const char *;
std::unordered_map<StateName, KPState *> mapNameToState;
std::unordered_map<StateName, Middleware> mapNameToMiddleware;
KPState * currentState = nullptr;
public:
using KPComponent::KPComponent;
template <typename T>
void registerState(T && state, StateName name, Middleware middleware = nullptr) {
if (mapNameToState.count(name)) {
halt(TRACE, name, " is already used");
}
if (name == nullptr) {
halt(TRACE, "State must have a name");
}
T * copy = new T{std::forward<T>(state)};
copy->name = name;
mapNameToState[name] = copy;
if (middleware) {
mapNameToMiddleware[name] = middleware;
} else {
mapNameToMiddleware[name] = [name](int code) {
halt(TRACE, "Unhandled state transition: ", name);
};
}
}
template <typename T>
void registerState(T && state, StateName name, StateName next) {
registerState(std::forward<T>(state), name, [this, next](int code) { transitionTo(next); });
}
template <typename T = KPState>
T & getState(StateName name) {
auto c = mapNameToState.find(name);
if (c != mapNameToState.end()) {
return *static_cast<T *>(c->second);
} else {
halt(TRACE, "Unregistered state name: ", name);
}
}
KPState * getCurrentState() const {
return currentState;
}
void next(int code = 0) const;
void restart();
void transitionTo(StateName name);
protected:
void setup() override;
void update() override;
};