rpcsx/rpcs3/Emu/IdManager.h

436 lines
10 KiB
C
Raw Normal View History

#pragma once
2015-03-06 23:58:42 +01:00
#define ID_MANAGER_INCLUDED
2015-11-26 09:06:29 +01:00
// TODO: make id_aux_initialize and id_aux_finalize safer against a possible ODR violation
2015-11-26 09:06:29 +01:00
// Function called after the successfull creation of an ID (does nothing by default, provide an overload)
inline void id_aux_initialize(void*)
{
;
}
2015-11-26 09:06:29 +01:00
// Function called after the ID removal (does nothing by default, provide an overload)
inline void id_aux_finalize(void*)
{
2015-11-26 09:06:29 +01:00
;
}
2015-11-26 09:06:29 +01:00
// Type-erased id_aux_* function type
using id_aux_func_t = void(*)(void*);
template<typename T>
struct id_type_info_t
{
2015-11-26 09:06:29 +01:00
static const auto size = sizeof(T); // forbid forward declarations
2015-11-26 09:06:29 +01:00
static const id_aux_func_t on_remove;
};
2015-11-26 09:06:29 +01:00
// Type-erased finalization function
template<typename T>
const id_aux_func_t id_type_info_t<T>::on_remove = [](void* ptr)
{
return id_aux_finalize(static_cast<T*>(ptr));
};
2015-11-26 09:06:29 +01:00
using id_type_index_t = const id_aux_func_t*;
// Get a unique pointer to the on_remove value (will be unique for each type)
template<typename T>
inline constexpr id_type_index_t get_id_type_index()
{
2015-11-26 09:06:29 +01:00
return &id_type_info_t<T>::on_remove;
}
// Default ID traits for any arbitrary type
template<typename T>
struct id_traits
{
static const auto size = sizeof(T); // forbid forward declarations
// 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; }
};
// ID Manager
// 0 is invalid ID
// 1..0x7fffffff : general purpose IDs
// 0x80000000+ : reserved (may be used through id_traits specializations)
namespace idm
{
2015-11-26 09:06:29 +01:00
struct id_data_t final
{
std::shared_ptr<void> data;
const std::type_info* info;
id_type_index_t type_index;
template<typename T> id_data_t(const std::shared_ptr<T>& data)
: data(data)
, info(&typeid(T))
, type_index(get_id_type_index<T>())
{
}
};
2015-11-26 09:06:29 +01:00
using map_t = std::unordered_map<u32, id_data_t>;
2015-11-26 09:06:29 +01:00
// Can be called from the constructor called through make() or make_ptr() to get the ID of the object being created
inline u32 get_last_id()
{
2015-11-26 09:06:29 +01:00
extern thread_local u32 g_tls_last_id;
return g_tls_last_id;
}
2015-11-26 09:06:29 +01:00
// Remove all objects
void clear();
2015-11-26 09:06:29 +01:00
// Internal
bool check(u32 in_id, id_type_index_t type);
2015-11-26 09:06:29 +01:00
// Check if an ID of specified type exists
template<typename T>
bool check(u32 id)
{
2015-11-26 09:06:29 +01:00
return check(id_traits<T>::in_id(id), get_id_type_index<T>());
}
2015-11-26 09:06:29 +01:00
// Check if an ID exists and return its type or nullptr
const std::type_info* get_type(u32 raw_id);
2015-11-26 09:06:29 +01:00
// Internal
template<typename T, typename Ptr>
std::shared_ptr<T> add(Ptr&& get_ptr)
2015-07-01 00:25:52 +02:00
{
2015-11-26 09:06:29 +01:00
extern std::mutex g_mutex;
extern idm::map_t g_map;
extern u32 g_last_raw_id;
extern thread_local u32 g_tls_last_id;
std::lock_guard<std::mutex> lock(g_mutex);
for (u32 raw_id = g_last_raw_id; (raw_id = id_traits<T>::next_id(raw_id)); /**/)
{
if (g_map.find(raw_id) != g_map.end()) continue;
g_tls_last_id = id_traits<T>::out_id(raw_id);
2015-11-26 09:06:29 +01:00
std::shared_ptr<T> ptr = get_ptr();
2015-07-01 00:25:52 +02:00
g_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
}
2015-11-26 09:06:29 +01:00
// Add a 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-03-12 20:02:02 +01:00
{
2015-11-26 09:06:29 +01:00
if (auto ptr = add<T>(WRAP_EXPR(std::make_shared<T>(std::forward<Args>(args)...))))
{
2015-11-26 09:06:29 +01:00
id_aux_initialize(ptr.get());
return ptr;
}
2015-11-26 09:06:29 +01:00
return nullptr;
}
2015-11-26 09:06:29 +01:00
// Add a 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-11-26 09:06:29 +01:00
if (auto ptr = add<T>(WRAP_EXPR(std::make_shared<T>(std::forward<Args>(args)...))))
{
2015-11-26 09:06:29 +01:00
id_aux_initialize(ptr.get());
return get_last_id();
}
2015-11-26 09:06:29 +01:00
throw EXCEPTION("Out of IDs ('%s')", typeid(T).name());
}
2015-11-26 09:06:29 +01:00
// Add a new ID for an existing object provided (returns new id)
template<typename T>
u32 import(const std::shared_ptr<T>& ptr)
2015-03-15 10:20:29 +01:00
{
2015-11-26 09:06:29 +01:00
static const auto size = sizeof(T); // forbid forward declarations
2015-11-26 09:06:29 +01:00
if (add<T>(WRAP_EXPR(ptr)))
2015-03-15 10:20:29 +01:00
{
2015-11-26 09:06:29 +01:00
id_aux_initialize(ptr.get());
return get_last_id();
2015-03-15 10:20:29 +01:00
}
2015-11-26 09:06:29 +01:00
throw EXCEPTION("Out of IDs ('%s')", typeid(T).name());
2015-03-15 10:20:29 +01:00
}
2015-11-26 09:06:29 +01:00
// Internal
std::shared_ptr<void> get(u32 in_id, id_type_index_t type);
// Get ID of specified type
template<typename T>
std::shared_ptr<T> get(u32 id)
2015-07-08 17:01:59 +02:00
{
2015-11-26 09:06:29 +01:00
return std::static_pointer_cast<T>(get(id_traits<T>::in_id(id), get_id_type_index<T>()));
}
2015-07-08 17:01:59 +02:00
2015-11-26 09:06:29 +01:00
// Internal
idm::map_t get_all(id_type_index_t type);
2015-07-08 17:01:59 +02:00
2015-11-26 09:06:29 +01:00
// Get all IDs of specified type T (unsorted)
template<typename T>
std::vector<std::shared_ptr<T>> get_all()
{
std::vector<std::shared_ptr<T>> result;
2015-07-08 17:01:59 +02:00
2015-11-26 09:06:29 +01:00
for (auto& id : get_all(get_id_type_index<T>()))
2015-07-08 17:01:59 +02:00
{
2015-11-26 09:06:29 +01:00
result.emplace_back(std::static_pointer_cast<T>(id.second.data));
2015-07-08 17:01:59 +02:00
}
return result;
}
2015-11-26 09:06:29 +01:00
std::shared_ptr<void> withdraw(u32 in_id, id_type_index_t type);
2015-11-26 09:06:29 +01:00
// Remove the ID created with type T
template<typename T>
bool remove(u32 id)
{
if (auto ptr = withdraw(id_traits<T>::in_id(id), get_id_type_index<T>()))
{
2015-11-26 09:06:29 +01:00
id_aux_finalize(static_cast<T*>(ptr.get()));
2015-11-26 09:06:29 +01:00
return true;
}
2015-11-26 09:06:29 +01:00
return false;
}
2015-11-26 09:06:29 +01:00
// Remove the ID created with type T and return it
template<typename T>
std::shared_ptr<T> withdraw(u32 id)
{
2015-11-26 09:06:29 +01:00
if (auto ptr = std::static_pointer_cast<T>(withdraw(id_traits<T>::in_id(id), get_id_type_index<T>())))
{
2015-11-26 09:06:29 +01:00
id_aux_finalize(ptr.get());
2015-11-26 09:06:29 +01:00
return ptr;
}
2015-11-26 09:06:29 +01:00
return nullptr;
}
2015-11-26 09:06:29 +01:00
u32 get_count(id_type_index_t type);
2015-07-01 00:25:52 +02:00
2015-11-26 09:06:29 +01:00
template<typename T>
u32 get_count()
{
return get_count(get_id_type_index<T>());
2015-07-01 00:25:52 +02:00
}
2015-11-26 09:06:29 +01:00
// Get sorted list of all IDs of specified type
template<typename T>
std::set<u32> get_set()
2015-07-01 00:25:52 +02:00
{
std::set<u32> result;
2015-11-26 09:06:29 +01:00
for (auto& id : get_all(get_id_type_index<T>()))
2015-07-01 00:25:52 +02:00
{
2015-11-26 09:06:29 +01:00
result.emplace(id_traits<T>::out_id(id.first));
2015-07-01 00:25:52 +02:00
}
return result;
}
2015-11-26 09:06:29 +01:00
// Get sorted map (ID value -> ID data) of all IDs of specified type
template<typename T>
std::map<u32, std::shared_ptr<T>> get_map()
2014-12-24 17:09:32 +01:00
{
std::map<u32, std::shared_ptr<T>> result;
2015-07-01 00:25:52 +02:00
2015-11-26 09:06:29 +01:00
for (auto& id : get_all(get_id_type_index<T>()))
2015-07-01 00:25:52 +02:00
{
2015-11-26 09:06:29 +01:00
result[id_traits<T>::out_id(id.first)] = std::static_pointer_cast<T>(id.second.data);
2015-07-01 00:25:52 +02:00
}
return result;
}
2015-11-26 09:06:29 +01:00
}
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
{
2015-11-26 09:06:29 +01:00
using map_t = std::unordered_map<id_type_index_t, std::shared_ptr<void>>;
2015-11-26 09:06:29 +01:00
// Remove all objects
void clear();
2015-11-26 09:06:29 +01:00
// Internal (returns old and new pointers)
template<typename T, bool Always, typename Ptr>
std::pair<std::shared_ptr<T>, std::shared_ptr<T>> add(Ptr&& get_ptr)
{
2015-11-26 09:06:29 +01:00
extern std::mutex g_mutex;
extern fxm::map_t g_map;
2015-08-06 15:05:33 +02:00
std::lock_guard<std::mutex> lock(g_mutex);
2015-08-06 15:05:33 +02:00
2015-11-26 09:06:29 +01:00
auto& item = g_map[get_id_type_index<T>()];
2015-08-06 15:05:33 +02:00
2015-11-26 09:06:29 +01:00
if (Always || !item)
2015-08-06 15:05:33 +02:00
{
2015-11-26 09:06:29 +01:00
std::shared_ptr<T> old = std::static_pointer_cast<T>(std::move(item));
std::shared_ptr<T> ptr = get_ptr();
2015-08-06 15:05:33 +02:00
2015-11-26 09:06:29 +01:00
// Set new object
item = ptr;
2015-08-06 15:05:33 +02:00
2015-11-26 09:06:29 +01:00
return{ std::move(old), std::move(ptr) };
}
else
{
return{ std::static_pointer_cast<T>(item), nullptr };
2015-08-06 15:05:33 +02:00
}
}
2015-11-26 09:06:29 +01:00
// Create the object (returns nullptr if it already exists)
template<typename T, typename... Args>
std::enable_if_t<std::is_constructible<T, Args...>::value, std::shared_ptr<T>> make(Args&&... args)
2015-08-06 17:55:19 +02:00
{
2015-11-26 09:06:29 +01:00
auto pair = add<T, false>(WRAP_EXPR(std::make_shared<T>(std::forward<Args>(args)...)));
2015-11-26 09:06:29 +01:00
if (pair.second)
{
2015-11-26 09:06:29 +01:00
id_aux_initialize(pair.second.get());
return std::move(pair.second);
}
return nullptr;
}
2015-11-26 09:06:29 +01:00
// Create the object unconditionally (old object will be removed 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)
{
2015-11-26 09:06:29 +01:00
auto pair = add<T, true>(WRAP_EXPR(std::make_shared<T>(std::forward<Args>(args)...)));
2015-11-26 09:06:29 +01:00
if (pair.first)
{
id_aux_finalize(pair.first.get());
}
2015-08-06 17:55:19 +02:00
2015-11-26 09:06:29 +01:00
id_aux_initialize(pair.second.get());
return std::move(pair.second);
2015-08-06 17:55:19 +02:00
}
2015-11-26 09:06:29 +01:00
// Emplace the object
template<typename T>
bool import(const std::shared_ptr<T>& ptr)
2015-08-10 21:39:52 +02:00
{
2015-11-26 09:06:29 +01:00
static const auto size = sizeof(T); // forbid forward declarations
2015-08-10 21:39:52 +02:00
2015-11-26 09:06:29 +01:00
auto pair = add<T, false>(WRAP_EXPR(ptr));
2015-08-10 21:39:52 +02:00
2015-11-26 09:06:29 +01:00
if (pair.second)
2015-08-10 21:39:52 +02:00
{
2015-11-26 09:06:29 +01:00
id_aux_initialize(pair.second.get());
return true;
2015-08-10 21:39:52 +02:00
}
2015-11-26 09:06:29 +01:00
return false;
2015-08-10 21:39:52 +02:00
}
2015-11-26 09:06:29 +01:00
// Emplace the object unconditionally (old object will be removed if it exists)
template<typename T>
void import_always(const std::shared_ptr<T>& ptr)
2015-08-06 15:05:33 +02:00
{
2015-11-26 09:06:29 +01:00
static const auto size = sizeof(T); // forbid forward declarations
2015-08-06 15:05:33 +02:00
2015-11-26 09:06:29 +01:00
auto pair = add<T, true>(WRAP_EXPR(ptr));
2015-08-06 15:05:33 +02:00
2015-11-26 09:06:29 +01:00
if (pair.first)
2015-08-06 15:05:33 +02:00
{
2015-11-26 09:06:29 +01:00
id_aux_finalize(pair.first.get());
2015-08-06 15:05:33 +02:00
}
2015-11-26 09:06:29 +01:00
id_aux_initialize(pair.second.get());
2015-08-06 15:05:33 +02:00
}
2015-11-26 09:06:29 +01:00
// Get the object unconditionally (create an object 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)
2015-08-06 15:05:33 +02:00
{
2015-11-26 09:06:29 +01:00
auto pair = add<T, false>(WRAP_EXPR(std::make_shared<T>(std::forward<Args>(args)...)));
2015-08-06 15:05:33 +02:00
2015-11-26 09:06:29 +01:00
if (pair.second)
2015-08-06 15:05:33 +02:00
{
2015-11-26 09:06:29 +01:00
id_aux_initialize(pair.second.get());
return std::move(pair.second);
2015-08-06 15:05:33 +02:00
}
2015-11-26 09:06:29 +01:00
return std::move(pair.first);
2015-08-06 15:05:33 +02:00
}
2015-08-06 17:55:19 +02:00
2015-11-26 09:06:29 +01:00
// Internal
bool check(id_type_index_t type);
// Check whether the object exists
template<typename T>
bool check()
2015-08-06 17:55:19 +02:00
{
2015-11-26 09:06:29 +01:00
return check(get_id_type_index<T>());
}
2015-08-06 17:55:19 +02:00
2015-11-26 09:06:29 +01:00
// Internal
std::shared_ptr<void> get(id_type_index_t type);
2015-08-06 17:55:19 +02:00
2015-11-26 09:06:29 +01:00
// Get the object (returns nullptr if it doesn't exist)
template<typename T>
std::shared_ptr<T> get()
{
return std::static_pointer_cast<T>(get(get_id_type_index<T>()));
}
// Internal
std::shared_ptr<void> withdraw(id_type_index_t type);
// Delete the object
template<typename T>
bool remove()
{
if (auto ptr = withdraw(get_id_type_index<T>()))
2015-08-06 17:55:19 +02:00
{
2015-11-26 09:06:29 +01:00
id_aux_finalize(static_cast<T*>(ptr.get()));
return true;
2015-08-06 17:55:19 +02:00
}
2015-11-26 09:06:29 +01:00
return false;
}
2015-08-06 17:55:19 +02:00
2015-11-26 09:06:29 +01:00
// Delete the object and return it
template<typename T>
std::shared_ptr<T> withdraw()
{
if (auto ptr = std::static_pointer_cast<T>(withdraw(get_id_type_index<T>())))
{
id_aux_finalize(ptr.get());
return ptr;
}
return nullptr;
2015-08-06 17:55:19 +02:00
}
2015-11-26 09:06:29 +01:00
}