2012-11-15 00:39:56 +01:00
|
|
|
#pragma once
|
2015-03-06 23:58:42 +01:00
|
|
|
|
|
|
|
|
#define ID_MANAGER_INCLUDED
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
// ID type
|
|
|
|
|
enum : u32
|
2014-07-26 05:31:46 +02:00
|
|
|
{
|
2015-05-27 05:11:59 +02:00
|
|
|
ID_TYPE_NONE = 0,
|
2014-07-26 05:31:46 +02:00
|
|
|
};
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
// Helper template to detect type
|
|
|
|
|
template<typename T> struct ID_type
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-05-27 05:11:59 +02:00
|
|
|
//static_assert(sizeof(T) == 0, "ID type not registered (use REG_ID_TYPE)");
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
static const u32 type = ID_TYPE_NONE; // default type
|
|
|
|
|
};
|
2014-01-19 04:14:11 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
class ID_data_t final
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
const std::shared_ptr<void> data;
|
|
|
|
|
const std::type_info& info;
|
|
|
|
|
const u32 type;
|
2015-07-04 21:23:10 +02:00
|
|
|
const u32 id;
|
2015-05-27 05:11:59 +02:00
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
template<typename T> force_inline ID_data_t(std::shared_ptr<T> data, u32 type, u32 id)
|
2015-05-28 21:13:35 +02:00
|
|
|
: data(std::move(data))
|
2015-05-27 05:11:59 +02:00
|
|
|
, info(typeid(T))
|
|
|
|
|
, type(type)
|
2015-07-04 21:23:10 +02:00
|
|
|
, id(id)
|
2014-04-25 18:57:00 +02:00
|
|
|
{
|
|
|
|
|
}
|
2014-04-15 16:12:15 +02:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
ID_data_t(const ID_data_t& right)
|
|
|
|
|
: data(right.data)
|
|
|
|
|
, info(right.info)
|
|
|
|
|
, type(right.type)
|
2015-07-04 21:23:10 +02:00
|
|
|
, id(right.id)
|
2015-07-01 00:25:52 +02:00
|
|
|
{
|
|
|
|
|
}
|
2015-03-06 23:10:04 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
ID_data_t& operator =(const ID_data_t& right) = delete;
|
2014-10-01 11:45:43 +02:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
ID_data_t(ID_data_t&& right)
|
2015-05-28 21:13:35 +02:00
|
|
|
: data(std::move(const_cast<std::shared_ptr<void>&>(right.data)))
|
2015-05-27 05:11:59 +02:00
|
|
|
, info(right.info)
|
|
|
|
|
, type(right.type)
|
2015-07-04 21:23:10 +02:00
|
|
|
, id(right.id)
|
2014-10-01 11:45:43 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
ID_data_t& operator =(ID_data_t&& other) = delete;
|
2012-11-15 00:39:56 +01:00
|
|
|
};
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
class ID_manager
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-03-15 14:26:01 +01:00
|
|
|
std::mutex m_mutex;
|
2014-01-19 04:14:11 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
std::unordered_map<u32, ID_data_t> m_id_map;
|
|
|
|
|
u32 m_cur_id = 1; // first ID
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
public:
|
2015-05-27 05:11:59 +02:00
|
|
|
// check if ID exists and has specified type
|
|
|
|
|
template<typename T> bool check_id(const u32 id)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-03-15 14:26:01 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
2014-01-19 04:14:11 +01:00
|
|
|
|
2015-03-10 15:42:08 +01:00
|
|
|
auto f = m_id_map.find(id);
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
return f != m_id_map.end() && f->second.info == typeid(T);
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
2014-01-19 04:14:11 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
// must be called from the constructor called through make() to get further ID of current object
|
2015-06-19 17:49:38 +02:00
|
|
|
u32 get_current_id()
|
2015-05-27 05:11:59 +02:00
|
|
|
{
|
|
|
|
|
// 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<std::mutex> lock(m_mutex, std::adopt_lock);
|
|
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
throw EXCEPTION("Current ID is not available");
|
2015-05-27 05:11:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m_cur_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void clear()
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-03-15 14:26:01 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
2014-01-19 04:14:11 +01:00
|
|
|
|
|
|
|
|
m_id_map.clear();
|
2015-05-27 05:11:59 +02:00
|
|
|
m_cur_id = 1; // first ID
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
2014-01-19 04:14:11 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
// add new ID of specified type with specified constructor arguments (returns object)
|
|
|
|
|
template<typename T, typename... Args, typename = std::enable_if_t<std::is_constructible<T, Args...>::value>> std::shared_ptr<T> make_ptr(Args&&... args)
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
|
|
|
|
|
const u32 type = ID_type<T>::type;
|
|
|
|
|
|
|
|
|
|
auto ptr = std::make_shared<T>(std::forward<Args>(args)...);
|
|
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
m_id_map.emplace(m_cur_id, ID_data_t(ptr, type, m_cur_id));
|
2015-07-01 00:25:52 +02:00
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
return m_cur_id++, std::move(ptr);
|
2015-07-01 00:25:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add new ID of specified type with specified constructor arguments (returns id)
|
|
|
|
|
template<typename T, typename... Args> std::enable_if_t<std::is_constructible<T, Args...>::value, u32> make(Args&&... args)
|
2015-03-12 20:02:02 +01:00
|
|
|
{
|
2015-03-15 14:26:01 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
2015-03-12 20:02:02 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
const u32 type = ID_type<T>::type;
|
2015-03-12 20:02:02 +01:00
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
m_id_map.emplace(m_cur_id, ID_data_t(std::make_shared<T>(std::forward<Args>(args)...), type, m_cur_id));
|
2014-01-19 04:14:11 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
return m_cur_id++;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
// load ID created with type Original, optionally static_cast to T
|
|
|
|
|
template<typename T, typename Orig = T> auto get(u32 id) -> decltype(std::shared_ptr<T>(static_cast<T*>(std::declval<Orig*>())))
|
2015-03-15 10:20:29 +01:00
|
|
|
{
|
2015-03-15 14:26:01 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
2015-03-15 10:20:29 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
auto f = m_id_map.find(id);
|
2015-03-15 10:20:29 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
if (f == m_id_map.end() || f->second.info != typeid(Orig))
|
2015-03-15 10:20:29 +01:00
|
|
|
{
|
2015-05-27 05:11:59 +02:00
|
|
|
return nullptr;
|
2015-03-15 10:20:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
return std::static_pointer_cast<T>(f->second.data);
|
2015-03-15 10:20:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
template<typename T> bool remove(u32 id)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-03-15 14:26:01 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-01-19 04:14:11 +01:00
|
|
|
auto item = m_id_map.find(id);
|
|
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
if (item == m_id_map.end() || item->second.info != typeid(T))
|
2015-03-12 20:02:02 +01:00
|
|
|
{
|
2014-07-26 05:31:46 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2015-03-12 20:02:02 +01:00
|
|
|
|
2014-01-19 04:14:11 +01:00
|
|
|
m_id_map.erase(item);
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-07-26 05:31:46 +02:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
template<typename T> u32 get_count()
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
|
|
|
|
|
u32 result = 0;
|
|
|
|
|
|
|
|
|
|
for (auto& v : m_id_map)
|
|
|
|
|
{
|
|
|
|
|
if (v.second.info == typeid(T))
|
|
|
|
|
{
|
|
|
|
|
result++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 get_count(u32 type)
|
2014-12-24 17:09:32 +01:00
|
|
|
{
|
2015-03-15 14:26:01 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
2014-12-24 17:09:32 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
u32 result = 0;
|
|
|
|
|
|
|
|
|
|
for (auto& v : m_id_map)
|
2014-12-24 17:09:32 +01:00
|
|
|
{
|
2015-05-27 05:11:59 +02:00
|
|
|
if (v.second.type == type)
|
|
|
|
|
{
|
|
|
|
|
result++;
|
|
|
|
|
}
|
2014-12-24 17:09:32 +01:00
|
|
|
}
|
2015-05-27 05:11:59 +02:00
|
|
|
|
|
|
|
|
return result;
|
2014-12-24 17:09:32 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
template<typename T> std::set<u32> get_IDs()
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
|
|
|
|
|
std::set<u32> result;
|
|
|
|
|
|
|
|
|
|
for (auto& v : m_id_map)
|
|
|
|
|
{
|
|
|
|
|
if (v.second.info == typeid(T))
|
|
|
|
|
{
|
|
|
|
|
result.insert(v.first);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::set<u32> get_IDs(u32 type)
|
2014-12-24 17:09:32 +01:00
|
|
|
{
|
2015-03-15 14:26:01 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
2014-12-24 17:09:32 +01:00
|
|
|
|
2015-05-27 05:11:59 +02:00
|
|
|
std::set<u32> result;
|
|
|
|
|
|
|
|
|
|
for (auto& v : m_id_map)
|
2014-12-24 17:09:32 +01:00
|
|
|
{
|
2015-05-27 05:11:59 +02:00
|
|
|
if (v.second.type == type)
|
|
|
|
|
{
|
|
|
|
|
result.insert(v.first);
|
|
|
|
|
}
|
2014-12-24 17:09:32 +01:00
|
|
|
}
|
2015-05-27 05:11:59 +02:00
|
|
|
|
|
|
|
|
return result;
|
2014-12-24 17:09:32 +01:00
|
|
|
}
|
2015-07-01 00:25:52 +02:00
|
|
|
|
|
|
|
|
template<typename T> std::vector<ID_data_t> get_data()
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
|
|
|
|
|
std::vector<ID_data_t> result;
|
|
|
|
|
|
|
|
|
|
for (auto& v : m_id_map)
|
|
|
|
|
{
|
|
|
|
|
if (v.second.info == typeid(T))
|
|
|
|
|
{
|
|
|
|
|
result.emplace_back(v.second);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<ID_data_t> get_data(u32 type)
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
|
|
|
|
|
std::vector<ID_data_t> result;
|
|
|
|
|
|
|
|
|
|
for (auto& v : m_id_map)
|
|
|
|
|
{
|
|
|
|
|
if (v.second.type == type)
|
|
|
|
|
{
|
|
|
|
|
result.emplace_back(v.second);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2014-02-23 17:52:52 +01:00
|
|
|
};
|