//! \addtogroup StateMachine
//! \{
//! \file pistatemachine_state.h
//! \brief
//! \~english State machine node
//! \~russian Узел машины состояний
//! \details
//! \~english Contains state classes for building state machines
//! \~russian Содержит классы состояний для построения машин состояний
//! \}
/*
PIP - Platform Independent Primitives
State machine node
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
#ifndef pistatemachine_state_H
#define pistatemachine_state_H
#include "pistatemachine_base.h"
#include "pistring.h"
#include "pisystemtime.h"
//! \~english Base class for state machine states
//! \~russian Базовый класс для состояний машины состояний
class PIP_EXPORT PIStateBase {
friend class PIStateMachine;
friend class PITransitionBase;
friend class PIStateFinal;
public:
//! \~english Creates state with name
//! \~russian Создает состояние с именем
PIStateBase(const PIString & n = {}): name_(n) { ; }
virtual ~PIStateBase();
//! \~english Called when state is \~russian Вы entered
//! зывается при входе в состояние
virtual void onEnter() {}
//! \~english Called when state is exited
//! \~russian Вызывается при выходе из состояния
virtual void onExit() {}
//! \~english Called when state machine finishes (for final states)
//! \~russian Вызывается при завершении машины состояний (для финальных состояний)
virtual void onFinish() {}
//! \~english Returns state machine this state belongs to
//! \~russian Возвращает машину состояний, которой принадлежит это состояние
PIStateMachine * machine() const { return root; }
//! \~english Returns parent state
//! \~russian Возвращает родительское состояние
PIStateBase * parent() const { return parent_state; }
//! \~english Returns active child state
//! \~russian Возвращает активное дочернее состояние
PIStateBase * activeChild() const { return active_state; }
//! \~english Returns all active child states
//! \~russian Возвращает все активные дочерние состояния
PIVector activeChildren() const;
//! \~english Returns all active atomic states
//! \~russian Возвращает все активные атомарные состояния
PIVector activeAtomics() const;
//! \~english Adds child state
//! \~russian Добавляет дочернее состояние
void addState(PIStateBase * s);
//! \~english Adds multiple child states
//! \~russian Добавляет несколько дочерних состояний
void addStates(PIVector s);
//! \~english Sets initial state for compound state
//! \~russian Устанавливает начальное состояние для составного состояния
void setInitialState(PIStateBase * s);
//! \~english Adds transition to target state on event
//! \~russian Добавляет переход к целевому состоянию по событию
PITransitionBase * addTransition(PIStateBase * target, int event_id);
//! \~english Adds timeout transition to target state
//! \~russian Добавляет переход по таймауту к целевому состоянию
PITransitionTimeout * addTimeoutTransition(PIStateBase * target, PISystemTime timeout);
//! \~english Sets parallel mode for state
//! \~russian Устанавливает параллельный режим для состояния
void setParallel(bool yes) { is_parallel = yes; }
//! \~english Returns state name
//! \~russian Возвращает имя состояния
const PIString & getName() const { return name_; }
//! \~english Checks if this is root state machine
//! \~russian Проверяет является ли это корневой машиной состояний
bool isStateMachine() const { return is_root; }
//! \~english Checks if state is active
//! \~russian Проверяет активно ли состояние
bool isActive() const { return is_active; }
//! \~english Checks if state is in parallel mode
//! \~russian Проверяет находится ли состояние в параллельном режиме
bool isParallel() const { return is_parallel; }
//! \~english Checks if state is final
//! \~russian Проверяет является ли состояние финальным
bool isFinal() const { return is_final; }
//! \~english Checks if state is atomic (no children)
//! \~russian Проверяет является ли состояние атомарным (нет потомков)
bool isAtomic() const { return children.isEmpty(); }
//! \~english Checks if state is compound (has children)
//! \~russian Проверяет является ли состояние составным (есть потомки)
bool isCompound() const { return children.isNotEmpty(); }
//! \~english Returns child states
//! \~russian Возвращает дочерние состояния
const PIVector & getChildren() const { return children; }
//! \~english Returns transitions from this state
//! \~russian Возвращает переходы из этого состояния
const PIVector & getTransitions() const { return transitions; }
//! \~english Prints state tree to string
//! \~russian Выводит дерево состояний в строку
void print(PIString prefix = {});
//! \~english Returns all states in machine
//! \~russian Возвращает все состояния в машине
PIVector gatherStates();
private:
bool start(bool force = false);
void setActive(bool yes);
void setActiveRecursive(bool yes);
void setChildrenActive(bool yes);
void setChildrenActiveRecursive(bool yes);
void activeChild(PIStateBase * c);
void childActived(PIStateBase * s);
void propagateRoot(PIStateMachine * r);
void gatherActiveStates(PIVector & output);
void gatherActiveAtomicStates(PIVector & output) const;
void gatherPathToMachine(PIVector & output);
PIVector pathToMachine();
bool is_active = false, is_root = false, is_parallel = false, is_final = false;
PIVector children;
PIVector transitions;
PIStateBase *active_state = nullptr, *initial_state = nullptr, *parent_state = nullptr;
PIStateMachine * root = nullptr;
PIString name_;
};
//! \~english State with lambda callbacks
//! \~russian Состояние с lambda коллбэками
class PIP_EXPORT PIStateLambda: public PIStateBase {
public:
//! \~english Creates lambda state with callbacks
//! \~russian Создает lambda состояние с коллбэками
PIStateLambda(std::function on_enter, std::function on_exit = nullptr, const PIString & n = {}): PIStateBase(n) {
enter = on_enter;
exit = on_exit;
}
void onEnter() override {
if (enter) enter();
}
void onExit() override {
if (exit) exit();
}
private:
std::function enter, exit;
};
//! \~english Final state of state machine
//! \~russian Финальное состояние машины состояний
class PIP_EXPORT PIStateFinal: public PIStateBase {
public:
//! \~english Creates final state with finish callback
//! \~russian Создает финальное состояние с коллбэком завершения
PIStateFinal(std::function on_finish = nullptr, const PIString & n = {}): PIStateBase(n) {
is_final = true;
enter = on_finish;
}
void onEnter() override {
if (enter) enter();
}
private:
std::function enter;
};
//! \~english Output stream operator for PIStateBase
//! \~russian Оператор вывода потока для PIStateBase
//! \param c Output stream
//! \param s State to output
//! \return Reference to output stream
inline PICout operator<<(PICout c, PIStateBase * s) {
if (!s)
c << "state(nullptr)";
else
c << ("state(\"" + s->getName() + "\")");
return c;
}
#endif