diff --git a/Utilities/typemap.h b/Utilities/typemap.h index baa52b329f..36cdbdab04 100644 --- a/Utilities/typemap.h +++ b/Utilities/typemap.h @@ -4,6 +4,7 @@ #include "mutex.h" #include "cond.h" #include "util/atomic.hpp" +#include "util/typeindices.hpp" #include "VirtualMemory.h" #include @@ -92,7 +93,6 @@ namespace utils // Type information struct typeinfo_base { - uint type = 0; uint size = 0; uint align = 0; uint count = 0; @@ -100,84 +100,27 @@ namespace utils constexpr typeinfo_base() noexcept = default; - protected: - // Next typeinfo in linked list - typeinfo_base* next = 0; + template + static void call_destructor(typemap_block* ptr) noexcept; template - friend struct typeinfo; - - friend class typecounter; - - friend class typemap_block; - friend class typemap; - }; - - template - inline typeinfo_base g_sh{}; - - // Class for automatic type registration - class typecounter - { - // Linked list built at global initialization time - typeinfo_base* first = &g_sh; - typeinfo_base* next = first; - typeinfo_base* last = first; - - template - 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 + static constexpr typeinfo_base make_typeinfo() noexcept { - 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::max_count; + r.clean = &call_destructor; + return r; } }; - // Global typecounter instance - inline typecounter g_typecounter{}; - template - struct typeinfo : typeinfo_base + uint get_typeid() noexcept { - static void call_destructor(class typemap_block* ptr); - - typeinfo(); - }; - - // Type information for each used type - template - inline const typeinfo g_typeinfo{}; - - template - typeinfo::typeinfo() - { - static_assert(alignof(T) < 4096); - - this->type = g_typecounter; - this->size = uint{sizeof(T)}; - this->align = uint{alignof(T)}; - this->count = typeinfo_count::max_count; - this->clean = &call_destructor; - - if (this != &g_typeinfo) - { - // Protect global state against unrelated constructions of typeinfo<> objects - this->type = g_typeinfo.type; - } - else - { - // Update linked list - g_typecounter.next->next = this; - g_typecounter.next = this; - g_typecounter.last = this; - } + return stx::type_counter::type>.index(); } // Internal, control block for a particular object @@ -208,7 +151,7 @@ namespace utils static_assert(sizeof(typemap_block) == 8); template - void typeinfo::call_destructor(typemap_block* ptr) + void typeinfo_base::call_destructor(typemap_block* ptr) noexcept { ptr->get_ptr()->~T(); } @@ -557,7 +500,7 @@ namespace utils static uint type_index() { - return g_typeinfo>.type; + return get_typeid(); } static constexpr bool type_const() @@ -586,8 +529,7 @@ namespace utils template typemap_head* get_head() const { - using _type = std::decay_t; - return &m_map[g_typeinfo<_type>.type]; + return &m_map[get_typeid() - 1]; } public: @@ -619,10 +561,7 @@ namespace utils // Recreate, also required if constructed without initialization. void init() { - // Kill the ability to register more types (should segfault on attempt) - g_typecounter.next = nullptr; - - if (g_typecounter <= 1) + if (!stx::typeinfo_v.count()) { return; } @@ -630,13 +569,14 @@ namespace utils // Recreate and copy some type information if (m_map == nullptr) { - m_map = new typemap_head[g_typecounter](); + m_map = new typemap_head[stx::typeinfo_v.count()](); } else { - auto type = g_typecounter.first; + auto type = stx::typeinfo_v.begin(); + auto _end = stx::typeinfo_v.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) 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) { - m_map[type_id].clean(block); + m_map[type_id - 1].clean(block); } } @@ -664,9 +604,10 @@ namespace utils if (m_memory == nullptr) { // Determine total size, copy typeinfo - auto type = g_typecounter.first; + auto type = stx::typeinfo_v.begin(); + auto _end = stx::typeinfo_v.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 ssize = ::align(sizeof(typemap_block), align) + ::align(type->size, align); @@ -693,7 +634,7 @@ namespace utils utils::memory_commit(m_memory, m_total); // Update pointers - for (uint i = 0, n = g_typecounter; i < n; i++) + for (uint i = 0, n = stx::typeinfo_v.count(); i < n; i++) { if (m_map[i].m_count) { @@ -725,7 +666,7 @@ namespace utils return {}; } - const uint type_id = g_typeinfo>.type; + const uint type_id = get_typeid(); using id_tag = std::decay_t; @@ -845,7 +786,7 @@ namespace utils { using id_tag = std::decay_t; - const uint type_id = g_typeinfo>.type; + const uint type_id = get_typeid(); if constexpr (std::is_same_v) { @@ -1085,7 +1026,7 @@ namespace utils static_assert(!std::is_array_v); static_assert(!std::is_void_v); - const uint type_id = g_typeinfo>>.type; + const uint type_id = get_typeid>(); typemap_head* head = get_head>(); diff --git a/rpcs3/util/typeindices.hpp b/rpcs3/util/typeindices.hpp new file mode 100644 index 0000000000..ceb9142a50 --- /dev/null +++ b/rpcs3/util/typeindices.hpp @@ -0,0 +1,123 @@ +#pragma once + +namespace stx +{ + template + class type_counter; + + // Type information for given Info type, also serving as tag + template + 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; + + public: + constexpr type_info() noexcept = default; + + unsigned index() const + { + return type; + } + }; + + // Class for automatic type registration for given Info type + template + class type_counter final + { + // Dummy first element to simplify list filling logic + type_info first{}; + + // Linked list built at global initialization time + type_info* next = &first; + + friend type_info; + + public: + constexpr type_counter() noexcept = default; + + unsigned count() const + { + return next->index(); + } + + class const_iterator + { + const type_info* ptr; + + public: + const_iterator(const type_info* ptr) + : ptr(ptr) + { + } + + const type_info& operator*() const + { + return *ptr; + } + + const type_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 + static inline const type_info type{Info::template make_typeinfo(), sizeof(T)}; + }; + + // Global typecounter instance + template + inline type_counter typeinfo_v{}; + + template + type_info::type_info(Info info, decltype(sizeof(int))) noexcept + : Info(info) + , type(typeinfo_v.count() + 1) + { + // Update linked list + typeinfo_v.next->next = this; + typeinfo_v.next = this; + } +}