diff --git a/src/shared/utils/DependencyManager/DependencyManager.cpp b/src/shared/utils/DependencyManager/DependencyManager.cpp index df91e884219661e6dd620c72f1c2bf984c5eabfb..bec947184508f73c1147f97d6b5880126d84a2dc 100644 --- a/src/shared/utils/DependencyManager/DependencyManager.cpp +++ b/src/shared/utils/DependencyManager/DependencyManager.cpp @@ -22,10 +22,36 @@ #include "DependencyManager.h" +#include <cxxabi.h> #include <fmt/format.h> +#include <atomic> + using namespace Boardcore; +int32_t Boardcore::getNextDependencyId() +{ + static std::atomic<int32_t> NEXT_ID{0}; + + int32_t next_id = NEXT_ID; + while (next_id <= 256) + { + if (NEXT_ID.compare_exchange_weak(next_id, next_id + 1)) + return next_id; + } + + return -1; +} + +std::string demangleName(const char* name) +{ + char* demangled = abi::__cxa_demangle(name, nullptr, nullptr, nullptr); + std::string demangled2{demangled}; + std::free(demangled); + + return demangled2; +} + void DependencyManager::graphviz(std::ostream& os) { os << "digraph {" << std::endl; @@ -33,7 +59,7 @@ void DependencyManager::graphviz(std::ostream& os) // First print out all of the nodes for (auto& module : modules) { - os << fmt::format(" \"{}\"", module.first) << std::endl; + os << fmt::format(" \"{}\"", module.second.name) << std::endl; } // Then print out the arcs @@ -41,7 +67,8 @@ void DependencyManager::graphviz(std::ostream& os) { for (auto& dep : module.second.deps) { - os << fmt::format(" \"{}\" -> \"{}\"", module.first, dep) + os << fmt::format(" \"{}\" -> \"{}\"", module.second.name, + modules[dep].name) << std::endl; } } @@ -55,8 +82,8 @@ bool DependencyManager::inject() for (auto& module : modules) { - LOG_INFO(logger, "Configuring [{}]...", module.first); - DependencyInjector injector{*this, module}; + LOG_INFO(logger, "Configuring [{}]...", module.second.name); + DependencyInjector injector{*this, module.second}; module.second.injectable->inject(injector); } @@ -72,16 +99,21 @@ bool DependencyManager::inject() return load_success; } -bool DependencyManager::insertImpl(void* raw, Injectable* injectable, - std::string name) +bool DependencyManager::insertImpl(int32_t id, void* raw, + Injectable* injectable, const char* name) { - return modules.insert({std::move(name), ModuleInfo{raw, injectable, {}}}) + // Check that the ID is valid + if (id < 0) + return false; + + return modules + .insert({id, ModuleInfo{demangleName(name), raw, injectable, {}}}) .second; } -void* DependencyManager::getImpl(const std::string& name) +void* DependencyManager::getImpl(int32_t id) { - auto iter = modules.find(name); + auto iter = modules.find(id); if (iter == modules.end()) { return nullptr; @@ -92,21 +124,21 @@ void* DependencyManager::getImpl(const std::string& name) } } -void* DependencyInjector::getImpl(const std::string& name) +void* DependencyInjector::getImpl(int32_t id) { - void* ptr = manager.getImpl(name); + void* ptr = manager.getImpl(id); if (ptr == nullptr) { // Get failed, signal inject failure and log it manager.load_success = false; - LOG_ERR(logger, "[{}] requires [{}], which doesn't exist", info.first, - name); + LOG_ERR(logger, "[{}] requires a modules which doesn't exist", + info.name); return nullptr; } else { // Get successful, add it to the dependencies - info.second.deps.push_back(name); + info.deps.push_back(id); return ptr; } } diff --git a/src/shared/utils/DependencyManager/DependencyManager.h b/src/shared/utils/DependencyManager/DependencyManager.h index 5f65095b35be0a5d669a49e85e871d6e5ca35a99..8ce5153d41f98e232bd26b50ebec8c42abf71820 100644 --- a/src/shared/utils/DependencyManager/DependencyManager.h +++ b/src/shared/utils/DependencyManager/DependencyManager.h @@ -24,19 +24,34 @@ #include <diagnostic/PrintLogger.h> +#include <map> #include <numeric> #include <ostream> #include <string> #include <typeindex> #include <typeinfo> -#include <unordered_map> #include <vector> -#include "TypeName.h" - namespace Boardcore { +/** + * @brief Returns the next available id. + * + * @note THIS IS ONLY USED INTERNALLY BY getDependencyId(). + */ +int32_t getNextDependencyId(); + +/** + * @brief Get the ID associated with the given T type. + */ +template <typename T> +int32_t getDependencyId() +{ + static int32_t ID = getNextDependencyId(); + return ID; +} + class DependencyInjector; class DependencyManager; @@ -103,12 +118,13 @@ class DependencyManager private: struct ModuleInfo { + std::string name; //< Name of the type. void *raw; ///< Pointer to the dependency's concrete type, returned ///< when retrieving this dependency Injectable *injectable; ///< Pointer to the dependency as an ///< Injectable, needed for dynamic dispatching ///< of the inject method - std::vector<std::string> deps; ///< List of dependencies + std::vector<int32_t> deps; ///< List of dependencies }; public: @@ -126,9 +142,9 @@ public: std::is_base_of<Injectable, T>::value>> [[nodiscard]] bool insert(T *dependency) { - return insertImpl(reinterpret_cast<void *>(dependency), - static_cast<Injectable *>(dependency), - Boardcore::typeName<T>()); + return insertImpl( + getDependencyId<T>(), reinterpret_cast<void *>(dependency), + static_cast<Injectable *>(dependency), typeid(T).name()); } /** @@ -147,17 +163,17 @@ public: [[nodiscard]] bool inject(); private: - [[nodiscard]] bool insertImpl(void *raw, Injectable *injectable, - std::string name); + [[nodiscard]] bool insertImpl(int32_t id, void *raw, Injectable *injectable, + const char *name); - void *getImpl(const std::string &name); + void *getImpl(int32_t id); Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("DependencyManager"); bool load_success = true; // Maps from interface type name to ModuleInfo - std::unordered_map<std::string, ModuleInfo> modules; + std::map<int32_t, ModuleInfo> modules; }; /** @@ -168,9 +184,8 @@ class DependencyInjector friend class DependencyManager; private: - DependencyInjector( - DependencyManager &manager, - std::pair<const std::string, DependencyManager::ModuleInfo> &info) + DependencyInjector(DependencyManager &manager, + DependencyManager::ModuleInfo &info) : manager(manager), info(info) { } @@ -185,17 +200,17 @@ public: template <typename T> T *get() { - return reinterpret_cast<T *>(getImpl(Boardcore::typeName<T>())); + return reinterpret_cast<T *>(getImpl(getDependencyId<T>())); } private: - void *getImpl(const std::string &name); + void *getImpl(int32_t id); Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("DependencyManager"); DependencyManager &manager; - std::pair<const std::string, DependencyManager::ModuleInfo> &info; + DependencyManager::ModuleInfo &info; }; namespace DependencyManagerDetails diff --git a/src/shared/utils/DependencyManager/TypeName.h b/src/shared/utils/DependencyManager/TypeName.h deleted file mode 100644 index 0d7f10ff64c071919b2c55b1c08582c70fe06b63..0000000000000000000000000000000000000000 --- a/src/shared/utils/DependencyManager/TypeName.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (c) 2024 Skyward Experimental Rocketry - * Authors: Davide Mor - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include <string> - -namespace Boardcore -{ - -namespace TypeNameDetails -{ - -// This needs to be in its own namespace so that types in Boardcore:: don't get -// the namespace cut off - -template <typename T> -std::string typeName() -{ - - // taken from - // https://github.com/Manu343726/ctti/blob/master/include/ctti/detail/pretty_function.hpp - -#if defined(__clang__) -// clang required slightly different logic, but should be supported, keep it -// like this for now -#error "Clang does not yet support typeName" -#elif defined(__GNUC__) || defined(__GNUG__) -#define SKYWARD_PRETTY_FUNCTION __PRETTY_FUNCTION__ -#define SKYWARD_PRETTY_FUNCTION_PREFIX \ - "std::string Boardcore::TypeNameDetails::typeName() [with T = " -#define SKYWARD_PRETTY_FUNCTION_SUFFIX \ - "; std::string = std::__cxx11::basic_string<char>]" -#else -#error "Compiler does not support typeName" -#endif - -#define SKYWARD_PRETTY_FUNCTION_PREFIX_LEN \ - (sizeof(SKYWARD_PRETTY_FUNCTION_PREFIX) - 1) -#define SKYWARD_PRETTY_FUNCTION_SUFFIX_LEN \ - (sizeof(SKYWARD_PRETTY_FUNCTION_SUFFIX) - 1) - - std::string pretty_function{SKYWARD_PRETTY_FUNCTION}; - return std::string{ - pretty_function.begin() + SKYWARD_PRETTY_FUNCTION_PREFIX_LEN, - pretty_function.end() - SKYWARD_PRETTY_FUNCTION_SUFFIX_LEN}; - -#undef SKYWARD_PRETTY_FUNCTION -#undef SKYWARD_PRETTY_FUNCTION_PREFIX -#undef SKYWARD_PRETTY_FUNCTION_SUFFIX -#undef SKYWARD_PRETTY_FUNCTION_PREFIX_LEN -#undef SKYWARD_PRETTY_FUNCTION_SUFFIX_LEN -} - -} // namespace TypeNameDetails - -template <typename T> -std::string typeName() -{ - return TypeNameDetails::typeName<T>(); -} - -} // namespace Boardcore \ No newline at end of file diff --git a/src/tests/catch/test-dependencymanager.cpp b/src/tests/catch/test-dependencymanager.cpp index 04989e34eaf9b3e4047088ee96f478c96d7b7156..1b1691390bea7efc65c161bcaa331c17d165faeb 100644 --- a/src/tests/catch/test-dependencymanager.cpp +++ b/src/tests/catch/test-dependencymanager.cpp @@ -128,34 +128,8 @@ public: } }; -namespace Inner -{ -template <typename T, typename U> -struct Pair -{ -}; -} // namespace Inner - } // namespace Boardcore -TEST_CASE("DependencyManager - TypeName") -{ - - REQUIRE(Boardcore::typeName<Boardcore::A>() == "Boardcore::A"); - REQUIRE(Boardcore::typeName<Boardcore::B>() == "Boardcore::B"); - REQUIRE(Boardcore::typeName<Boardcore::CIface>() == "Boardcore::CIface"); - REQUIRE(Boardcore::typeName<Boardcore::C>() == "Boardcore::C"); - REQUIRE(Boardcore::typeName<Boardcore::D>() == "Boardcore::D"); - REQUIRE(Boardcore::typeName<Boardcore::E>() == "Boardcore::E"); - REQUIRE(Boardcore::typeName<Boardcore::F>() == "Boardcore::F"); - REQUIRE(Boardcore::typeName<Boardcore::G>() == "Boardcore::G"); - REQUIRE(Boardcore::typeName<Boardcore::H>() == "Boardcore::H"); - REQUIRE(Boardcore::typeName<Boardcore::I>() == "Boardcore::I"); - REQUIRE(Boardcore::typeName< - Boardcore::Inner::Pair<Boardcore::A, Boardcore::B>>() == - "Boardcore::Inner::Pair<Boardcore::A, Boardcore::B>"); -} - TEST_CASE("DependencyManager - Circular dependencies") { DependencyManager manager;