#pragma once #define ID_MANAGER_INCLUDED // ID type enum : u32 { ID_TYPE_NONE = 0, }; // Helper template to detect type template struct ID_type { //static_assert(sizeof(T) == 0, "ID type not registered (use REG_ID_TYPE)"); static const u32 type = ID_TYPE_NONE; // default type }; class ID_data_t final { public: const std::shared_ptr data; const std::type_info& info; const std::size_t hash; const u32 type; const u32 id; template force_inline ID_data_t(std::shared_ptr data, u32 type, u32 id) : data(std::move(data)) , info(typeid(T)) , hash(typeid(T).hash_code()) , type(type) , id(id) { } ID_data_t(const ID_data_t& right) : data(right.data) , info(right.info) , hash(right.hash) , type(right.type) , id(right.id) { } ID_data_t& operator =(const ID_data_t& right) = delete; ID_data_t(ID_data_t&& right) : data(std::move(const_cast&>(right.data))) , info(right.info) , hash(right.hash) , type(right.type) , id(right.id) { } ID_data_t& operator =(ID_data_t&& other) = delete; }; class ID_manager { std::mutex m_mutex; std::unordered_map m_id_map; u32 m_cur_id = 1; // first ID public: // check if ID exists and has specified type template bool check_id(u32 id) { std::lock_guard lock(m_mutex); auto f = m_id_map.find(id); return f != m_id_map.end() && f->second.info == typeid(T); } // check if ID exists and has specified type bool check_id(u32 id, u32 type) { std::lock_guard lock(m_mutex); auto f = m_id_map.find(id); return f != m_id_map.end() && f->second.type == type; } // must be called from the constructor called through make() to get further ID of current object u32 get_current_id() { // if called correctly from make(), the mutex is locked // if called illegally, the mutex is unlocked with high probability (wrong ID is returned otherwise) if (m_mutex.try_lock()) { // schedule unlocking std::lock_guard lock(m_mutex, std::adopt_lock); throw EXCEPTION("Current ID is not available"); } return m_cur_id; } void clear() { std::lock_guard lock(m_mutex); m_id_map.clear(); m_cur_id = 1; // first ID } // add new ID of specified type with specified constructor arguments (returns object) template::value>> std::shared_ptr make_ptr(Args&&... args) { std::lock_guard lock(m_mutex); const u32 type = ID_type::type; auto ptr = std::make_shared(std::forward(args)...); m_id_map.emplace(m_cur_id, ID_data_t(ptr, type, m_cur_id)); return m_cur_id++, std::move(ptr); } // add new ID of specified type with specified constructor arguments (returns id) template std::enable_if_t::value, u32> make(Args&&... args) { std::lock_guard lock(m_mutex); const u32 type = ID_type::type; m_id_map.emplace(m_cur_id, ID_data_t(std::make_shared(std::forward(args)...), type, m_cur_id)); return m_cur_id++; } // load ID created with type Orig, optionally static_cast to T template auto get(u32 id) -> decltype(std::shared_ptr(static_cast(std::declval()))) { std::lock_guard lock(m_mutex); auto f = m_id_map.find(id); if (f == m_id_map.end() || f->second.info != typeid(Orig)) { return nullptr; } return std::static_pointer_cast(f->second.data); } // load all IDs created with type Orig, optionally static_cast to T template auto get_all() -> std::vector(static_cast(std::declval())))> { std::lock_guard lock(m_mutex); std::vector> result; const std::size_t hash = typeid(Orig).hash_code(); for (auto& v : m_id_map) { if (v.second.hash == hash && v.second.info == typeid(Orig)) { result.emplace_back(std::static_pointer_cast(v.second.data)); } } return result; } template bool remove(u32 id) { std::lock_guard lock(m_mutex); auto item = m_id_map.find(id); if (item == m_id_map.end() || item->second.info != typeid(T)) { return false; } m_id_map.erase(item); return true; } template u32 get_count() { std::lock_guard lock(m_mutex); u32 result = 0; const std::size_t hash = typeid(T).hash_code(); for (auto& v : m_id_map) { if (v.second.hash == hash && v.second.info == typeid(T)) { result++; } } return result; } u32 get_count(u32 type) { std::lock_guard lock(m_mutex); u32 result = 0; for (auto& v : m_id_map) { if (v.second.type == type) { result++; } } return result; } // get sorted ID list template std::set get_IDs() { std::lock_guard lock(m_mutex); std::set result; const std::size_t hash = typeid(T).hash_code(); for (auto& v : m_id_map) { if (v.second.hash == hash && v.second.info == typeid(T)) { result.insert(v.first); } } return result; } // get sorted ID list std::set get_IDs(u32 type) { std::lock_guard lock(m_mutex); std::set result; for (auto& v : m_id_map) { if (v.second.type == type) { result.insert(v.first); } } return result; } template std::vector get_data() { std::lock_guard lock(m_mutex); std::vector result; const std::size_t hash = typeid(T).hash_code(); for (auto& v : m_id_map) { if (v.second.hash == hash && v.second.info == typeid(T)) { result.emplace_back(v.second); } } return result; } std::vector get_data(u32 type) { std::lock_guard lock(m_mutex); std::vector result; for (auto& v : m_id_map) { if (v.second.type == type) { result.emplace_back(v.second); } } return result; } };