Files
pip/libs/main/state_machine/pistatemachine_state.h
2026-03-20 16:31:30 +03:00

261 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \~\file pistatemachine_state.h
//! \~\ingroup StateMachine
//! \~\brief
//! \~english Declares states used by PIStateMachine
//! \~russian Объявляет состояния, используемые в PIStateMachine
/*
PIP - Platform Independent Primitives
State machine node
Ivan Pelipenko peri4ko@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 <http://www.gnu.org/licenses/>.
*/
#ifndef pistatemachine_state_H
#define pistatemachine_state_H
#include "pistatemachine_base.h"
#include "pistring.h"
#include "pisystemtime.h"
//! \~\ingroup StateMachine
//! \~\brief
//! \~english Base class for states in a hierarchical state machine.
//! \~russian Базовый класс состояния в иерархической машине состояний.
//! \~\details
//! \~english
//! A state can own child states and outgoing transitions. Compound states activate
//! either their initial child state or all children when parallel mode is enabled.
//! \~russian
//! Состояние может владеть дочерними состояниями и исходящими переходами.
//! Составные состояния активируют либо начальное дочернее состояние, либо все
//! дочерние состояния при включенном параллельном режиме.
class PIP_EXPORT PIStateBase {
friend class PIStateMachine;
friend class PITransitionBase;
friend class PIStateFinal;
public:
//! \~english Creates a state with an optional diagnostic name.
//! \~russian Создает состояние с необязательным именем для диагностики.
PIStateBase(const PIString & n = {}): name_(n) { ; }
//! \~english Destroys the state together with owned child states and transitions.
//! \~russian Уничтожает состояние вместе с принадлежащими дочерними состояниями и переходами.
virtual ~PIStateBase();
//! \~english Called when the state becomes active.
//! \~russian Вызывается при активации состояния.
virtual void onEnter() {}
//! \~english Called when the state becomes inactive.
//! \~russian Вызывается при деактивации состояния.
virtual void onExit() {}
//! \~english Called when a final child finishes this state.
//! \~russian Вызывается, когда финальное дочернее состояние завершает это состояние.
virtual void onFinish() {}
//! \~english Returns the root state machine.
//! \~russian Возвращает корневую машину состояний.
PIStateMachine * machine() const { return root; }
//! \~english Returns the parent state.
//! \~russian Возвращает родительское состояние.
PIStateBase * parent() const { return parent_state; }
//! \~english Returns the active child of a non-parallel compound state.
//! \~russian Возвращает активное дочернее состояние непараллельного составного состояния.
PIStateBase * activeChild() const { return active_state; }
//! \~english Returns active child states.
//! \~russian Возвращает активные дочерние состояния.
PIVector<PIStateBase *> activeChildren() const;
//! \~english Returns active atomic leaf states below this state.
//! \~russian Возвращает активные атомарные листовые состояния под этим состоянием.
PIVector<PIStateBase *> activeAtomics() const;
//! \~english Adds a child state owned by this state.
//! \~russian Добавляет дочернее состояние, которым владеет это состояние.
void addState(PIStateBase * s);
//! \~english Adds multiple child states owned by this state.
//! \~russian Добавляет несколько дочерних состояний, которыми владеет это состояние.
void addStates(PIVector<PIStateBase *> s);
//! \~english Sets the initial child state for a non-parallel compound state.
//! \~russian Задает начальное дочернее состояние для непараллельного составного состояния.
void setInitialState(PIStateBase * s);
//! \~english Adds an event-driven transition from this state to \a target.
//! \~russian Добавляет переход по событию из этого состояния в \a target.
PITransitionBase * addTransition(PIStateBase * target, int event_id);
//! \~english Adds a timeout transition that fires while this state stays active.
//! \~russian Добавляет переход по таймауту, который срабатывает пока это состояние активно.
PITransitionTimeout * addTimeoutTransition(PIStateBase * target, PISystemTime timeout);
//! \~english Enables or disables parallel activation of child states.
//! \~russian Включает или выключает параллельную активацию дочерних состояний.
void setParallel(bool yes) { is_parallel = yes; }
//! \~english Returns the state name.
//! \~russian Возвращает имя состояния.
const PIString & getName() const { return name_; }
//! \~english Returns true for the root machine object.
//! \~russian Возвращает true для корневого объекта машины состояний.
bool isStateMachine() const { return is_root; }
//! \~english Returns true if the state is currently active.
//! \~russian Возвращает true, если состояние сейчас активно.
bool isActive() const { return is_active; }
//! \~english Returns true if child states are activated in parallel.
//! \~russian Возвращает true, если дочерние состояния активируются параллельно.
bool isParallel() const { return is_parallel; }
//! \~english Returns true if the state is marked as final.
//! \~russian Возвращает true, если состояние помечено как финальное.
bool isFinal() const { return is_final; }
//! \~english Returns true if the state has no children.
//! \~russian Возвращает true, если у состояния нет дочерних состояний.
bool isAtomic() const { return children.isEmpty(); }
//! \~english Returns true if the state owns child states.
//! \~russian Возвращает true, если состояние содержит дочерние состояния.
bool isCompound() const { return children.isNotEmpty(); }
//! \~english Returns direct child states.
//! \~russian Возвращает прямые дочерние состояния.
const PIVector<PIStateBase *> & getChildren() const { return children; }
//! \~english Returns outgoing transitions owned by this state.
//! \~russian Возвращает исходящие переходы, принадлежащие этому состоянию.
const PIVector<PITransitionBase *> & getTransitions() const { return transitions; }
//! \~english Prints the state tree and active branches to piCout.
//! \~russian Печатает дерево состояний и активные ветви в piCout.
void print(PIString prefix = {});
//! \~english Returns this state and all descendant states.
//! \~russian Возвращает это состояние и все дочерние состояния.
PIVector<PIStateBase *> 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<PIStateBase *> & output);
void gatherActiveAtomicStates(PIVector<PIStateBase *> & output) const;
void gatherPathToMachine(PIVector<PIStateBase *> & output);
PIVector<PIStateBase *> pathToMachine();
bool is_active = false, is_root = false, is_parallel = false, is_final = false;
PIVector<PIStateBase *> children;
PIVector<PITransitionBase *> transitions;
PIStateBase *active_state = nullptr, *initial_state = nullptr, *parent_state = nullptr;
PIStateMachine * root = nullptr;
PIString name_;
};
//! \~\ingroup StateMachine
//! \~\brief
//! \~english State implementation that forwards enter and exit virtual methods to callbacks.
//! \~russian Реализация состояния, которая перенаправляет виртуальные методы входа и выхода в callback-функции.
class PIP_EXPORT PIStateLambda: public PIStateBase {
public:
//! \~english Creates a state backed by enter and exit callbacks.
//! \~russian Создает состояние с callback-функциями входа и выхода.
PIStateLambda(std::function<void()> on_enter, std::function<void()> on_exit = nullptr, const PIString & n = {})
: PIStateBase(n)
, enter(std::move(on_enter))
, exit(std::move(on_exit)) {}
//! \~english Executes the enter callback.
//! \~russian Выполняет callback-функцию входа.
void onEnter() override {
if (enter) enter();
}
//! \~english Executes the exit callback.
//! \~russian Выполняет callback-функцию выхода.
void onExit() override {
if (exit) exit();
}
private:
std::function<void()> enter, exit;
};
//! \~\ingroup StateMachine
//! \~\brief
//! \~english Final state that finishes its parent state when entered.
//! \~russian Финальное состояние, которое завершает родительское состояние при входе.
class PIP_EXPORT PIStateFinal: public PIStateBase {
public:
//! \~english Creates a final state with an optional callback executed on entry.
//! \~russian Создает финальное состояние с необязательной callback-функцией, выполняемой при входе.
PIStateFinal(std::function<void()> on_finish = nullptr, const PIString & n = {}): PIStateBase(n), enter(std::move(on_finish)) {
is_final = true;
}
//! \~english Executes the finish callback when the final state is entered.
//! \~russian Выполняет callback завершения при входе в финальное состояние.
void onEnter() override {
if (enter) enter();
}
private:
std::function<void()> enter;
};
//! \relatesalso PIStateBase
//! \~english Writes a textual representation of a state to PICout.
//! \~russian Записывает текстовое представление состояния в PICout.
inline PICout operator<<(PICout c, PIStateBase * s) {
if (!s)
c << "state(nullptr)";
else
c << ("state(\"" + s->getName() + "\")");
return c;
}
#endif