Skip to content
Snippets Groups Projects
Commit d82d4d7c authored by Davide Mor's avatar Davide Mor
Browse files

[DependencyManager] Reverted back to using IDs

parent 59434fe5
Branches
No related tags found
1 merge request!269[DependencyManager] Reverted back to using IDs
Pipeline #8883 passed
......@@ -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;
}
}
......@@ -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
......
/* 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
......@@ -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;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment