diff --git a/include/fggl/ds/graph.hpp b/include/fggl/ds/graph.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f88ff5c61adf292b1e43beffc2b9c64adbdb747d --- /dev/null +++ b/include/fggl/ds/graph.hpp @@ -0,0 +1,142 @@ +/* + * This file is part of FGGL. + * + * FGGL 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. + * + * FGGL 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 FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 25/03/23. +// + +#ifndef FGGL_DS_GRAPH_HPP +#define FGGL_DS_GRAPH_HPP + +#include <map> +#include <vector> +#include <queue> +#include <stack> +#include <set> + +namespace fggl::ds { + + template<typename T> + class DirectedGraph { + public: + + /** + * Add a single edge to the graph. + * + * If the entry does not already exist, this will create the entry before adding the dependencies to it. + * If the entry already exists, this will append the provided dependencies to its existing list. + * + * @param start the entry which depends something else + * @param end the thing it depends on + */ + inline void addEdge(T start, const T end) { + m_edges[start].push_back(end); + m_edges[end]; + } + + /** + * Add a single vertex to the graph. + */ + inline void addVertex(T vertex) { + m_edges[vertex]; + } + + /** + * Add a series of dependencies for an entry. + * + * If the entry does not already exist, this will create the entry before adding the dependencies to it. + * If the entry already exists, this will append the provided dependencies to its existing list. + * + * @param name the entry having dependencies added + * @param dependencies the things it depends on + */ + void addEdges(const T &name, const std::vector<T> &dependencies) { + auto existing = m_edges.find(name); + if (existing == m_edges.end()) { + m_edges[name] = dependencies; + } else { + existing->second.insert(existing->second.end(), dependencies.begin(), dependencies.end()); + } + } + + /** + * Clear all currently stored dependencies. + * + * This method will result in the dependency graph being empty, with no known modules. + */ + inline void clear() { + m_edges.clear(); + } + + inline auto begin() const { + return m_edges.begin(); + } + + inline auto end() const { + return m_edges.end(); + } + + bool getOrder(std::stack<T> &stack) { + std::set<T> visited{}; + + for (const auto &module : m_edges) { + if (!visited.contains(module.first)) { + sortUtil(module.first, visited, stack); + } + } + + return true; + } + + bool getOrderRev(std::queue<T> &stack) { + std::set<T> visited{}; + + for (const auto &module : m_edges) { + if (!visited.contains(module.first)) { + sortUtilRev(module.first, visited, stack); + } + } + + return true; + } + + private: + std::map<T, std::vector<T>> m_edges; + + void sortUtil(T idx, std::set<T> &visited, std::stack<T> &stack) { + visited.emplace(idx); + + for (auto dep : m_edges.at(idx)) { + if (!visited.contains(dep)) + sortUtil(dep, visited, stack); + } + + stack.push(idx); + } + + void sortUtilRev(T idx, std::set<T> &visited, std::queue<T> &stack) { + visited.emplace(idx); + + for (auto dep : m_edges.at(idx)) { + if (!visited.contains(dep)) + sortUtilRev(dep, visited, stack); + } + + stack.push(idx); + } + }; + +} // namespace fggl::ds + +#endif //FGGL_DS_GRAPH_HPP diff --git a/include/fggl/modules/manager.hpp b/include/fggl/modules/manager.hpp index 522553a05b0334e9ecb760719fab006488dc725c..48acb0c2d8aa6aaa49d76cc3c8bfbdcf49b3cc4d 100644 --- a/include/fggl/modules/manager.hpp +++ b/include/fggl/modules/manager.hpp @@ -21,6 +21,7 @@ #include "fggl/modules/module.hpp" #include "fggl/debug/logging.hpp" +#include "fggl/ds/graph.hpp" #include <queue> #include <vector> @@ -31,108 +32,6 @@ namespace fggl::modules { - /** - * A class used for representing a Directed Acyclic Graph. - * - * This class is mostly used for establishing the loading order of classes for module loading. - * - * @tparam T the type being represented - */ - template<typename T> - class DependencyGraph { - public: - DependencyGraph() = default; - - /** - * Clear all currently stored dependencies. - * - * This method will result in the dependency graph being empty, with no known modules. - */ - void clear() { - m_dependencies.clear(); - } - - /** - * Add a series of dependencies for an entry. - * - * If the entry does not already exist, this will create the entry before adding the dependencies to it. - * If the entry already exists, this will append the provided dependencies to its existing list. - * - * @param name the entry having dependencies added - * @param dependencies the things it depends on - */ - void addAll(const T &name, const std::vector<T> &dependencies) { - auto existing = m_dependencies.find(name); - if (existing == m_dependencies.end()) { - m_dependencies[name] = dependencies; - } else { - existing->second.insert(existing->second.end(), dependencies.begin(), dependencies.end()); - } - } - - /** - * Add a single dependency to the graph. - * - * If the entry does not already exist, this will create the entry before adding the dependencies to it. - * If the entry already exists, this will append the provided dependencies to its existing list. - * - * @param name the entry which depends something else - * @param depends the thing it depends on - */ - void add(const T &name, const T &depends) { - m_dependencies[name].push_back(depends); - } - - bool getOrder(std::stack<T> &stack) { - std::set<T> visited{}; - - for (const auto &module : m_dependencies) { - if (!visited.contains(module.first)) { - sortUtil(module.first, visited, stack); - } - } - - return true; - } - - bool getOrderRev(std::queue<T> &stack) { - std::set<T> visited{}; - - for (const auto &module : m_dependencies) { - if (!visited.contains(module.first)) { - sortUtilRev(module.first, visited, stack); - } - } - - return true; - } - - private: - std::map<T, std::vector<T>> m_dependencies; - - void sortUtil(T idx, std::set<T> &visited, std::stack<T> &stack) { - visited.emplace(idx); - - for (auto dep : m_dependencies.at(idx)) { - if (!visited.contains(dep)) - sortUtil(dep, visited, stack); - } - - stack.push(idx); - } - - void sortUtilRev(T idx, std::set<T> &visited, std::queue<T> &stack) { - visited.emplace(idx); - - for (auto dep : m_dependencies.at(idx)) { - if (!visited.contains(dep)) - sortUtilRev(dep, visited, stack); - } - - stack.push(idx); - } - }; - /** * Store and initialise modules present in the engine. * @@ -191,7 +90,7 @@ namespace fggl::modules { // resolve links between modules for (auto &moduleItr : m_modules) { if (moduleItr.second.depends.empty()) { - m_dependencies.addAll(moduleItr.first, {}); + m_dependencies.addVertex(moduleItr.first); continue; } @@ -207,7 +106,7 @@ namespace fggl::modules { return false; } - m_dependencies.add(moduleItr.first, provider->second); + m_dependencies.addEdge(moduleItr.first, provider->second); } } return true; @@ -267,7 +166,7 @@ namespace fggl::modules { bool m_locked = false; Services m_services; std::map<ModuleIdentifier, Config> m_modules; - DependencyGraph<ModuleIdentifier> m_dependencies; + ds::DirectedGraph<ModuleIdentifier> m_dependencies; std::map<ServiceName, ModuleIdentifier> m_serviceProviders; }; diff --git a/include/fggl/modules/service.hpp b/include/fggl/modules/service.hpp index a1b679b3a4bd874594d4f63b7d9bdb28d8486f29..75a42606de64c5b0e350a8c362ada2898e8b2659 100644 --- a/include/fggl/modules/service.hpp +++ b/include/fggl/modules/service.hpp @@ -43,7 +43,6 @@ namespace fggl::modules { public: template<ServiceType Svc, Derived<Svc> Impl, typename ...Args> void bind(Args... args) { - static_assert(std::is_base_of_v<Svc, Impl>, "Service type must be assignable from implementation type"); m_services[Svc::service] = std::make_shared<Impl>(args...); } @@ -72,4 +71,6 @@ namespace fggl::modules { } // namespace fggl::modules + + #endif //FGGL_MODULES_SERVICE_HPP