25 #include <initializer_list>
31 #include <boost/optional.hpp>
37 #define DEFINE_STATE_STRUCT(MachineType, ContextType, Id, StructName) \
38 static constexpr StateId Id = #Id; \
39 struct StructName : public State<MachineType, ContextType> { \
40 using State<MachineType, ContextType>::State; \
41 StateId id() const override { return Id; } \
42 StateId impl(ContextType& ctx) override; \
47 using StateId =
const char*;
49 template <
typename MachineType,
typename ContextType>
58 std::map<StateId, uint64_t> transitions_;
61 MachineType* machine_;
64 State(MachineType* ptr) : machine_(ptr) { assert(machine_ !=
nullptr); }
65 virtual ~
State() =
default;
73 virtual StateId
id()
const = 0;
88 virtual StateId
run(ContextType& ctx) {
90 logger()->trace(
"Enter state: {}", this->
id());
92 [&](timer::Milliseconds timing) { this->timing_ms_.
push_back(timing.count()); });
94 StateId next =
impl(ctx);
95 if (next !=
nullptr) {
104 virtual cloe::Logger
logger()
const {
return cloe::logger::get(
"cloe"); }
110 {
"transitions", s.transitions_},
111 {
"timing_ms", s.timing_ms_},
119 virtual StateId
impl(ContextType& ctx) = 0;
122 template <
typename StateType,
typename ContextType>
124 using StateMap = std::map<StateId, std::shared_ptr<StateType>>;
126 StateId prev_state_{
nullptr};
127 StateId interrupt_{
nullptr};
128 std::mutex interrupt_mtx_;
137 const StateMap&
states()
const {
return states_; }
147 template <
typename StateImpl = StateType>
149 return std::dynamic_pointer_cast<StateImpl>(states_.at(
id));
152 StateId run_state(StateId
id, ContextType& ctx) {
153 assert(states_.count(
id) == 1);
154 auto s = states_.at(
id);
156 auto next_id = s->run(ctx);
165 void register_state(StateType* s) {
166 assert(s !=
nullptr);
167 register_state(std::shared_ptr<StateType>(s));
170 void register_state(std::shared_ptr<StateType> s) {
172 assert(states_.count(
id) == 0);
173 states_[id] = std::move(s);
176 void register_states(std::initializer_list<StateType*> init) {
177 for (
auto& s : init) {
189 logger()->trace(
"Push interrupt: {}",
id);
190 std::lock_guard<std::mutex> guard(interrupt_mtx_);
191 if (interrupt_ !=
nullptr) {
192 throw std::logic_error{
"interrupt queuing is currently not available, already processing: " +
193 std::string(interrupt_)};
198 boost::optional<StateId> pop_interrupt() {
199 std::lock_guard<std::mutex> guard(interrupt_mtx_);
200 if (interrupt_ ==
nullptr) {
203 auto tmp = interrupt_;
204 interrupt_ =
nullptr;
215 virtual StateId
handle_interrupt(StateId nominal, StateId interrupt, ContextType& ctx) = 0;
220 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:123
virtual StateId handle_interrupt(StateId nominal, StateId interrupt, ContextType &ctx)=0
virtual cloe::Logger logger() const
Definition: state_machine.hpp:220
std::shared_ptr< StateImpl > get_state(StateId id)
Definition: state_machine.hpp:148
StateId previous_state() const
Definition: state_machine.hpp:142
const StateMap & states() const
Definition: state_machine.hpp:137
void push_interrupt(StateId id)
Definition: state_machine.hpp:188
Definition: state_machine.hpp:50
virtual cloe::Logger logger() const
Definition: state_machine.hpp:104
MachineType * state_machine() const
Definition: state_machine.hpp:81
virtual StateId impl(ContextType &ctx)=0
virtual StateId run(ContextType &ctx)
Definition: state_machine.hpp:88
virtual StateId id() const =0