mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-16 11:48:36 +12:00
Implement stx::typeinfo_v (util/typeindices.hpp)
Move and generalize logic from typemap.h
This commit is contained in:
parent
9f9309055f
commit
4df1c16099
2 changed files with 153 additions and 89 deletions
|
@ -4,6 +4,7 @@
|
||||||
#include "mutex.h"
|
#include "mutex.h"
|
||||||
#include "cond.h"
|
#include "cond.h"
|
||||||
#include "util/atomic.hpp"
|
#include "util/atomic.hpp"
|
||||||
|
#include "util/typeindices.hpp"
|
||||||
#include "VirtualMemory.h"
|
#include "VirtualMemory.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -92,7 +93,6 @@ namespace utils
|
||||||
// Type information
|
// Type information
|
||||||
struct typeinfo_base
|
struct typeinfo_base
|
||||||
{
|
{
|
||||||
uint type = 0;
|
|
||||||
uint size = 0;
|
uint size = 0;
|
||||||
uint align = 0;
|
uint align = 0;
|
||||||
uint count = 0;
|
uint count = 0;
|
||||||
|
@ -100,84 +100,27 @@ namespace utils
|
||||||
|
|
||||||
constexpr typeinfo_base() noexcept = default;
|
constexpr typeinfo_base() noexcept = default;
|
||||||
|
|
||||||
protected:
|
template <typename T>
|
||||||
// Next typeinfo in linked list
|
static void call_destructor(typemap_block* ptr) noexcept;
|
||||||
typeinfo_base* next = 0;
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend struct typeinfo;
|
static constexpr typeinfo_base make_typeinfo() noexcept
|
||||||
|
|
||||||
friend class typecounter;
|
|
||||||
|
|
||||||
friend class typemap_block;
|
|
||||||
friend class typemap;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline typeinfo_base g_sh{};
|
|
||||||
|
|
||||||
// Class for automatic type registration
|
|
||||||
class typecounter
|
|
||||||
{
|
|
||||||
// Linked list built at global initialization time
|
|
||||||
typeinfo_base* first = &g_sh<void>;
|
|
||||||
typeinfo_base* next = first;
|
|
||||||
typeinfo_base* last = first;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
friend struct typeinfo;
|
|
||||||
|
|
||||||
friend class typemap_block;
|
|
||||||
friend class typemap;
|
|
||||||
|
|
||||||
public:
|
|
||||||
constexpr typecounter() noexcept = default;
|
|
||||||
|
|
||||||
// Get next type id, or total type count
|
|
||||||
operator uint() const
|
|
||||||
{
|
{
|
||||||
return last->type + 1;
|
static_assert(alignof(T) < 4096);
|
||||||
|
|
||||||
|
typeinfo_base r;
|
||||||
|
r.size = uint{sizeof(T)};
|
||||||
|
r.align = uint{alignof(T)};
|
||||||
|
r.count = typeinfo_count<T>::max_count;
|
||||||
|
r.clean = &call_destructor<T>;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Global typecounter instance
|
|
||||||
inline typecounter g_typecounter{};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct typeinfo : typeinfo_base
|
uint get_typeid() noexcept
|
||||||
{
|
{
|
||||||
static void call_destructor(class typemap_block* ptr);
|
return stx::type_counter<typeinfo_base>::type<std::decay_t<T>>.index();
|
||||||
|
|
||||||
typeinfo();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Type information for each used type
|
|
||||||
template <typename T>
|
|
||||||
inline const typeinfo<T> g_typeinfo{};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
typeinfo<T>::typeinfo()
|
|
||||||
{
|
|
||||||
static_assert(alignof(T) < 4096);
|
|
||||||
|
|
||||||
this->type = g_typecounter;
|
|
||||||
this->size = uint{sizeof(T)};
|
|
||||||
this->align = uint{alignof(T)};
|
|
||||||
this->count = typeinfo_count<T>::max_count;
|
|
||||||
this->clean = &call_destructor;
|
|
||||||
|
|
||||||
if (this != &g_typeinfo<T>)
|
|
||||||
{
|
|
||||||
// Protect global state against unrelated constructions of typeinfo<> objects
|
|
||||||
this->type = g_typeinfo<T>.type;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Update linked list
|
|
||||||
g_typecounter.next->next = this;
|
|
||||||
g_typecounter.next = this;
|
|
||||||
g_typecounter.last = this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal, control block for a particular object
|
// Internal, control block for a particular object
|
||||||
|
@ -208,7 +151,7 @@ namespace utils
|
||||||
static_assert(sizeof(typemap_block) == 8);
|
static_assert(sizeof(typemap_block) == 8);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void typeinfo<T>::call_destructor(typemap_block* ptr)
|
void typeinfo_base::call_destructor(typemap_block* ptr) noexcept
|
||||||
{
|
{
|
||||||
ptr->get_ptr<T>()->~T();
|
ptr->get_ptr<T>()->~T();
|
||||||
}
|
}
|
||||||
|
@ -557,7 +500,7 @@ namespace utils
|
||||||
|
|
||||||
static uint type_index()
|
static uint type_index()
|
||||||
{
|
{
|
||||||
return g_typeinfo<std::decay_t<T>>.type;
|
return get_typeid<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool type_const()
|
static constexpr bool type_const()
|
||||||
|
@ -586,8 +529,7 @@ namespace utils
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typemap_head* get_head() const
|
typemap_head* get_head() const
|
||||||
{
|
{
|
||||||
using _type = std::decay_t<T>;
|
return &m_map[get_typeid<T>() - 1];
|
||||||
return &m_map[g_typeinfo<_type>.type];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -619,10 +561,7 @@ namespace utils
|
||||||
// Recreate, also required if constructed without initialization.
|
// Recreate, also required if constructed without initialization.
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
// Kill the ability to register more types (should segfault on attempt)
|
if (!stx::typeinfo_v<typeinfo_base>.count())
|
||||||
g_typecounter.next = nullptr;
|
|
||||||
|
|
||||||
if (g_typecounter <= 1)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -630,13 +569,14 @@ namespace utils
|
||||||
// Recreate and copy some type information
|
// Recreate and copy some type information
|
||||||
if (m_map == nullptr)
|
if (m_map == nullptr)
|
||||||
{
|
{
|
||||||
m_map = new typemap_head[g_typecounter]();
|
m_map = new typemap_head[stx::typeinfo_v<typeinfo_base>.count()]();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto type = g_typecounter.first;
|
auto type = stx::typeinfo_v<typeinfo_base>.begin();
|
||||||
|
auto _end = stx::typeinfo_v<typeinfo_base>.end();
|
||||||
|
|
||||||
for (uint i = 0; type; i++, type = type->next)
|
for (uint i = 0; type != _end; i++, ++type)
|
||||||
{
|
{
|
||||||
// Delete objects (there shall be no threads accessing them)
|
// Delete objects (there shall be no threads accessing them)
|
||||||
const uint lim = m_map[i].m_count != 1 ? +m_map[i].m_limit : 1;
|
const uint lim = m_map[i].m_count != 1 ? +m_map[i].m_limit : 1;
|
||||||
|
@ -647,7 +587,7 @@ namespace utils
|
||||||
|
|
||||||
if (const uint type_id = block->m_type)
|
if (const uint type_id = block->m_type)
|
||||||
{
|
{
|
||||||
m_map[type_id].clean(block);
|
m_map[type_id - 1].clean(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,9 +604,10 @@ namespace utils
|
||||||
if (m_memory == nullptr)
|
if (m_memory == nullptr)
|
||||||
{
|
{
|
||||||
// Determine total size, copy typeinfo
|
// Determine total size, copy typeinfo
|
||||||
auto type = g_typecounter.first;
|
auto type = stx::typeinfo_v<typeinfo_base>.begin();
|
||||||
|
auto _end = stx::typeinfo_v<typeinfo_base>.end();
|
||||||
|
|
||||||
for (uint i = 0; type; i++, type = type->next)
|
for (uint i = 0; type != _end; i++, ++type)
|
||||||
{
|
{
|
||||||
const uint align = type->align;
|
const uint align = type->align;
|
||||||
const uint ssize = ::align<uint>(sizeof(typemap_block), align) + ::align(type->size, align);
|
const uint ssize = ::align<uint>(sizeof(typemap_block), align) + ::align(type->size, align);
|
||||||
|
@ -693,7 +634,7 @@ namespace utils
|
||||||
utils::memory_commit(m_memory, m_total);
|
utils::memory_commit(m_memory, m_total);
|
||||||
|
|
||||||
// Update pointers
|
// Update pointers
|
||||||
for (uint i = 0, n = g_typecounter; i < n; i++)
|
for (uint i = 0, n = stx::typeinfo_v<typeinfo_base>.count(); i < n; i++)
|
||||||
{
|
{
|
||||||
if (m_map[i].m_count)
|
if (m_map[i].m_count)
|
||||||
{
|
{
|
||||||
|
@ -725,7 +666,7 @@ namespace utils
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint type_id = g_typeinfo<std::decay_t<Type>>.type;
|
const uint type_id = get_typeid<Type>();
|
||||||
|
|
||||||
using id_tag = std::decay_t<Arg>;
|
using id_tag = std::decay_t<Arg>;
|
||||||
|
|
||||||
|
@ -845,7 +786,7 @@ namespace utils
|
||||||
{
|
{
|
||||||
using id_tag = std::decay_t<Arg>;
|
using id_tag = std::decay_t<Arg>;
|
||||||
|
|
||||||
const uint type_id = g_typeinfo<std::decay_t<Type>>.type;
|
const uint type_id = get_typeid<Type>();
|
||||||
|
|
||||||
if constexpr (std::is_same_v<id_tag, id_new_t>)
|
if constexpr (std::is_same_v<id_tag, id_new_t>)
|
||||||
{
|
{
|
||||||
|
@ -1085,7 +1026,7 @@ namespace utils
|
||||||
static_assert(!std::is_array_v<Type>);
|
static_assert(!std::is_array_v<Type>);
|
||||||
static_assert(!std::is_void_v<Type>);
|
static_assert(!std::is_void_v<Type>);
|
||||||
|
|
||||||
const uint type_id = g_typeinfo<std::decay_t<decode_t<Type>>>.type;
|
const uint type_id = get_typeid<decode_t<Type>>();
|
||||||
|
|
||||||
typemap_head* head = get_head<decode_t<Type>>();
|
typemap_head* head = get_head<decode_t<Type>>();
|
||||||
|
|
||||||
|
|
123
rpcs3/util/typeindices.hpp
Normal file
123
rpcs3/util/typeindices.hpp
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace stx
|
||||||
|
{
|
||||||
|
template <typename Info>
|
||||||
|
class type_counter;
|
||||||
|
|
||||||
|
// Type information for given Info type, also serving as tag
|
||||||
|
template <typename Info>
|
||||||
|
class type_info final : public Info
|
||||||
|
{
|
||||||
|
// Current type id (non-zero)
|
||||||
|
unsigned type = 0;
|
||||||
|
|
||||||
|
// Next typeinfo in linked list
|
||||||
|
type_info* next = nullptr;
|
||||||
|
|
||||||
|
type_info(Info info, decltype(sizeof(int))) noexcept;
|
||||||
|
|
||||||
|
friend type_counter<Info>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr type_info() noexcept = default;
|
||||||
|
|
||||||
|
unsigned index() const
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class for automatic type registration for given Info type
|
||||||
|
template <typename Info>
|
||||||
|
class type_counter final
|
||||||
|
{
|
||||||
|
// Dummy first element to simplify list filling logic
|
||||||
|
type_info<Info> first{};
|
||||||
|
|
||||||
|
// Linked list built at global initialization time
|
||||||
|
type_info<Info>* next = &first;
|
||||||
|
|
||||||
|
friend type_info<Info>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr type_counter() noexcept = default;
|
||||||
|
|
||||||
|
unsigned count() const
|
||||||
|
{
|
||||||
|
return next->index();
|
||||||
|
}
|
||||||
|
|
||||||
|
class const_iterator
|
||||||
|
{
|
||||||
|
const type_info<Info>* ptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const_iterator(const type_info<Info>* ptr)
|
||||||
|
: ptr(ptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const type_info<Info>& operator*() const
|
||||||
|
{
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const type_info<Info>* operator->() const
|
||||||
|
{
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator& operator++()
|
||||||
|
{
|
||||||
|
ptr = ptr->next;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator operator++(int)
|
||||||
|
{
|
||||||
|
const_iterator r = ptr;
|
||||||
|
ptr = ptr->next;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const const_iterator& r) const
|
||||||
|
{
|
||||||
|
return ptr == r.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const const_iterator& r) const
|
||||||
|
{
|
||||||
|
return ptr != r.ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return first.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global type info instance
|
||||||
|
template <typename T>
|
||||||
|
static inline const type_info<Info> type{Info::template make_typeinfo<T>(), sizeof(T)};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global typecounter instance
|
||||||
|
template <typename Info>
|
||||||
|
inline type_counter<Info> typeinfo_v{};
|
||||||
|
|
||||||
|
template <typename Info>
|
||||||
|
type_info<Info>::type_info(Info info, decltype(sizeof(int))) noexcept
|
||||||
|
: Info(info)
|
||||||
|
, type(typeinfo_v<Info>.count() + 1)
|
||||||
|
{
|
||||||
|
// Update linked list
|
||||||
|
typeinfo_v<Info>.next->next = this;
|
||||||
|
typeinfo_v<Info>.next = this;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue