parent
740e30cb2b
commit
7228bdf210
@ -0,0 +1,28 @@ |
||||
#pragma once |
||||
|
||||
#include <fmt/core.h> |
||||
|
||||
#ifndef FSM_DEBUG |
||||
#define FSM_STATE(C, S, E, ...) case C::S: S(E, ##__VA_ARGS__); break |
||||
#else |
||||
#define FSM_STATE(C, S, E, ...) case C::S: fmt::println(">> " #C " " #S " event={}, state={}", int(E), int($state)); S(E, ##__VA_ARGS__); fmt::println("<< " #C " state={}", int($state)); break |
||||
#endif |
||||
|
||||
template<typename S, typename E> |
||||
class DeadSimpleFSM { |
||||
protected: |
||||
// BUG: don't put this in your class because state() won't work
|
||||
S $state = S::START; |
||||
|
||||
public: |
||||
template<typename... Types> |
||||
void event(E event, Types... args); |
||||
|
||||
void state(S next_state) { |
||||
$state = next_state; |
||||
} |
||||
|
||||
bool in_state(S state) { |
||||
return $state == state; |
||||
} |
||||
}; |
@ -0,0 +1,67 @@ |
||||
#include <catch2/catch_test_macros.hpp> |
||||
#include <fmt/core.h> |
||||
#include <string> |
||||
#include "../fsm.hpp" |
||||
|
||||
using namespace fmt; |
||||
using std::string; |
||||
|
||||
enum class MyState { |
||||
START, RUNNING, END |
||||
}; |
||||
|
||||
enum class MyEvent { |
||||
STARTED, PUSH, QUIT |
||||
}; |
||||
|
||||
class MyFSM : public DeadSimpleFSM<MyState, MyEvent> { |
||||
public: |
||||
void event(MyEvent ev, string data="") { |
||||
switch($state) { |
||||
FSM_STATE(MyState, START, ev); |
||||
FSM_STATE(MyState, RUNNING, ev, data); |
||||
FSM_STATE(MyState, END, ev); |
||||
} |
||||
} |
||||
|
||||
void START(MyEvent ev) { |
||||
println("<<< START {}", (int)ev); |
||||
state(MyState::RUNNING); |
||||
} |
||||
|
||||
void RUNNING(MyEvent ev, string &data) { |
||||
if(ev == MyEvent::QUIT) { |
||||
println("<<< QUITTING {}", data); |
||||
state(MyState::END); |
||||
} else { |
||||
println("<<< RUN: {}", data); |
||||
state(MyState::RUNNING); |
||||
} |
||||
} |
||||
|
||||
void END(MyEvent ev) { |
||||
println("<<< STOP {}", (int)ev); |
||||
state(MyState::END); |
||||
} |
||||
}; |
||||
|
||||
TEST_CASE("confirm fsm works with optional data", "[utils]") { |
||||
MyFSM fsm; |
||||
|
||||
REQUIRE(fsm.in_state(MyState::START)); |
||||
|
||||
fsm.event(MyEvent::STARTED); |
||||
REQUIRE(fsm.in_state(MyState::RUNNING)); |
||||
|
||||
fsm.event(MyEvent::PUSH); |
||||
REQUIRE(fsm.in_state(MyState::RUNNING)); |
||||
|
||||
fsm.event(MyEvent::PUSH); |
||||
REQUIRE(fsm.in_state(MyState::RUNNING)); |
||||
|
||||
fsm.event(MyEvent::PUSH); |
||||
REQUIRE(fsm.in_state(MyState::RUNNING)); |
||||
|
||||
fsm.event(MyEvent::QUIT, "DONE!"); |
||||
REQUIRE(fsm.in_state(MyState::END)); |
||||
} |
Loading…
Reference in new issue