2018-11-20 16:35:06 +01:00
|
|
|
|
#pragma once
|
2015-03-06 23:58:42 +01:00
|
|
|
|
|
2016-04-27 00:27:24 +02:00
|
|
|
|
#include "Utilities/types.h"
|
2017-01-24 21:19:52 +01:00
|
|
|
|
#include "Utilities/mutex.h"
|
2015-11-30 16:10:17 +01:00
|
|
|
|
|
2016-04-27 00:27:24 +02:00
|
|
|
|
#include <memory>
|
|
|
|
|
|
#include <vector>
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// Helper namespace
|
2016-04-14 00:59:00 +02:00
|
|
|
|
namespace id_manager
|
2015-11-26 09:06:29 +01:00
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
|
// Common global mutex
|
|
|
|
|
|
extern shared_mutex g_mutex;
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// ID traits
|
|
|
|
|
|
template <typename T, typename = void>
|
2016-04-14 00:59:00 +02:00
|
|
|
|
struct id_traits
|
|
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
|
static_assert(sizeof(T) == 0, "ID object must specify: id_base, id_step, id_count");
|
2015-09-18 00:41:14 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
static const u32 base = 1; // First ID (N = 0)
|
|
|
|
|
|
static const u32 step = 1; // Any ID: N * id_step + id_base
|
|
|
|
|
|
static const u32 count = 65535; // Limit: N < id_count
|
2017-01-25 18:50:30 +01:00
|
|
|
|
static const u32 invalid = 0;
|
2016-04-14 00:59:00 +02:00
|
|
|
|
};
|
2015-09-18 00:41:14 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T>
|
2018-08-23 23:31:27 +02:00
|
|
|
|
struct id_traits<T, std::void_t<decltype(&T::id_base), decltype(&T::id_step), decltype(&T::id_count)>>
|
2016-04-14 00:59:00 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
static const u32 base = T::id_base;
|
|
|
|
|
|
static const u32 step = T::id_step;
|
|
|
|
|
|
static const u32 count = T::id_count;
|
2017-01-25 18:50:30 +01:00
|
|
|
|
static const u32 invalid = base > 0 ? 0 : -1;
|
2015-11-26 09:06:29 +01:00
|
|
|
|
|
2017-01-25 18:50:30 +01:00
|
|
|
|
static_assert(u64{step} * count + base < UINT32_MAX, "ID traits: invalid object range");
|
2016-04-14 00:59:00 +02:00
|
|
|
|
};
|
2015-08-11 18:14:53 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// Correct usage testing
|
|
|
|
|
|
template <typename T, typename T2, typename = void>
|
|
|
|
|
|
struct id_verify : std::integral_constant<bool, std::is_base_of<T, T2>::value>
|
|
|
|
|
|
{
|
|
|
|
|
|
// If common case, T2 shall be derived from or equal to T
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T, typename T2>
|
2018-08-23 23:31:27 +02:00
|
|
|
|
struct id_verify<T, T2, std::void_t<typename T2::id_type>> : std::integral_constant<bool, std::is_same<T, typename T2::id_type>::value>
|
2017-01-29 17:50:18 +01:00
|
|
|
|
{
|
|
|
|
|
|
// If T2 contains id_type type, T must be equal to it
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
|
class typeinfo
|
|
|
|
|
|
{
|
|
|
|
|
|
// Global variable for each registered type
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T>
|
2016-04-14 00:59:00 +02:00
|
|
|
|
struct registered
|
|
|
|
|
|
{
|
|
|
|
|
|
static const u32 index;
|
|
|
|
|
|
};
|
2015-11-26 09:06:29 +01:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// Increment type counter
|
|
|
|
|
|
static u32 add_type(u32 i)
|
|
|
|
|
|
{
|
|
|
|
|
|
static atomic_t<u32> g_next{0};
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return g_next.fetch_add(i);
|
|
|
|
|
|
}
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
// Get type index
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T>
|
2016-04-14 00:59:00 +02:00
|
|
|
|
static inline u32 get_index()
|
2015-11-26 09:06:29 +01:00
|
|
|
|
{
|
2016-06-21 10:22:30 +02:00
|
|
|
|
return registered<T>::index;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// Get type count
|
|
|
|
|
|
static inline u32 get_count()
|
2016-06-21 10:22:30 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return add_type(0);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
}
|
2015-11-26 09:06:29 +01:00
|
|
|
|
};
|
2015-09-18 00:41:14 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T>
|
|
|
|
|
|
const u32 typeinfo::registered<T>::index = typeinfo::add_type(1);
|
2016-08-01 00:35:53 +02:00
|
|
|
|
|
|
|
|
|
|
// ID value with additional type stored
|
|
|
|
|
|
class id_key
|
|
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
u32 m_value; // ID value
|
|
|
|
|
|
u32 m_type; // True object type
|
2016-08-01 00:35:53 +02:00
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
id_key() = default;
|
|
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
|
id_key(u32 value, u32 type)
|
2016-08-01 00:35:53 +02:00
|
|
|
|
: m_value(value)
|
|
|
|
|
|
, m_type(type)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
u32 value() const
|
2016-08-01 00:35:53 +02:00
|
|
|
|
{
|
|
|
|
|
|
return m_value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u32 type() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_type;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
operator u32() const
|
2017-01-28 15:59:43 +01:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return m_value;
|
2017-01-28 15:59:43 +01:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
using id_map = std::vector<std::pair<id_key, std::shared_ptr<void>>>;
|
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
|
|
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
|
// Last allocated ID for constructors
|
|
|
|
|
|
static thread_local u32 g_id;
|
2016-04-27 00:27:24 +02:00
|
|
|
|
|
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
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T>
|
2016-04-14 00:59:00 +02:00
|
|
|
|
static inline u32 get_type()
|
2015-09-18 00:41:14 +02:00
|
|
|
|
{
|
2016-04-27 00:27:24 +02:00
|
|
|
|
return id_manager::typeinfo::get_index<T>();
|
2015-08-08 03:16:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T>
|
|
|
|
|
|
static constexpr u32 get_index(u32 id)
|
|
|
|
|
|
{
|
|
|
|
|
|
return (id - id_manager::id_traits<T>::base) / id_manager::id_traits<T>::step;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-13 16:01:48 +02:00
|
|
|
|
// Helper
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename F>
|
2016-05-13 16:01:48 +02:00
|
|
|
|
struct function_traits;
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename F, typename R, typename A1, typename A2>
|
|
|
|
|
|
struct function_traits<R (F::*)(A1, A2&) const>
|
2016-05-13 16:01:48 +02:00
|
|
|
|
{
|
2017-01-25 01:45:36 +01:00
|
|
|
|
using object_type = A2;
|
|
|
|
|
|
using result_type = R;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename F, typename R, typename A1, typename A2>
|
|
|
|
|
|
struct function_traits<R (F::*)(A1, A2&)>
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
|
|
|
|
|
using object_type = A2;
|
|
|
|
|
|
using result_type = R;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename F, typename A1, typename A2>
|
|
|
|
|
|
struct function_traits<void (F::*)(A1, A2&) const>
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
|
|
|
|
|
using object_type = A2;
|
2017-01-29 17:50:18 +01:00
|
|
|
|
using void_type = void;
|
2017-01-25 01:45:36 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename F, typename A1, typename A2>
|
|
|
|
|
|
struct function_traits<void (F::*)(A1, A2&)>
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
|
|
|
|
|
using object_type = A2;
|
2017-01-29 17:50:18 +01:00
|
|
|
|
using void_type = void;
|
2016-05-13 16:01:48 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
2017-02-02 18:32:49 +01:00
|
|
|
|
// Helper type: pointer + return value propagated
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T, typename RT>
|
2017-01-25 01:45:36 +01:00
|
|
|
|
struct return_pair
|
2016-05-13 16:01:48 +02:00
|
|
|
|
{
|
2017-01-25 01:45:36 +01:00
|
|
|
|
std::shared_ptr<T> ptr;
|
2017-02-02 18:32:49 +01:00
|
|
|
|
RT ret;
|
2017-01-25 01:45:36 +01:00
|
|
|
|
|
|
|
|
|
|
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-02-02 18:32:49 +01:00
|
|
|
|
T* 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-02-02 18:32:49 +01:00
|
|
|
|
// Unsafe specialization (not refcounted)
|
|
|
|
|
|
template <typename T, typename RT>
|
|
|
|
|
|
struct return_pair<T*, RT>
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
2017-02-02 18:32:49 +01:00
|
|
|
|
T* ptr;
|
|
|
|
|
|
RT ret;
|
2017-01-25 01:45:36 +01:00
|
|
|
|
|
|
|
|
|
|
explicit operator bool() const
|
|
|
|
|
|
{
|
2017-02-02 18:32:49 +01:00
|
|
|
|
return ptr != nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
T* operator->() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return ptr;
|
2017-01-25 01:45:36 +01:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Prepare new ID (returns nullptr if out of resources)
|
2017-01-29 17:50:18 +01:00
|
|
|
|
static id_manager::id_map::pointer allocate_id(const id_manager::id_key& info, u32 base, u32 step, u32 count);
|
|
|
|
|
|
|
|
|
|
|
|
// Find ID (additionally check type if types are not equal)
|
|
|
|
|
|
template <typename T, typename Type>
|
|
|
|
|
|
static id_manager::id_map::pointer find_id(u32 id)
|
|
|
|
|
|
{
|
|
|
|
|
|
static_assert(id_manager::id_verify<T, Type>::value, "Invalid ID type combination");
|
|
|
|
|
|
|
|
|
|
|
|
const u32 index = get_index<Type>(id);
|
2015-08-04 12:46:05 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
auto& vec = g_map[get_type<T>()];
|
|
|
|
|
|
|
|
|
|
|
|
if (index >= vec.size() || index >= id_manager::id_traits<Type>::count)
|
|
|
|
|
|
{
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-31 13:57:32 +01:00
|
|
|
|
auto& data = vec[index];
|
|
|
|
|
|
|
|
|
|
|
|
if (data.second)
|
2017-01-29 17:50:18 +01:00
|
|
|
|
{
|
2017-01-31 13:57:32 +01:00
|
|
|
|
if (std::is_same<T, Type>::value || data.first.type() == get_type<Type>())
|
2017-01-29 17:50:18 +01:00
|
|
|
|
{
|
2017-01-31 13:57:32 +01:00
|
|
|
|
return &data;
|
2017-01-29 17:50:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-01-25 18:50:30 +01:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
2015-08-04 12:46:05 +02:00
|
|
|
|
|
2017-01-25 01:45:36 +01:00
|
|
|
|
// Allocate new ID and assign the object from the provider()
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T, typename Type, 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
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
static_assert(id_manager::id_verify<T, Type>::value, "Invalid ID type combination");
|
2017-01-25 18:50:30 +01:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// ID info
|
2018-10-11 00:17:19 +02:00
|
|
|
|
const id_manager::id_key info{get_type<T>(), get_type<Type>()};
|
2016-06-21 10:22:30 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// ID traits
|
|
|
|
|
|
using traits = id_manager::id_traits<Type>;
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2017-01-25 18:50:30 +01:00
|
|
|
|
// Allocate new id
|
2018-09-03 21:28:33 +02:00
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2017-01-29 17:50:18 +01:00
|
|
|
|
|
|
|
|
|
|
if (auto* place = allocate_id(info, traits::base, traits::step, traits::count))
|
2016-04-14 00:59:00 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// Get object, store it
|
|
|
|
|
|
place->second = provider();
|
2017-01-31 13:57:32 +01:00
|
|
|
|
|
|
|
|
|
|
if (place->second)
|
|
|
|
|
|
{
|
|
|
|
|
|
return place;
|
|
|
|
|
|
}
|
2015-08-04 12:46:05 +02:00
|
|
|
|
}
|
2015-07-01 00:25:52 +02:00
|
|
|
|
|
2015-08-11 18:14:53 +02:00
|
|
|
|
return nullptr;
|
2015-07-01 00:25:52 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
|
public:
|
|
|
|
|
|
// Initialize object manager
|
2016-04-27 00:27:24 +02:00
|
|
|
|
static void init();
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
|
|
|
|
|
// Remove all objects
|
2016-04-27 00:27:24 +02:00
|
|
|
|
static void clear();
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// Get last ID (updated in create_id/allocate_id)
|
2017-01-25 18:50:30 +01:00
|
|
|
|
static inline u32 last_id()
|
|
|
|
|
|
{
|
|
|
|
|
|
return g_id;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
|
// Add a new ID of specified type with specified constructor arguments (returns object or nullptr)
|
2017-01-29 17:50:18 +01: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)...); }))
|
2015-08-04 12:46:05 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return {pair->second, static_cast<Make*>(pair->second.get())};
|
2015-08-04 12:46:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
|
return nullptr;
|
2015-08-04 12:46:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
|
// Add a new ID of specified type with specified constructor arguments (returns id)
|
2017-01-29 17:50:18 +01: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)
|
2015-08-07 23:28:09 +02: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)...); }))
|
2015-08-07 23:28:09 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return pair->first;
|
2015-08-07 23:28:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return id_manager::id_traits<Make>::invalid;
|
2015-08-07 23:28:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
|
// Add a new ID for an existing object provided (returns new id)
|
2017-01-29 17:50:18 +01: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
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return pair->first;
|
2015-03-15 10:20:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return id_manager::id_traits<Made>::invalid;
|
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()
|
2018-09-05 14:10:37 +02:00
|
|
|
|
template <typename T, typename Made = T, typename F, typename = std::invoke_result_t<F>>
|
2017-01-31 13:57:32 +01:00
|
|
|
|
static inline u32 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
|
|
|
|
{
|
2017-01-31 13:57:32 +01:00
|
|
|
|
return pair->first;
|
2016-04-14 00:59:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-31 13:57:32 +01:00
|
|
|
|
return id_manager::id_traits<Made>::invalid;
|
2016-04-14 00:59:00 +02:00
|
|
|
|
}
|
2015-11-26 09:06:29 +01:00
|
|
|
|
|
2017-02-02 18:32:49 +01:00
|
|
|
|
// Access the ID record without locking (unsafe)
|
|
|
|
|
|
template <typename T, typename Get = T>
|
|
|
|
|
|
static inline id_manager::id_map::pointer find_unlocked(u32 id)
|
|
|
|
|
|
{
|
|
|
|
|
|
return find_id<T, Get>(id);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Check the ID without locking (can be called from other method)
|
|
|
|
|
|
template <typename T, typename Get = T>
|
|
|
|
|
|
static inline Get* check_unlocked(u32 id)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (const auto found = find_id<T, Get>(id))
|
|
|
|
|
|
{
|
|
|
|
|
|
return static_cast<Get*>(found->second.get());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-25 01:45:36 +01:00
|
|
|
|
// Check the ID
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T, typename Get = T>
|
2017-02-02 18:32:49 +01:00
|
|
|
|
static inline Get* check(u32 id)
|
2015-07-08 17:01:59 +02:00
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
|
reader_lock lock(id_manager::g_mutex);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2017-02-02 18:32:49 +01:00
|
|
|
|
return check_unlocked<T, Get>(id);
|
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
|
2018-09-05 14:10:37 +02:00
|
|
|
|
template <typename T, typename Get = T, typename F, typename FRT = std::invoke_result_t<F, Get&>>
|
|
|
|
|
|
static inline auto check(u32 id, F&& func)
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
|
reader_lock lock(id_manager::g_mutex);
|
2017-01-25 01:45:36 +01:00
|
|
|
|
|
2017-02-02 18:32:49 +01:00
|
|
|
|
if (const auto ptr = check_unlocked<T, Get>(id))
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
|
if constexpr (!std::is_void_v<FRT>)
|
|
|
|
|
|
{
|
|
|
|
|
|
return return_pair<Get*, FRT>{ptr, func(*ptr)};
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
func(*ptr);
|
|
|
|
|
|
return ptr;
|
|
|
|
|
|
}
|
2017-01-25 01:45:36 +01:00
|
|
|
|
}
|
2018-08-23 23:31:27 +02:00
|
|
|
|
|
2018-09-05 14:10:37 +02:00
|
|
|
|
if constexpr (!std::is_void_v<FRT>)
|
2017-02-02 18:32:49 +01:00
|
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
|
return return_pair<Get*, FRT>{nullptr};
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return static_cast<Get*>(nullptr);
|
2017-02-02 18:32:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get the object without locking (can be called from other method)
|
|
|
|
|
|
template <typename T, typename Get = T>
|
|
|
|
|
|
static inline std::shared_ptr<Get> get_unlocked(u32 id)
|
|
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
const auto found = find_id<T, Get>(id);
|
2017-01-25 01:45:36 +01:00
|
|
|
|
|
|
|
|
|
|
if (UNLIKELY(found == nullptr))
|
|
|
|
|
|
{
|
2017-02-02 18:32:49 +01:00
|
|
|
|
return nullptr;
|
2017-01-25 01:45:36 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-02 18:32:49 +01:00
|
|
|
|
return {found->second, static_cast<Get*>(found->second.get())};
|
2017-01-25 01:45:36 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get the object
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T, typename Get = T>
|
|
|
|
|
|
static inline std::shared_ptr<Get> get(u32 id)
|
2016-04-14 00:59:00 +02:00
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
|
reader_lock lock(id_manager::g_mutex);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
const auto found = find_id<T, Get>(id);
|
2015-07-08 17:01:59 +02:00
|
|
|
|
|
2016-04-27 00:27:24 +02:00
|
|
|
|
if (UNLIKELY(found == nullptr))
|
2016-04-14 00:59:00 +02:00
|
|
|
|
{
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return {found->second, static_cast<Get*>(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
|
2018-09-05 14:10:37 +02:00
|
|
|
|
template <typename T, typename Get = T, typename F, typename FRT = std::invoke_result_t<F, Get&>>
|
|
|
|
|
|
static inline std::conditional_t<std::is_void_v<FRT>, std::shared_ptr<Get>, return_pair<Get, FRT>> get(u32 id, F&& func)
|
2015-11-26 09:06:29 +01:00
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
|
reader_lock lock(id_manager::g_mutex);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
const auto found = find_id<T, Get>(id);
|
2016-05-13 16:01:48 +02:00
|
|
|
|
|
|
|
|
|
|
if (UNLIKELY(found == nullptr))
|
|
|
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
|
return {nullptr};
|
2016-05-13 16:01:48 +02:00
|
|
|
|
}
|
2015-07-08 17:01:59 +02:00
|
|
|
|
|
2017-01-25 18:50:30 +01:00
|
|
|
|
const auto ptr = static_cast<Get*>(found->second.get());
|
2017-01-25 01:45:36 +01:00
|
|
|
|
|
2018-09-05 14:10:37 +02:00
|
|
|
|
if constexpr (std::is_void_v<FRT>)
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
|
func(*ptr);
|
|
|
|
|
|
return {found->second, ptr};
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return {{found->second, ptr}, func(*ptr)};
|
2017-01-25 01:45:36 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// Access all objects of specified type. Returns the number of objects processed.
|
|
|
|
|
|
template <typename T, typename Get = T, typename F, typename FT = decltype(&std::decay_t<F>::operator()), typename FRT = typename function_traits<FT>::void_type>
|
2017-01-25 01:45:36 +01:00
|
|
|
|
static inline u32 select(F&& func, int = 0)
|
|
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
static_assert(id_manager::id_verify<T, Get>::value, "Invalid ID type combination");
|
|
|
|
|
|
|
2017-01-25 18:50:30 +01:00
|
|
|
|
reader_lock lock(id_manager::g_mutex);
|
2017-01-25 01:45:36 +01:00
|
|
|
|
|
|
|
|
|
|
u32 result = 0;
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
for (auto& id : g_map[get_type<T>()])
|
2015-07-08 17:01:59 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
if (id.second)
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
if (std::is_same<T, Get>::value || id.first.type() == get_type<Get>())
|
|
|
|
|
|
{
|
|
|
|
|
|
func(id.first, *static_cast<typename function_traits<FT>::object_type*>(id.second.get()));
|
|
|
|
|
|
result++;
|
|
|
|
|
|
}
|
2017-01-25 01:45:36 +01:00
|
|
|
|
}
|
2018-08-23 23:31:27 +02:00
|
|
|
|
}
|
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-29 17:50:18 +01:00
|
|
|
|
// Access all objects of specified type. If function result evaluates to true, stop and return the object and the value.
|
|
|
|
|
|
template <typename T, typename Get = T, typename F, typename FT = decltype(&std::decay_t<F>::operator()), typename FRT = typename function_traits<FT>::result_type>
|
2017-01-25 01:45:36 +01:00
|
|
|
|
static inline auto select(F&& func)
|
2016-05-13 16:01:48 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
static_assert(id_manager::id_verify<T, Get>::value, "Invalid ID type combination");
|
|
|
|
|
|
|
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
|
|
|
|
|
2017-01-25 18:50:30 +01:00
|
|
|
|
reader_lock lock(id_manager::g_mutex);
|
2016-05-13 16:01:48 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
for (auto& id : g_map[get_type<T>()])
|
2016-05-13 16:01:48 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
if (auto ptr = static_cast<object_type*>(id.second.get()))
|
2016-05-13 16:01:48 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
if (std::is_same<T, Get>::value || id.first.type() == get_type<Get>())
|
2016-05-13 16:01:48 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
if (FRT result = func(id.first, *ptr))
|
|
|
|
|
|
{
|
|
|
|
|
|
return result_type{{id.second, ptr}, 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
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
// Remove the ID
|
|
|
|
|
|
template <typename T, typename Get = T>
|
2018-09-05 15:24:11 +02:00
|
|
|
|
static inline bool remove(u32 id)
|
2016-05-13 16:01:48 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
std::shared_ptr<void> ptr;
|
2016-08-01 01:26:55 +02:00
|
|
|
|
{
|
2018-09-03 21:28:33 +02:00
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2016-08-01 01:26:55 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
if (const auto found = find_id<T, Get>(id))
|
2016-08-01 01:26:55 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
ptr = std::move(found->second);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
2016-08-01 01:26:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return true;
|
2015-08-04 12:46:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-01-25 01:45:36 +01:00
|
|
|
|
// Remove the ID and return the object
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T, typename Get = T>
|
2017-01-25 18:50:30 +01:00
|
|
|
|
static inline std::shared_ptr<Get> withdraw(u32 id)
|
2015-08-07 23:28:09 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
std::shared_ptr<void> ptr;
|
2016-04-14 00:59:00 +02:00
|
|
|
|
{
|
2018-09-03 21:28:33 +02:00
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2017-01-29 17:50:18 +01:00
|
|
|
|
|
|
|
|
|
|
if (const auto found = find_id<T, Get>(id))
|
|
|
|
|
|
{
|
|
|
|
|
|
ptr = std::move(found->second);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
2015-11-26 09:06:29 +01:00
|
|
|
|
}
|
2015-08-07 23:28:09 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return {ptr, static_cast<Get*>(ptr.get())};
|
2017-01-25 01:45:36 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Remove the ID after accessing the object under writer lock, return the object and propagate return value
|
2018-09-05 14:10:37 +02:00
|
|
|
|
template <typename T, typename Get = T, typename F, typename FRT = std::invoke_result_t<F, Get&>>
|
|
|
|
|
|
static inline std::conditional_t<std::is_void_v<FRT>, std::shared_ptr<Get>, return_pair<Get, FRT>> withdraw(u32 id, F&& func)
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
|
std::unique_lock lock(id_manager::g_mutex);
|
2017-01-25 01:45:36 +01:00
|
|
|
|
|
2018-09-05 14:10:37 +02:00
|
|
|
|
if (const auto found = find_id<T, Get>(id))
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
|
const auto _ptr = static_cast<Get*>(found->second.get());
|
2017-01-25 01:45:36 +01:00
|
|
|
|
|
2018-09-05 14:10:37 +02:00
|
|
|
|
if constexpr (std::is_void_v<FRT>)
|
2017-01-29 17:50:18 +01:00
|
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
|
func(*_ptr);
|
|
|
|
|
|
std::shared_ptr<void> ptr = std::move(found->second);
|
|
|
|
|
|
return {ptr, static_cast<Get*>(ptr.get())};
|
2017-01-29 17:50:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
else
|
2017-01-25 01:45:36 +01:00
|
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
|
FRT ret = func(*_ptr);
|
2017-01-25 01:45:36 +01:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
if (ret)
|
|
|
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
|
// If return value evaluates to true, don't delete the object (error code)
|
|
|
|
|
|
return {{found->second, _ptr}, std::move(ret)};
|
2017-01-29 17:50:18 +01:00
|
|
|
|
}
|
2017-01-25 01:45:36 +01:00
|
|
|
|
|
2018-09-05 14:10:37 +02:00
|
|
|
|
std::shared_ptr<void> ptr = std::move(found->second);
|
|
|
|
|
|
return {{ptr, static_cast<Get*>(ptr.get())}, std::move(ret)};
|
2016-05-13 16:01:48 +02:00
|
|
|
|
}
|
2015-07-01 00:25:52 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-05 14:10:37 +02:00
|
|
|
|
return {nullptr};
|
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.
|
2018-10-11 00:17:19 +02:00
|
|
|
|
static std::vector<std::shared_ptr<void>> g_vec;
|
2015-09-18 00:41:14 +02:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T>
|
2016-04-14 00:59:00 +02:00
|
|
|
|
static inline u32 get_type()
|
2015-09-18 00:41:14 +02:00
|
|
|
|
{
|
2016-04-27 00:27:24 +02:00
|
|
|
|
return id_manager::typeinfo::get_index<T>();
|
2016-04-14 00:59:00 +02:00
|
|
|
|
}
|
2015-08-06 15:05:33 +02:00
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
|
public:
|
|
|
|
|
|
// Initialize object manager
|
2016-04-27 00:27:24 +02:00
|
|
|
|
static void init();
|
2018-08-23 23:31:27 +02:00
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
|
// Remove all objects
|
2016-04-27 00:27:24 +02:00
|
|
|
|
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)
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T, typename Make = T, typename... Args>
|
2016-04-14 00:59:00 +02:00
|
|
|
|
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
|
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
|
std::shared_ptr<T> ptr;
|
|
|
|
|
|
{
|
2018-09-03 21:28:33 +02:00
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
|
auto& cur = g_vec[get_type<T>()];
|
2017-01-29 17:50:18 +01:00
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
|
if (!cur)
|
2016-04-14 00:59:00 +02:00
|
|
|
|
{
|
|
|
|
|
|
ptr = std::make_shared<Make>(std::forward<Args>(args)...);
|
2018-10-11 00:17:19 +02:00
|
|
|
|
cur = ptr;
|
2017-01-29 17:50:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return nullptr;
|
2016-04-14 00:59:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2015-09-18 00:41:14 +02:00
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
|
return ptr;
|
2015-09-18 00:41:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
|
// Create the object unconditionally (old object will be removed if it exists)
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T, typename Make = T, typename... Args>
|
2016-04-14 00:59:00 +02:00
|
|
|
|
static std::enable_if_t<std::is_constructible<Make, Args...>::value, std::shared_ptr<T>> make_always(Args&&... args)
|
2015-09-18 00:41:14 +02:00
|
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
|
std::shared_ptr<T> ptr;
|
|
|
|
|
|
std::shared_ptr<void> old;
|
|
|
|
|
|
{
|
2018-09-03 21:28:33 +02:00
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
|
auto& cur = g_vec[get_type<T>()];
|
2017-01-29 17:50:18 +01:00
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
|
ptr = std::make_shared<Make>(std::forward<Args>(args)...);
|
2018-10-11 00:17:19 +02:00
|
|
|
|
old = std::move(cur);
|
|
|
|
|
|
cur = ptr;
|
2015-11-26 09:06:29 +01:00
|
|
|
|
}
|
2015-08-06 17:55:19 +02:00
|
|
|
|
|
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
|
2018-11-20 16:35:06 +01:00
|
|
|
|
template <typename T, typename F, typename... Args>
|
|
|
|
|
|
static auto import(F&& provider, Args&&... args) -> decltype(static_cast<std::shared_ptr<T>>(provider(std::forward<Args>(args)...)))
|
2015-08-10 21:39:52 +02:00
|
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
|
std::shared_ptr<T> ptr;
|
|
|
|
|
|
{
|
2018-09-03 21:28:33 +02:00
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2015-08-10 21:39:52 +02:00
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
|
auto& cur = g_vec[get_type<T>()];
|
2017-01-29 17:50:18 +01:00
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
|
if (!cur)
|
2016-04-14 00:59:00 +02:00
|
|
|
|
{
|
2018-11-20 16:35:06 +01:00
|
|
|
|
ptr = provider(std::forward<Args>(args)...);
|
2015-08-10 21:39:52 +02:00
|
|
|
|
|
2017-01-31 13:57:32 +01:00
|
|
|
|
if (ptr)
|
|
|
|
|
|
{
|
2018-10-11 00:17:19 +02:00
|
|
|
|
cur = ptr;
|
2017-01-31 13:57:32 +01:00
|
|
|
|
}
|
2017-01-29 17:50:18 +01:00
|
|
|
|
}
|
2017-01-31 13:57:32 +01:00
|
|
|
|
|
|
|
|
|
|
if (!ptr)
|
2017-01-29 17:50:18 +01:00
|
|
|
|
{
|
|
|
|
|
|
return nullptr;
|
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)
|
2018-11-20 16:35:06 +01:00
|
|
|
|
template <typename T, typename F, typename... Args>
|
|
|
|
|
|
static auto import_always(F&& provider, Args&&... args) -> decltype(static_cast<std::shared_ptr<T>>(provider(std::forward<Args>(args)...)))
|
2015-08-06 15:05:33 +02:00
|
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
|
std::shared_ptr<T> ptr;
|
|
|
|
|
|
std::shared_ptr<void> old;
|
|
|
|
|
|
{
|
2018-09-03 21:28:33 +02:00
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2015-08-06 15:05:33 +02:00
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
|
auto& cur = g_vec[get_type<T>()];
|
2017-01-29 17:50:18 +01:00
|
|
|
|
|
2018-11-20 16:35:06 +01:00
|
|
|
|
ptr = provider(std::forward<Args>(args)...);
|
2015-08-06 15:05:33 +02:00
|
|
|
|
|
2017-01-31 13:57:32 +01:00
|
|
|
|
if (ptr)
|
|
|
|
|
|
{
|
2018-10-11 00:17:19 +02:00
|
|
|
|
old = std::move(cur);
|
|
|
|
|
|
cur = ptr;
|
2017-01-31 13:57:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
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)
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T, typename Make = T, typename... Args>
|
2016-04-14 00:59:00 +02:00
|
|
|
|
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
|
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
|
std::shared_ptr<T> ptr;
|
2015-08-06 15:05:33 +02:00
|
|
|
|
{
|
2018-09-03 21:28:33 +02:00
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
|
auto& old = g_vec[get_type<T>()];
|
2017-01-29 17:50:18 +01:00
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
|
if (old)
|
2016-04-14 00:59:00 +02:00
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return {old, static_cast<T*>(old.get())};
|
2016-04-14 00:59:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
ptr = std::make_shared<Make>(std::forward<Args>(args)...);
|
2018-10-11 00:17:19 +02:00
|
|
|
|
old = ptr;
|
2016-04-14 00:59:00 +02:00
|
|
|
|
}
|
2015-08-06 15:05:33 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
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
|
|
|
|
|
2017-02-22 10:57:39 +01:00
|
|
|
|
// Unsafe version of check(), can be used in some cases
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
|
static inline T* check_unlocked()
|
|
|
|
|
|
{
|
2018-10-11 00:17:19 +02:00
|
|
|
|
return static_cast<T*>(g_vec[get_type<T>()].get());
|
2017-02-22 10:57:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
|
// Check whether the object exists
|
2017-02-02 18:32:49 +01:00
|
|
|
|
template <typename T>
|
|
|
|
|
|
static inline T* check()
|
2015-08-06 17:55:19 +02:00
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
|
reader_lock lock(id_manager::g_mutex);
|
2015-08-06 17:55:19 +02:00
|
|
|
|
|
2017-02-22 10:57:39 +01:00
|
|
|
|
return check_unlocked<T>();
|
2016-04-14 00:59:00 +02:00
|
|
|
|
}
|
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)
|
2017-01-29 17:50:18 +01:00
|
|
|
|
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
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
|
reader_lock lock(id_manager::g_mutex);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
|
auto& ptr = g_vec[get_type<T>()];
|
2015-11-26 09:06:29 +01:00
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
|
return {ptr, static_cast<T*>(ptr.get())};
|
2016-04-14 00:59:00 +02:00
|
|
|
|
}
|
2015-11-26 09:06:29 +01:00
|
|
|
|
|
|
|
|
|
|
// Delete the object
|
2017-01-29 17:50:18 +01:00
|
|
|
|
template <typename T>
|
2018-09-05 15:24:11 +02:00
|
|
|
|
static inline bool remove()
|
2015-11-26 09:06:29 +01:00
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
|
std::shared_ptr<void> ptr;
|
|
|
|
|
|
{
|
2018-09-03 21:28:33 +02:00
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2018-10-11 00:17:19 +02:00
|
|
|
|
ptr = std::move(g_vec[get_type<T>()]);
|
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
|
2017-01-29 17:50:18 +01:00
|
|
|
|
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 18:50:30 +01:00
|
|
|
|
std::shared_ptr<void> ptr;
|
|
|
|
|
|
{
|
2018-09-03 21:28:33 +02:00
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2018-10-11 00:17:19 +02:00
|
|
|
|
ptr = std::move(g_vec[get_type<T>()]);
|
2015-11-26 09:06:29 +01:00
|
|
|
|
}
|
2017-01-29 17:50:18 +01:00
|
|
|
|
|
|
|
|
|
|
return {ptr, static_cast<T*>(ptr.get())};
|
2015-08-06 17:55:19 +02:00
|
|
|
|
}
|
2016-04-14 00:59:00 +02:00
|
|
|
|
};
|
2018-10-01 19:57:08 +02:00
|
|
|
|
|
|
|
|
|
|
#include "Utilities/typemap.h"
|
|
|
|
|
|
|
|
|
|
|
|
extern utils::typemap g_typemap;
|
|
|
|
|
|
|
|
|
|
|
|
constexpr utils::typemap* g_idm = &g_typemap;
|
|
|
|
|
|
|
|
|
|
|
|
using utils::id_new;
|
|
|
|
|
|
using utils::id_any;
|
|
|
|
|
|
using utils::id_always;
|