/**
* @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