rpcsx/rpcs3/Emu/IdManager.h

844 lines
21 KiB
C
Raw Normal View History

#pragma once
2015-03-06 23:58:42 +01:00
#include "Utilities/types.h"
#include "Utilities/mutex.h"
2015-11-30 16:10:17 +01:00
#include <memory>
#include <vector>
#include <unordered_map>
2016-04-14 00:59:00 +02:00
// Mostly helper namespace
namespace id_manager
2015-11-26 09:06:29 +01:00
{
2016-04-14 00:59:00 +02:00
// Optional ID traits
template<typename T, typename = void>
struct id_traits
{
using tag = void;
2016-04-14 00:59:00 +02:00
static constexpr u32 min = 1;
static constexpr u32 max = 0x7fffffff;
};
2016-04-14 00:59:00 +02:00
template<typename T>
struct id_traits<T, void_t<typename T::id_base, decltype(&T::id_min), decltype(&T::id_max)>>
{
using tag = typename T::id_base;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
static constexpr u32 min = T::id_min;
static constexpr u32 max = T::id_max;
};
2016-04-14 00:59:00 +02:00
// Optional object initialization function (called after ID registration)
template<typename T, typename = void>
struct on_init
{
static inline void func(T*, const std::shared_ptr<void>&)
2016-04-14 00:59:00 +02:00
{
2016-06-25 07:16:15 +02:00
// Forbid forward declarations
static constexpr auto size = sizeof(std::conditional_t<std::is_void<T>::value, void*, T>);
2016-04-14 00:59:00 +02:00
}
};
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
template<typename T>
struct on_init<T, decltype(std::declval<T>().on_init(std::declval<const std::shared_ptr<void>&>()))>
2016-04-14 00:59:00 +02:00
{
static inline void func(T* ptr, const std::shared_ptr<void>&_ptr)
2016-04-14 00:59:00 +02:00
{
if (ptr) ptr->on_init(_ptr);
2016-04-14 00:59:00 +02:00
}
};
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
// Optional object finalization function (called after ID removal)
template<typename T, typename = void>
struct on_stop
{
2016-05-13 16:01:48 +02:00
static inline void func(T*)
2016-04-14 00:59:00 +02:00
{
2016-06-25 07:16:15 +02:00
// Forbid forward declarations
static constexpr auto size = sizeof(std::conditional_t<std::is_void<T>::value, void*, T>);
2016-04-14 00:59:00 +02:00
}
};
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
template<typename T>
struct on_stop<T, decltype(std::declval<T>().on_stop())>
{
2016-05-13 16:01:48 +02:00
static inline void func(T* ptr)
2016-04-14 00:59:00 +02:00
{
2016-06-25 07:16:15 +02:00
if (ptr) ptr->on_stop();
2016-04-14 00:59:00 +02:00
}
};
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
class typeinfo
{
// Global variable for each registered type
template<typename T>
struct registered
{
static const u32 index;
};
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
// Access global type list
static std::vector<typeinfo>& access();
2016-04-14 00:59:00 +02:00
// Add to the global list
static u32 add_type();
2016-04-14 00:59:00 +02:00
public:
void(*on_stop)(void*) = nullptr;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
// Get type index
template<typename T>
static inline u32 get_index()
2015-11-26 09:06:29 +01:00
{
return registered<T>::index;
}
// Register functions
template<typename T>
static inline void update()
{
2016-08-12 18:24:29 +02:00
access()[get_index<T>()].on_stop = [](void* ptr) { return id_manager::on_stop<T>::func(static_cast<T*>(ptr)); };
2016-04-14 00:59:00 +02:00
}
// Read all registered types
static inline const auto& get()
{
return access();
2015-11-26 09:06:29 +01:00
}
};
template<typename T>
const u32 typeinfo::registered<T>::index = typeinfo::add_type();
2016-08-01 00:35:53 +02:00
// ID value with additional type stored
class id_key
{
u32 m_value; // ID value
u32 m_type; // True object type
public:
id_key() = default;
id_key(u32 value, u32 type = 0)
: m_value(value)
, m_type(type)
{
}
u32 id() const
{
return m_value;
}
u32 type() const
{
return m_type;
}
bool operator ==(const id_key& rhs) const
{
return m_value == rhs.m_value;
}
bool operator !=(const id_key& rhs) const
{
return m_value != rhs.m_value;
}
};
// Custom hasher for ID values
struct id_hash final
{
std::size_t operator ()(const id_key& key) const
{
return key.id();
}
};
using id_map = std::unordered_map<id_key, std::shared_ptr<void>, id_hash>;
2016-04-14 00:59:00 +02:00
}
// Object manager for emulated process. Multiple objects of specified arbitrary type are given unique IDs.
class idm
{
// Rules for ID allocation:
// 0) Individual ID counter may be specified for each type by defining 'using id_base = ...;'
// 1) If no id_base specified, void is assumed.
// 2) g_id[id_base] indicates next ID allocated in g_map.
// 3) g_map[id_base] contains the additional copy of object pointer.
static shared_mutex g_mutex;
2016-04-14 00:59:00 +02:00
// Type Index -> ID -> Object. Use global since only one process is supported atm.
2016-08-01 00:35:53 +02:00
static std::vector<id_manager::id_map> g_map;
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
// Next ID for each category
static std::vector<u32> g_id;
2015-11-26 09:06:29 +01:00
template<typename T>
2016-04-14 00:59:00 +02:00
static inline u32 get_type()
{
return id_manager::typeinfo::get_index<T>();
}
2016-04-14 00:59:00 +02:00
template<typename T>
static inline u32 get_tag()
{
return get_type<typename id_manager::id_traits<T>::tag>();
}
// Update optional ID storage
template<typename T>
2016-05-13 16:01:48 +02:00
static inline auto set_id_value(T* ptr, u32 id) -> decltype(static_cast<void>(std::declval<T&>().id))
2015-07-01 00:25:52 +02:00
{
ptr->id = id;
2016-04-14 00:59:00 +02:00
}
2016-05-13 16:01:48 +02:00
static inline void set_id_value(...)
2016-04-14 00:59:00 +02:00
{
}
2015-07-01 00:25:52 +02:00
2016-05-13 16:01:48 +02:00
// Helper
template<typename F>
struct function_traits;
template<typename F, typename R, typename A1, typename A2>
struct function_traits<R(F::*)(A1, A2&) const>
{
2017-01-25 01:45:36 +01:00
using object_type = A2;
using result_type = R;
};
template<typename F, typename R, typename A1, typename A2>
struct function_traits<R(F::*)(A1, A2&)>
{
using object_type = A2;
using result_type = R;
};
template<typename F, typename A1, typename A2>
struct function_traits<void(F::*)(A1, A2&) const>
{
using object_type = A2;
using void_type = void;
};
template<typename F, typename A1, typename A2>
struct function_traits<void(F::*)(A1, A2&)>
{
using object_type = A2;
using void_type = void;
2016-05-13 16:01:48 +02:00
};
// Helper
2017-01-25 01:45:36 +01:00
template<typename T, typename RT>
struct return_pair
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
std::shared_ptr<T> ptr;
RT value;
explicit operator bool() const
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
return ptr.operator bool();
2016-05-13 16:01:48 +02:00
}
2017-01-25 01:45:36 +01:00
auto operator->() const
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
return ptr.get();
2016-05-13 16:01:48 +02:00
}
};
2017-01-25 01:45:36 +01:00
template<typename RT>
struct return_pair<bool, RT>
{
bool result;
RT value;
explicit operator bool() const
{
return result;
}
};
// Prepare new ID (returns nullptr if out of resources)
2016-08-01 01:26:55 +02:00
static id_manager::id_map::pointer allocate_id(u32 tag, u32 type, u32 min, u32 max);
// Deallocate ID, returns object
static std::shared_ptr<void> deallocate_id(u32 tag, u32 id);
2017-01-25 01:45:36 +01:00
// Allocate new ID and assign the object from the provider()
2016-08-01 01:26:55 +02:00
template<typename T, typename Set, typename F>
2016-08-01 00:35:53 +02:00
static id_manager::id_map::pointer create_id(F&& provider)
2016-04-14 00:59:00 +02:00
{
id_manager::typeinfo::update<T>();
id_manager::typeinfo::update<typename id_manager::id_traits<T>::tag>();
writer_lock lock(g_mutex);
2016-04-14 00:59:00 +02:00
2016-08-01 01:26:55 +02:00
if (auto place = allocate_id(get_tag<T>(), get_type<Set>(), id_manager::id_traits<T>::min, id_manager::id_traits<T>::max))
2016-04-14 00:59:00 +02:00
{
try
{
// Get object, store it
2016-04-14 00:59:00 +02:00
place->second = provider();
// Update ID value if required
2016-08-01 00:35:53 +02:00
set_id_value(static_cast<T*>(place->second.get()), place->first.id());
2016-04-14 00:59:00 +02:00
return &*g_map[get_type<T>()].emplace(*place).first;
}
catch (...)
{
2016-08-01 00:35:53 +02:00
deallocate_id(get_tag<T>(), place->first.id());
2016-04-14 00:59:00 +02:00
throw;
}
}
2015-07-01 00:25:52 +02:00
return nullptr;
2015-07-01 00:25:52 +02:00
}
// Get ID (internal)
2016-08-01 01:26:55 +02:00
static id_manager::id_map::pointer find_id(u32 type, u32 true_type, u32 id);
2016-04-14 00:59:00 +02:00
2017-01-25 01:45:36 +01:00
// Remove ID and return the object
2016-08-01 01:26:55 +02:00
static std::shared_ptr<void> delete_id(u32 type, u32 true_type, u32 tag, u32 id);
2016-04-14 00:59:00 +02:00
public:
// Initialize object manager
static void init();
2016-04-14 00:59:00 +02:00
// Remove all objects
static void clear();
2016-04-14 00:59:00 +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)
2016-04-14 00:59:00 +02:00
template<typename T, typename Make = T, typename... Args>
2016-08-01 01:26:55 +02:00
static inline std::enable_if_t<std::is_constructible<Make, Args...>::value, std::shared_ptr<Make>> make_ptr(Args&&... args)
2015-03-12 20:02:02 +01:00
{
2016-08-15 16:11:45 +02:00
if (auto pair = create_id<T, Make>([&] { return std::make_shared<Make>(std::forward<Args>(args)...); }))
{
id_manager::on_init<T>::func(static_cast<T*>(pair->second.get()), pair->second);
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(nullptr);
2016-08-01 01:26:55 +02:00
return{ pair->second, static_cast<Make*>(pair->second.get()) };
}
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)
2016-04-14 00:59:00 +02:00
template<typename T, typename Make = T, typename... Args>
2016-05-13 16:01:48 +02:00
static inline std::enable_if_t<std::is_constructible<Make, Args...>::value, u32> make(Args&&... args)
{
2016-08-15 16:11:45 +02:00
if (auto pair = create_id<T, Make>([&] { return std::make_shared<Make>(std::forward<Args>(args)...); }))
{
id_manager::on_init<T>::func(static_cast<T*>(pair->second.get()), pair->second);
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(nullptr);
2016-08-01 00:35:53 +02:00
return pair->first.id();
}
fmt::throw_exception("Out of IDs ('%s')" HERE, typeid(T).name());
}
2015-11-26 09:06:29 +01:00
// Add a new ID for an existing object provided (returns new id)
2016-08-01 01:26:55 +02:00
template<typename T, typename Made = T>
2016-05-13 16:01:48 +02:00
static inline u32 import_existing(const std::shared_ptr<T>& ptr)
2015-03-15 10:20:29 +01:00
{
2016-08-15 16:11:45 +02:00
if (auto pair = create_id<T, Made>([&] { return ptr; }))
2015-03-15 10:20:29 +01:00
{
id_manager::on_init<T>::func(static_cast<T*>(pair->second.get()), pair->second);
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(nullptr);
2016-08-01 00:35:53 +02:00
return pair->first.id();
2015-03-15 10:20:29 +01:00
}
fmt::throw_exception("Out of IDs ('%s')" HERE, typeid(T).name());
2015-03-15 10:20:29 +01:00
}
2016-04-14 00:59:00 +02:00
// Add a new ID for an object returned by provider()
2016-08-01 01:26:55 +02:00
template<typename T, typename Made = T, typename F, typename = std::result_of_t<F()>>
static inline std::shared_ptr<Made> import(F&& provider)
2016-04-14 00:59:00 +02:00
{
2016-08-01 01:26:55 +02:00
if (auto pair = create_id<T, Made>(std::forward<F>(provider)))
2016-04-14 00:59:00 +02:00
{
id_manager::on_init<T>::func(static_cast<T*>(pair->second.get()), pair->second);
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(nullptr);
2016-08-01 01:26:55 +02:00
return { pair->second, static_cast<Made*>(pair->second.get()) };
2016-04-14 00:59:00 +02:00
}
return nullptr;
}
2015-11-26 09:06:29 +01:00
2017-01-25 01:45:36 +01:00
// Check the ID
2016-08-01 01:26:55 +02:00
template<typename T, typename Get = void>
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t check(u32 id)
2015-07-08 17:01:59 +02:00
{
2016-04-14 00:59:00 +02:00
reader_lock lock(g_mutex);
2016-08-01 01:26:55 +02:00
return find_id(get_type<T>(), get_type<Get>(), id) != nullptr;
2015-11-26 09:06:29 +01:00
}
2015-07-08 17:01:59 +02:00
2017-01-25 01:45:36 +01:00
// Check the ID, access object under shared lock
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<std::is_void<FRT>::value>>
static inline explicit_bool_t check(u32 id, F&& func, int = 0)
{
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
reader_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
if (UNLIKELY(found == nullptr))
{
return false;
}
func(*static_cast<pointer_type*>(found->second.get()));
return true;
}
// Check the ID, access object under reader lock, propagate return value
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<!std::is_void<FRT>::value>>
static inline return_pair<bool, FRT> check(u32 id, F&& func)
{
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
reader_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
if (UNLIKELY(found == nullptr))
{
return {false};
}
return {true, func(*static_cast<pointer_type*>(found->second.get()))};
}
// Get the object
2016-08-01 01:26:55 +02:00
template<typename T, typename Get = void, typename Made = std::conditional_t<std::is_void<Get>::value, T, Get>>
static inline std::shared_ptr<Made> get(u32 id)
2016-04-14 00:59:00 +02:00
{
reader_lock lock(g_mutex);
2016-08-01 01:26:55 +02:00
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
2015-07-08 17:01:59 +02:00
if (UNLIKELY(found == nullptr))
2016-04-14 00:59:00 +02:00
{
return nullptr;
}
2017-01-25 01:45:36 +01:00
return {found->second, static_cast<Made*>(found->second.get())};
2016-04-14 00:59:00 +02:00
}
2017-01-25 01:45:36 +01:00
// Get the object, access object under reader lock
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<std::is_void<FRT>::value>>
static inline auto get(u32 id, F&& func, int = 0)
2015-11-26 09:06:29 +01:00
{
2017-01-25 01:45:36 +01:00
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
using result_type = std::shared_ptr<pointer_type>;
2016-05-13 16:01:48 +02:00
2016-04-14 00:59:00 +02:00
reader_lock lock(g_mutex);
2016-08-01 01:26:55 +02:00
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
2016-05-13 16:01:48 +02:00
if (UNLIKELY(found == nullptr))
{
2017-01-25 01:45:36 +01:00
return result_type{nullptr};
2016-05-13 16:01:48 +02:00
}
2015-07-08 17:01:59 +02:00
2017-01-25 01:45:36 +01:00
const auto ptr = static_cast<pointer_type*>(found->second.get());
func(*ptr);
return result_type{found->second, ptr};
}
// Get the object, access object under reader lock, propagate return value
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<!std::is_void<FRT>::value>>
static inline auto get(u32 id, F&& func)
{
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
using result_type = return_pair<pointer_type, FRT>;
reader_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
if (UNLIKELY(found == nullptr))
{
return result_type{nullptr};
}
const auto ptr = static_cast<pointer_type*>(found->second.get());
return result_type{{found->second, ptr}, func(*ptr)};
}
// Access all objects of specified types under reader lock (use lambda or callable object), return the number of objects processed
template<typename... Types, typename F, typename FT = decltype(&std::decay_t<F>::operator()), typename FRT = typename function_traits<FT>::void_type>
static inline u32 select(F&& func, int = 0)
{
reader_lock lock(g_mutex);
u32 result = 0;
for (u32 type : { get_type<Types>()... })
2015-07-08 17:01:59 +02:00
{
2017-01-25 01:45:36 +01:00
for (auto& id : g_map[type])
{
func(id.first.id(), *static_cast<typename function_traits<FT>::object_type*>(id.second.get()));
result++;
}
2016-05-13 16:01:48 +02:00
}
2017-01-25 01:45:36 +01:00
return result;
2016-05-13 16:01:48 +02:00
}
2017-01-25 01:45:36 +01:00
// Access all objects of specified types under reader lock (use lambda or callable object), if return value evaluates to true, stop and return the object and the value
template<typename... Types, typename F, typename FT = decltype(&std::decay_t<F>::operator()), typename FRT = typename function_traits<FT>::result_type>
static inline auto select(F&& func)
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
using object_type = typename function_traits<FT>::object_type;
using result_type = return_pair<object_type, FRT>;
2016-05-13 16:01:48 +02:00
reader_lock lock(g_mutex);
for (u32 type : { get_type<Types>()... })
{
for (auto& id : g_map[type])
{
2017-01-25 01:45:36 +01:00
if (FRT result = func(id.first.id(), *static_cast<object_type*>(id.second.get())))
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
return result_type{{id.second, static_cast<object_type*>(id.second.get())}, std::move(result)};
2016-05-13 16:01:48 +02:00
}
}
2015-07-08 17:01:59 +02:00
}
2017-01-25 01:45:36 +01:00
return result_type{nullptr};
2016-05-13 16:01:48 +02:00
}
// Get count of objects
2016-08-01 01:26:55 +02:00
template<typename T, typename Get = void>
2016-05-13 16:01:48 +02:00
static inline u32 get_count()
{
reader_lock lock(g_mutex);
2016-08-01 01:26:55 +02:00
if (std::is_void<Get>::value)
{
return ::size32(g_map[get_type<T>()]);
}
u32 result = 0;
for (auto& id : g_map[get_type<T>()])
{
if (id.first.type() == get_type<Get>())
{
result++;
}
}
return result;
2015-07-08 17:01:59 +02:00
}
2016-04-14 00:59:00 +02:00
// Remove the ID
2016-08-01 01:26:55 +02:00
template<typename T, typename Get = void>
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t remove(u32 id)
2015-11-26 09:06:29 +01:00
{
2017-01-25 01:45:36 +01:00
auto ptr = delete_id(get_type<T>(), get_type<Get>(), get_tag<T>(), id);
if (LIKELY(ptr))
2016-04-14 00:59:00 +02:00
{
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
2015-11-26 09:06:29 +01:00
}
2016-04-14 00:59:00 +02:00
return ptr.operator bool();
}
2017-01-25 01:45:36 +01:00
// Remove the ID and return the object
2016-08-01 01:26:55 +02:00
template<typename T, typename Get = void, typename Made = std::conditional_t<std::is_void<Get>::value, T, Get>>
static inline std::shared_ptr<Made> withdraw(u32 id)
{
2017-01-25 01:45:36 +01:00
auto ptr = delete_id(get_type<T>(), get_type<Get>(), get_tag<T>(), id);
if (LIKELY(ptr))
2016-04-14 00:59:00 +02:00
{
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
2015-11-26 09:06:29 +01:00
}
2017-01-25 01:45:36 +01:00
return {ptr, static_cast<Made*>(ptr.get())};
}
// Remove the ID after accessing the object under writer lock, return the object and propagate return value
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<std::is_void<FRT>::value>>
static inline auto withdraw(u32 id, F&& func, int = 0)
{
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
using result_type = std::shared_ptr<pointer_type>;
std::shared_ptr<void> ptr;
{
writer_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
if (UNLIKELY(found == nullptr))
{
return result_type{nullptr};
}
func(*static_cast<pointer_type*>(found->second.get()));
ptr = deallocate_id(get_tag<T>(), id);
g_map[get_type<T>()].erase(id);
}
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
return result_type{ptr, static_cast<pointer_type*>(ptr.get())};
}
2017-01-25 01:45:36 +01:00
// Conditionally remove the ID (if return value evaluates to false) after accessing the object under writer lock, return the object and propagate return value
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<!std::is_void<FRT>::value>>
static inline auto withdraw(u32 id, F&& func)
2015-07-01 00:25:52 +02:00
{
2017-01-25 01:45:36 +01:00
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
using result_type = return_pair<pointer_type, FRT>;
2016-05-13 16:01:48 +02:00
std::shared_ptr<void> ptr;
2017-01-25 01:45:36 +01:00
FRT ret;
2015-07-01 00:25:52 +02:00
{
2016-05-13 16:01:48 +02:00
writer_lock lock(g_mutex);
2015-07-01 00:25:52 +02:00
2016-08-01 01:26:55 +02:00
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
2015-07-01 00:25:52 +02:00
2017-01-25 01:45:36 +01:00
if (UNLIKELY(found == nullptr))
{
return result_type{nullptr};
}
const auto _ptr = static_cast<pointer_type*>(found->second.get());
ret = func(*_ptr);
if (ret)
2016-05-13 16:01:48 +02:00
{
2017-01-25 01:45:36 +01:00
return result_type{{found->second, _ptr}, std::move(ret)};
2016-05-13 16:01:48 +02:00
}
2016-04-14 00:59:00 +02:00
2016-05-13 16:01:48 +02:00
ptr = deallocate_id(get_tag<T>(), id);
2015-07-01 00:25:52 +02:00
2016-05-13 16:01:48 +02:00
g_map[get_type<T>()].erase(id);
2015-07-01 00:25:52 +02:00
}
2016-05-13 16:01:48 +02:00
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
2015-07-01 00:25:52 +02:00
2017-01-25 01:45:36 +01:00
return result_type{{ptr, static_cast<pointer_type*>(ptr.get())}, std::move(ret)};
2015-07-01 00:25:52 +02:00
}
2016-04-14 00:59:00 +02:00
};
2015-08-06 15:05:33 +02:00
2016-04-14 00:59:00 +02:00
// Object manager for emulated process. One unique object per type, or zero.
class fxm
2015-08-06 15:05:33 +02:00
{
2016-04-14 00:59:00 +02:00
// Type Index -> Object. Use global since only one process is supported atm.
static std::vector<std::shared_ptr<void>> g_map;
2015-12-01 15:48:32 +01:00
2016-04-14 00:59:00 +02:00
static shared_mutex g_mutex;
2016-04-14 00:59:00 +02:00
template<typename T>
static inline u32 get_type()
{
return id_manager::typeinfo::get_index<T>();
2016-04-14 00:59:00 +02:00
}
2015-08-06 15:05:33 +02:00
static std::shared_ptr<void> remove(u32 type);
2015-08-06 15:05:33 +02:00
2016-04-14 00:59:00 +02:00
public:
// Initialize object manager
static void init();
2016-04-14 00:59:00 +02:00
// Remove all objects
static void clear();
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)
2016-04-14 00:59:00 +02:00
template<typename T, typename Make = T, typename... Args>
static std::enable_if_t<std::is_constructible<Make, Args...>::value, std::shared_ptr<T>> make(Args&&... args)
2015-08-06 17:55:19 +02:00
{
id_manager::typeinfo::update<T>();
2016-04-14 00:59:00 +02:00
std::shared_ptr<T> ptr;
{
writer_lock lock(g_mutex);
2016-04-14 00:59:00 +02:00
if (!g_map[get_type<T>()])
{
ptr = std::make_shared<Make>(std::forward<Args>(args)...);
g_map[get_type<T>()] = ptr;
}
}
2016-04-14 00:59:00 +02:00
if (ptr)
{
id_manager::on_init<T>::func(ptr.get(), ptr);
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(nullptr);
}
2016-04-14 00:59:00 +02:00
return ptr;
}
2015-11-26 09:06:29 +01:00
// Create the object unconditionally (old object will be removed if it exists)
2016-04-14 00:59:00 +02:00
template<typename T, typename Make = T, typename... Args>
static std::enable_if_t<std::is_constructible<Make, Args...>::value, std::shared_ptr<T>> make_always(Args&&... args)
{
id_manager::typeinfo::update<T>();
2016-04-14 00:59:00 +02:00
std::shared_ptr<T> ptr;
std::shared_ptr<void> old;
{
writer_lock lock(g_mutex);
2016-04-14 00:59:00 +02:00
old = std::move(g_map[get_type<T>()]);
ptr = std::make_shared<Make>(std::forward<Args>(args)...);
g_map[get_type<T>()] = ptr;
}
2016-04-14 00:59:00 +02:00
if (old)
2015-11-26 09:06:29 +01:00
{
2016-04-14 00:59:00 +02:00
id_manager::on_stop<T>::func(static_cast<T*>(old.get()));
2015-11-26 09:06:29 +01:00
}
2015-08-06 17:55:19 +02:00
id_manager::on_init<T>::func(ptr.get(), ptr);
2016-04-14 00:59:00 +02:00
return ptr;
2015-08-06 17:55:19 +02:00
}
2015-12-19 12:40:52 +01:00
// Emplace the object returned by provider() and return it if no object exists
template<typename T, typename F>
2016-04-14 00:59:00 +02:00
static auto import(F&& provider) -> decltype(static_cast<std::shared_ptr<T>>(provider()))
2015-08-10 21:39:52 +02:00
{
id_manager::typeinfo::update<T>();
2016-04-14 00:59:00 +02:00
std::shared_ptr<T> ptr;
{
writer_lock lock(g_mutex);
2015-08-10 21:39:52 +02:00
2016-04-14 00:59:00 +02:00
if (!g_map[get_type<T>()])
{
ptr = provider();
2015-08-10 21:39:52 +02:00
2016-04-14 00:59:00 +02:00
g_map[get_type<T>()] = ptr;
}
}
if (ptr)
2015-08-10 21:39:52 +02:00
{
id_manager::on_init<T>::func(ptr.get(), ptr);
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(nullptr);
2015-08-10 21:39:52 +02:00
}
2016-04-14 00:59:00 +02:00
return ptr;
2015-08-10 21:39:52 +02:00
}
2015-12-19 12:40:52 +01:00
// Emplace the object return by provider() (old object will be removed if it exists)
template<typename T, typename F>
2016-04-14 00:59:00 +02:00
static auto import_always(F&& provider) -> decltype(static_cast<std::shared_ptr<T>>(provider()))
2015-08-06 15:05:33 +02:00
{
id_manager::typeinfo::update<T>();
2016-04-14 00:59:00 +02:00
std::shared_ptr<T> ptr;
std::shared_ptr<void> old;
{
writer_lock lock(g_mutex);
2015-08-06 15:05:33 +02:00
2016-04-14 00:59:00 +02:00
old = std::move(g_map[get_type<T>()]);
ptr = provider();
2015-08-06 15:05:33 +02:00
2016-04-14 00:59:00 +02:00
g_map[get_type<T>()] = ptr;
}
if (old)
2015-08-06 15:05:33 +02:00
{
2016-04-14 00:59:00 +02:00
id_manager::on_stop<T>::func(static_cast<T*>(old.get()));
2015-08-06 15:05:33 +02:00
}
id_manager::on_init<T>::func(ptr.get(), ptr);
2016-04-14 00:59:00 +02:00
return ptr;
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)
2016-04-14 00:59:00 +02:00
template<typename T, typename Make = T, typename... Args>
static std::enable_if_t<std::is_constructible<Make, Args...>::value, std::shared_ptr<T>> get_always(Args&&... args)
2015-08-06 15:05:33 +02:00
{
id_manager::typeinfo::update<T>();
2016-04-14 00:59:00 +02:00
std::shared_ptr<T> ptr;
2015-08-06 15:05:33 +02:00
{
writer_lock lock(g_mutex);
2016-04-14 00:59:00 +02:00
if (auto& value = g_map[get_type<T>()])
{
return{ value, static_cast<T*>(value.get()) };
}
else
{
ptr = std::make_shared<Make>(std::forward<Args>(args)...);
g_map[get_type<T>()] = ptr;
}
2015-08-06 15:05:33 +02:00
}
id_manager::on_init<T>::func(ptr.get(), ptr);
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(nullptr);
2016-04-14 00:59:00 +02:00
return ptr;
2015-08-06 15:05:33 +02:00
}
2015-08-06 17:55:19 +02:00
2015-11-26 09:06:29 +01:00
// Check whether the object exists
template<typename T>
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t check()
2015-08-06 17:55:19 +02:00
{
2016-04-14 00:59:00 +02:00
reader_lock lock(g_mutex);
2015-08-06 17:55:19 +02:00
2016-04-14 00:59:00 +02:00
return g_map[get_type<T>()].operator bool();
}
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>
2016-05-13 16:01:48 +02:00
static inline std::shared_ptr<T> get()
2015-11-26 09:06:29 +01:00
{
2016-04-14 00:59:00 +02:00
reader_lock lock(g_mutex);
auto& ptr = g_map[get_type<T>()];
2015-11-26 09:06:29 +01:00
2016-04-14 00:59:00 +02:00
return{ ptr, static_cast<T*>(ptr.get()) };
}
2015-11-26 09:06:29 +01:00
// Delete the object
template<typename T>
2017-01-25 01:45:36 +01:00
static inline explicit_bool_t remove()
2015-11-26 09:06:29 +01:00
{
2017-01-25 01:45:36 +01:00
auto ptr = remove(get_type<T>());
2016-04-14 00:59:00 +02:00
if (ptr)
2015-08-06 17:55:19 +02:00
{
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
2015-08-06 17:55:19 +02:00
}
2016-04-14 00:59:00 +02:00
return ptr.operator bool();
2015-11-26 09:06:29 +01:00
}
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>
2016-05-13 16:01:48 +02:00
static inline std::shared_ptr<T> withdraw()
2015-11-26 09:06:29 +01:00
{
2017-01-25 01:45:36 +01:00
auto ptr = remove(get_type<T>());
2016-04-14 00:59:00 +02:00
if (ptr)
2015-11-26 09:06:29 +01:00
{
2016-06-25 07:16:15 +02:00
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
2015-11-26 09:06:29 +01:00
}
2016-04-14 00:59:00 +02:00
return{ ptr, static_cast<T*>(ptr.get()) };
2015-08-06 17:55:19 +02:00
}
2016-04-14 00:59:00 +02:00
};