Program Listing for File linker.h
↰ Return to documentation for file (PrismEngine/src/linker.h)
#pragma once
#include <memory>
#include <typeindex>
#include <utility>
#include <vector>
#include <unordered_map>
namespace prism {
class Linker {
public:
Linker() = default;
~Linker();
template<typename A, typename B>
void link(A* a, B* b) {
if (!a || !b) return;
if (find<A, B>(a) != nullptr || find<B, A>(b) != nullptr) {
return;
}
insert_(a, typeid(B), b);
insert_(b, typeid(A), a);
}
template<typename A, typename B>
void unlink(A* a, B* b) {
if (!a || !b) return;
erase_(a, typeid(B), b);
erase_(b, typeid(A), a);
}
template<typename T>
void detach(T* obj) {
if (!obj) return;
std::vector<std::pair<void*, std::type_index>> targets;
targets.reserve(map_.size() / 2);
for (auto it = map_.begin(); it != map_.end(); ) {
if (it->first.ptr == obj) {
targets.emplace_back(it->second, it->first.target_type);
it = map_.erase(it);
}
else {
++it;
}
}
for (const auto& p : targets) {
erase_(p.first, typeid(T), obj);
}
}
template<typename A, typename B>
B* find(A* a) {
if (!a) return nullptr;
auto it = map_.find(Key{ a, typeid(B) });
if (it != map_.end()) {
return static_cast<B*>(it->second);
}
return nullptr;
}
void clear();
private:
struct Key {
void* ptr;
std::type_index target_type;
Key(void* p, std::type_index t) : ptr(p), target_type(t) {}
bool operator==(const Key& other) const {
return ptr == other.ptr && target_type == other.target_type;
}
};
struct KeyHash {
std::size_t operator()(const Key& k) const {
return std::hash<void*>()(k.ptr) ^
(std::hash<std::type_index>()(k.target_type) << 1);
}
};
std::unordered_map<Key, void*, KeyHash> map_;
void insert_(void* source, std::type_index target_type, void* target);
void erase_(void* source, std::type_index target_type, void* expected_target);
};
extern Linker linker;
}