25 #include <initializer_list>
36 #define DEFINE_STATE_STRUCT(MachineType, ContextType, Id, StructName) \
37 static constexpr StateId Id = #Id; \
38 struct StructName : public State<MachineType, ContextType> { \
39 using State<MachineType, ContextType>::State; \
40 StateId id() const override { return Id; } \
41 StateId impl(ContextType& ctx) override; \
46 using StateId =
const char*;
48 template <
typename MachineType,
typename ContextType>
57 std::map<StateId, uint64_t> transitions_;
60 MachineType* machine_;
63 State(MachineType* ptr) : machine_(ptr) { assert(machine_ !=
nullptr); }
64 virtual ~
State() =
default;
72 virtual StateId
id()
const = 0;
87 virtual StateId
run(ContextType& ctx) {
89 logger()->trace(
"Enter state: {}", this->
id());
91 [&](timer::Milliseconds timing) { this->timing_ms_.
push_back(timing.count()); });
93 StateId next =
impl(ctx);
94 if (next !=
nullptr) {
103 virtual cloe::Logger
logger()
const {
return cloe::logger::get(
"cloe"); }
109 {
"transitions", s.transitions_},
110 {
"timing_ms", s.timing_ms_},
118 virtual StateId
impl(ContextType& ctx) = 0;
121 template <
typename StateType,
typename ContextType>
123 using StateMap = std::map<StateId, std::shared_ptr<StateType>>;
125 StateId prev_state_{
nullptr};
126 StateId interrupt_{
nullptr};
127 std::mutex interrupt_mtx_;
136 const StateMap&
states()
const {
return states_; }
146 template <
typename StateImpl = StateType>
148 return std::dynamic_pointer_cast<StateImpl>(states_.at(
id));
151 StateId run_state(StateId
id, ContextType& ctx) {
152 assert(states_.count(
id) == 1);
153 auto s = states_.at(
id);
155 auto next_id = s->run(ctx);
164 void register_state(StateType* s) {
165 assert(s !=
nullptr);
166 register_state(std::shared_ptr<StateType>(s));
169 void register_state(std::shared_ptr<StateType> s) {
171 assert(states_.count(
id) == 0);
172 states_[id] = std::move(s);
175 void register_states(std::initializer_list<StateType*> init) {
176 for (
auto& s : init) {
188 logger()->trace(
"Push interrupt: {}",
id);
189 std::lock_guard<std::mutex> guard(interrupt_mtx_);
190 if (interrupt_ !=
nullptr && interrupt_ !=
id) {
191 throw std::logic_error{
"interrupt queuing is currently not available, already processing: " +
192 std::string(interrupt_)};
197 std::optional<StateId> pop_interrupt() {
198 std::lock_guard<std::mutex> guard(interrupt_mtx_);
199 if (interrupt_ ==
nullptr) {
202 auto tmp = interrupt_;
203 interrupt_ =
nullptr;
214 virtual StateId
handle_interrupt(StateId nominal, StateId interrupt, ContextType& ctx) = 0;
219 virtual cloe::Logger
logger()
const {
return cloe::logger::get(
"cloe"); }
Definition: statistics.hpp:110
void push_back(double x)
Definition: statistics.hpp:132
Definition: state_machine.hpp:122
virtual StateId handle_interrupt(StateId nominal, StateId interrupt, ContextType &ctx)=0
virtual cloe::Logger logger() const
Definition: state_machine.hpp:219
std::shared_ptr< StateImpl > get_state(StateId id)
Definition: state_machine.hpp:147
StateId previous_state() const
Definition: state_machine.hpp:141
const StateMap & states() const
Definition: state_machine.hpp:136
void push_interrupt(StateId id)
Definition: state_machine.hpp:187
Definition: state_machine.hpp:49
virtual cloe::Logger logger() const
Definition: state_machine.hpp:103
MachineType * state_machine() const
Definition: state_machine.hpp:80
virtual StateId impl(ContextType &ctx)=0
virtual StateId run(ContextType &ctx)
Definition: state_machine.hpp:87
virtual StateId id() const =0