/** * @file utils/RootStateMachine.hpp * @author The ARTIS Development Team * See the AUTHORS or Authors.txt file */ /* * ARTIS - the multimodeling and simulation environment * This file is a part of the ARTIS environment * * Copyright (C) 2013-2023 ULCO http://www.univ-littoral.fr * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ARTIS_STAR_ADDONS_UTILS_ROOT_STATE_MACHINE_HPP #define ARTIS_STAR_ADDONS_UTILS_ROOT_STATE_MACHINE_HPP #include #include #include namespace artis::addons::utils { template class RootStateMachine { public: typedef std::vector external_events_type; RootStateMachine() = default; virtual ~RootStateMachine() = default; virtual void build(const Parameters ¶meters) = 0; template constexpr void build_machines(const Parameters ¶meters) { if constexpr(N == 1) { this->template build_machine> (0, parameters); } else { this->template build_machine> (N - 1, parameters); build_machines(parameters); } } int current_state(int machine_id) const { typename Types::state_machine_IDs_type::values key = static_cast(machine_id); return _machines.find(key)->second->current_state()->_id; } const std::shared_ptr & machine(const int machine_id) { typename Types::state_machine_IDs_type::values key = static_cast(machine_id); return _machines.find(key)->second; } const external_events_type &outbox() const { return _outbox; } void start(const typename Time::type &t) { std::for_each(_machines.begin(), _machines.end(), [t](const auto &e) { e.second->start(t); }); _last_time = t; } template const StateType &state_(int machine_id) const { typename Types::state_machine_IDs_type::values key = static_cast(machine_id); return std::dynamic_pointer_cast < StateMachine < Time, Types, StateType >> (_machines.at(key))->state_(); } typename Time::type ta(const typename Time::type &t) const { if (_outbox.empty()) { typename Time::type min = Time::infinity; std::for_each(_machines.cbegin(), _machines.cend(), [t, &min](const auto &e) { typename Time::type ta = e.second->ta(t); min = min < ta ? min : ta; }); return min; } else return 0; } void transition(const typename Time::type &t) { if (_outbox.empty()) { std::for_each(_machines.cbegin(), _machines.cend(), [t, this](const auto &e) { if (e.second->is_ready(t)) { typename Types::state_machine_type::Events events = e.second->transition(t); dispatch(t, events.internals); appendEvents(events.externals); } }); } else { _outbox.clear(); } _last_time = t; std::for_each(_machines.cbegin(), _machines.cend(), [t](const auto &e) { e.second->update_sigma(t); }); } void transition(const typename Time::type &t, int machine_id, const typename Types::state_machine_type::ExternalEvent &e) { typename Types::state_machine_IDs_type::values key = static_cast(machine_id); typename Types::state_machine_type::Events events = _machines.at(key)->transition(t, e); dispatch(t, events.internals); appendEvents(events.externals); std::for_each(_machines.cbegin(), _machines.cend(), [t](const auto &e) { e.second->update_sigma(t); }); } protected: template void build_machine(int machine_id, const Parameters ¶meters) { auto machine = std::make_shared(*dynamic_cast(this), parameters); typename Types::state_machine_IDs_type::values key = static_cast(machine_id); machine->build(machine); this->_machines[key] = std::dynamic_pointer_cast(machine); } private: void appendEvents(const std::vector &events) { _outbox.insert(_outbox.end(), events.cbegin(), events.cend()); } void dispatch(const typename Time::type &t, const std::vector &events) { std::for_each(events.cbegin(), events.cend(), [t, this](const auto &e) { typename Types::state_machine_IDs_type::values key = static_cast(e.machine_id); auto it = _machines.find(key); if (it != _machines.end()) { typename Types::state_machine_type::Events events = it->second->transition(t, e); dispatch(t, events.internals); appendEvents(events.externals); } }); } std::map> _machines; external_events_type _outbox; typename Time::type _last_time{}; }; } #endif //ARTIS_STAR_ADDONS_UTILS_ROOT_STATE_MACHINE_HPP