rpcsx/rpcs3/Emu/IdManager.h

456 lines
11 KiB
C
Raw Normal View History

#pragma once
2015-03-06 23:58:42 +01:00
#define ID_MANAGER_INCLUDED
// default traits for any arbitrary type
template<typename T> struct id_traits
{
// get next mapped id (may return 0 if out of IDs)
static u32 next_id(u32 raw_id) { return raw_id < 0x80000000 ? (raw_id + 1) & 0x7fffffff : 0; }
// convert "public" id to mapped id (may return 0 if invalid)
static u32 in_id(u32 id) { return id; }
// convert mapped id to "public" id
static u32 out_id(u32 raw_id) { return raw_id; }
};
class id_data_t final
{
public:
const std::shared_ptr<void> data;
2015-07-09 21:55:50 +02:00
const std::type_info& info;
const std::size_t hash;
template<typename T> force_inline id_data_t(std::shared_ptr<T> data)
2015-05-28 21:13:35 +02:00
: data(std::move(data))
2015-07-09 21:55:50 +02:00
, info(typeid(T))
, hash(typeid(T).hash_code())
2015-07-01 00:25:52 +02:00
{
}
2015-03-06 23:10:04 +01: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)))
, info(right.info)
2015-07-09 21:55:50 +02:00
, hash(right.hash)
{
}
};
// ID Manager
// 0 is invalid ID
// 1..0x7fffffff : general purpose IDs
// 0x80000000+ : reserved (may be used through id_traits specializations)
namespace idm
{
// can be called from the constructor called through make() or make_ptr() to get the ID of currently created object
inline u32 get_last_id()
{
thread_local extern u32 g_tls_last_id;
return g_tls_last_id;
}
// reinitialize ID manager
void clear();
// check if ID of specified type exists
template<typename T> bool check(u32 id)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
const auto found = g_id_map.find(id_traits<T>::in_id(id));
2015-03-10 15:42:08 +01:00
return found != g_id_map.end() && found->second.info == typeid(T);
}
// check if ID exists and return its type or nullptr
inline const std::type_info* get_type(u32 raw_id)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
const auto found = g_id_map.find(raw_id);
return found == g_id_map.end() ? nullptr : &found->second.info;
2015-07-08 17:01:59 +02:00
}
// add new ID of specified type with specified constructor arguments (returns object or nullptr)
template<typename T, typename... Args> std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> make_ptr(Args&&... args)
2015-07-01 00:25:52 +02:00
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
extern u32 g_last_raw_id;
thread_local extern u32 g_tls_last_id;
2015-07-01 00:25:52 +02:00
std::lock_guard<std::mutex> lock(g_id_mutex);
2015-07-01 00:25:52 +02:00
u32 raw_id = g_last_raw_id;
while ((raw_id = id_traits<T>::next_id(raw_id)))
{
if (g_id_map.find(raw_id) != g_id_map.end()) continue;
g_tls_last_id = id_traits<T>::out_id(raw_id);
auto ptr = std::make_shared<T>(std::forward<Args>(args)...);
2015-07-01 00:25:52 +02:00
g_id_map.emplace(raw_id, id_data_t(ptr));
if (raw_id < 0x80000000) g_last_raw_id = raw_id;
return ptr;
}
2015-07-01 00:25:52 +02:00
return nullptr;
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
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
extern u32 g_last_raw_id;
thread_local extern u32 g_tls_last_id;
2015-03-12 20:02:02 +01:00
std::lock_guard<std::mutex> lock(g_id_mutex);
2015-03-12 20:02:02 +01:00
u32 raw_id = g_last_raw_id;
while ((raw_id = id_traits<T>::next_id(raw_id)))
{
if (g_id_map.find(raw_id) != g_id_map.end()) continue;
g_tls_last_id = id_traits<T>::out_id(raw_id);
g_id_map.emplace(raw_id, id_data_t(std::make_shared<T>(std::forward<Args>(args)...)));
if (raw_id < 0x80000000) g_last_raw_id = raw_id;
return id_traits<T>::out_id(raw_id);
}
throw EXCEPTION("Out of IDs");
}
// add new ID for an existing object provided (don't use for initial object creation)
template<typename T> u32 import(const std::shared_ptr<T>& ptr)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
extern u32 g_last_raw_id;
thread_local extern u32 g_tls_last_id;
std::lock_guard<std::mutex> lock(g_id_mutex);
u32 raw_id = g_last_raw_id;
while ((raw_id = id_traits<T>::next_id(raw_id)))
{
if (g_id_map.find(raw_id) != g_id_map.end()) continue;
g_tls_last_id = id_traits<T>::out_id(raw_id);
g_id_map.emplace(raw_id, id_data_t(ptr));
if (raw_id < 0x80000000) g_last_raw_id = raw_id;
return id_traits<T>::out_id(raw_id);
}
throw EXCEPTION("Out of IDs");
}
// get ID of specified type
template<typename T> std::shared_ptr<T> get(u32 id)
2015-03-15 10:20:29 +01:00
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
2015-03-15 10:20:29 +01:00
const auto found = g_id_map.find(id_traits<T>::in_id(id));
2015-03-15 10:20:29 +01:00
if (found == g_id_map.end() || found->second.info != typeid(T))
2015-03-15 10:20:29 +01:00
{
return nullptr;
2015-03-15 10:20:29 +01:00
}
return std::static_pointer_cast<T>(found->second.data);
2015-03-15 10:20:29 +01:00
}
2015-08-06 15:05:33 +02:00
// get all IDs of specified type T (unsorted)
template<typename T> std::vector<std::shared_ptr<T>> get_all()
2015-07-08 17:01:59 +02:00
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
2015-07-08 17:01:59 +02:00
std::vector<std::shared_ptr<T>> result;
const std::size_t hash = typeid(T).hash_code();
2015-07-08 17:01:59 +02:00
for (auto& v : g_id_map)
2015-07-08 17:01:59 +02:00
{
if (v.second.hash == hash && v.second.info == typeid(T))
2015-07-08 17:01:59 +02:00
{
result.emplace_back(std::static_pointer_cast<T>(v.second.data));
}
}
return result;
}
// remove ID created with type T
template<typename T> bool remove(u32 id)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
const auto found = g_id_map.find(id_traits<T>::in_id(id));
if (found == g_id_map.end() || found->second.info != typeid(T))
{
return false;
}
g_id_map.erase(found);
return true;
}
// remove ID created with type T and return the object
template<typename T> std::shared_ptr<T> withdraw(u32 id)
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
const auto found = g_id_map.find(id_traits<T>::in_id(id));
if (found == g_id_map.end() || found->second.info != typeid(T))
{
return nullptr;
}
auto ptr = std::static_pointer_cast<T>(found->second.data);
g_id_map.erase(found);
return ptr;
}
2015-07-01 00:25:52 +02:00
template<typename T> u32 get_count()
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
2015-07-01 00:25:52 +02:00
u32 result = 0;
2015-07-08 17:01:59 +02:00
const std::size_t hash = typeid(T).hash_code();
for (auto& v : g_id_map)
2015-07-01 00:25:52 +02:00
{
2015-07-09 21:55:50 +02:00
if (v.second.hash == hash && v.second.info == typeid(T))
2015-07-01 00:25:52 +02:00
{
result++;
}
}
return result;
}
// get sorted ID list of specified type
template<typename T> std::set<u32> get_set()
2015-07-01 00:25:52 +02:00
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
std::lock_guard<std::mutex> lock(g_id_mutex);
2015-07-01 00:25:52 +02:00
std::set<u32> result;
2015-07-08 17:01:59 +02:00
const std::size_t hash = typeid(T).hash_code();
for (auto& v : g_id_map)
2015-07-01 00:25:52 +02:00
{
2015-07-09 21:55:50 +02:00
if (v.second.hash == hash && v.second.info == typeid(T))
2015-07-01 00:25:52 +02:00
{
result.insert(id_traits<T>::out_id(v.first));
2015-07-01 00:25:52 +02:00
}
}
return result;
}
// get sorted ID map (ID value -> ID data) of specified type
template<typename T> std::map<u32, std::shared_ptr<T>> get_map()
2014-12-24 17:09:32 +01:00
{
extern std::mutex g_id_mutex;
extern std::unordered_map<u32, id_data_t> g_id_map;
2014-12-24 17:09:32 +01:00
std::lock_guard<std::mutex> lock(g_id_mutex);
std::map<u32, std::shared_ptr<T>> result;
2015-07-01 00:25:52 +02:00
2015-07-08 17:01:59 +02:00
const std::size_t hash = typeid(T).hash_code();
for (auto& v : g_id_map)
2015-07-01 00:25:52 +02:00
{
2015-07-09 21:55:50 +02:00
if (v.second.hash == hash && v.second.info == typeid(T))
2015-07-01 00:25:52 +02:00
{
result[id_traits<T>::out_id(v.first)] = std::static_pointer_cast<T>(v.second.data);
2015-07-01 00:25:52 +02:00
}
}
return result;
}
2015-08-06 15:05:33 +02:00
}
// Fixed Object Manager
// allows to manage shared objects of any specified type, but only one object per type;
// object are deleted when the emulation is stopped
namespace fxm
{
// reinitialize
void clear();
// add fixed object of specified type only if it doesn't exist (one unique object per type may exist)
template<typename T, typename... Args> std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> make(Args&&... args)
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_fx_mutex);
const auto found = g_fx_map.find(typeid(T));
// only if object of this type doesn't exist
if (found == g_fx_map.end())
{
auto ptr = std::make_shared<T>(std::forward<Args>(args)...);
g_fx_map.emplace(typeid(T), ptr);
return std::move(ptr);
}
return nullptr;
}
2015-08-06 17:55:19 +02:00
// add fixed object of specified type, replacing previous one if it exists
template<typename T, typename... Args> std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> make_always(Args&&... args)
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_fx_mutex);
auto ptr = std::make_shared<T>(std::forward<Args>(args)...);
g_fx_map[typeid(T)] = ptr;
return ptr;
}
2015-08-10 21:39:52 +02:00
// get fixed object of specified type (always returns an object, it's created if it doesn't exist)
template<typename T, typename... Args> std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> get_always(Args&&... args)
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_fx_mutex);
const auto found = g_fx_map.find(typeid(T));
if (found == g_fx_map.end())
{
auto ptr = std::make_shared<T>(std::forward<Args>(args)...);
g_fx_map[typeid(T)] = ptr;
return ptr;
}
return std::static_pointer_cast<T>(found->second);
}
2015-08-06 15:05:33 +02:00
// check whether the object exists
template<typename T> bool check()
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_fx_mutex);
return g_fx_map.find(typeid(T)) != g_fx_map.end();
}
2015-08-10 21:39:52 +02:00
// get fixed object of specified type (returns nullptr if it doesn't exist)
2015-08-06 15:05:33 +02:00
template<typename T> std::shared_ptr<T> get()
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_fx_mutex);
const auto found = g_fx_map.find(typeid(T));
if (found == g_fx_map.end())
{
return nullptr;
}
return std::static_pointer_cast<T>(found->second);
}
// remove fixed object created with type T
template<typename T> bool remove()
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_fx_mutex);
const auto found = g_fx_map.find(typeid(T));
if (found == g_fx_map.end())
{
return false;
}
return g_fx_map.erase(found), true;
}
2015-08-06 17:55:19 +02:00
// remove fixed object created with type T and return it
template<typename T> std::shared_ptr<T> withdraw()
{
extern std::mutex g_fx_mutex;
extern std::unordered_map<std::type_index, std::shared_ptr<void>> g_fx_map;
std::lock_guard<std::mutex> lock(g_fx_mutex);
const auto found = g_fx_map.find(typeid(T));
if (found == g_fx_map.end())
{
return nullptr;
}
auto ptr = std::static_pointer_cast<T>(std::move(found->second));
return g_fx_map.erase(found), ptr;
}
2015-08-06 15:05:33 +02:00
}