diff --git a/rpcs3/util/auto_typemap.hpp b/rpcs3/util/auto_typemap.hpp index 08a9783b3e..e1ef056edb 100644 --- a/rpcs3/util/auto_typemap.hpp +++ b/rpcs3/util/auto_typemap.hpp @@ -1,5 +1,6 @@ #pragma once +#include "util/types.hpp" #include "util/typeindices.hpp" #include @@ -8,41 +9,41 @@ namespace stx { // Simplified typemap with exactly one object of each used type, non-moveable. - template - class auto_typemap + template + class alignas(Align) auto_typemap { // Save default constructor and destructor struct typeinfo { - void(*create)(void*& ptr, auto_typemap&) noexcept; + bool(*create)(uchar* ptr, auto_typemap&) noexcept; void(*destroy)(void* ptr) noexcept; template - static void call_ctor(void*& ptr, auto_typemap& _this) noexcept + static bool call_ctor(uchar* ptr, auto_typemap& _this) noexcept { - // Don't overwrite if already exists - if (!ptr) { // Allow passing reference to "this" if constexpr (std::is_constructible_v) { - ptr = new T(_this); - return; + new (ptr) T(_this); + return true; } // Call default constructor only if available if constexpr (std::is_default_constructible_v) { - ptr = new T(); - return; + new (ptr) T(); + return true; } } + + return false; } template static void call_dtor(void* ptr) noexcept { - delete static_cast(ptr); + std::launder(static_cast(ptr))->~T(); } template @@ -55,8 +56,12 @@ namespace stx } }; - // Raw pointers to existing objects (may be nullptr) - void** m_list; + // Objects + union + { + uchar* m_list; + mutable uchar m_data[Size ? Size : 1]; + }; // Creation order for each object (used to reverse destruction order) void** m_order; @@ -64,23 +69,44 @@ namespace stx // Helper for destroying in reverse order const typeinfo** m_info; + // Indicates whether object is created at given index + bool* m_init; + public: auto_typemap() noexcept - : m_list(new void*[stx::typelist().count()]{}) - , m_order(new void*[stx::typelist().count()]) + : m_order(new void*[stx::typelist().count()]) , m_info(new const typeinfo*[stx::typelist().count()]) + , m_init(new bool[stx::typelist().count()]{}) { + if constexpr (Size == 0) + { + if (stx::typelist().align() > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + m_list = static_cast(::operator new(usz{stx::typelist().size()}, std::align_val_t{stx::typelist().align()})); + } + else + { + m_list = new uchar[stx::typelist().size()]; + } + } + else + { + ensure(Size >= stx::typelist().size()); + ensure(Align >= stx::typelist().align()); + m_data[0] = 0; + } + for (const auto& type : stx::typelist()) { - const unsigned id = type.index(); - - type.create(m_list[id], *this); + const u32 id = type.index(); + uchar* data = (Size ? +m_data : m_list) + type.pos(); // Allocate initialization order id - if (m_list[id]) + if (type.create(data, *this)) { - *m_order++ = m_list[id]; + *m_order++ = data; *m_info++ = &type; + m_init[id] = true; } } } @@ -92,11 +118,11 @@ namespace stx ~auto_typemap() { // Get actual number of created objects - unsigned _max = 0; + u32 _max = 0; for (const auto& type : stx::typelist()) { - if (m_list[type.index()]) + if (m_init[type.index()]) { // Skip object if not created _max++; @@ -110,16 +136,28 @@ namespace stx } // Pointers should be restored to their positions + delete[] m_init; delete[] m_info; delete[] m_order; - delete[] m_list; + + if constexpr (Size == 0) + { + if (stx::typelist().align() > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + ::operator delete[](m_list, std::align_val_t{stx::typelist().align()}); + } + else + { + delete[] m_list; + } + } } // Check if object is not initialized but shall be initialized first (to use in initializing other objects) template void need() noexcept { - if (!m_list[stx::typeindex>()]) + if (!m_init[stx::typeindex>()]) { if constexpr (std::is_constructible_v) { @@ -139,18 +177,25 @@ namespace stx template As* init(Args&&... args) noexcept { - auto& ptr = m_list[stx::typeindex>()]; - - if (ptr) + if (std::exchange(m_init[stx::typeindex, std::decay_t>()], true)) { // Already exists, recreation is not supported (may be added later) return nullptr; } - As* obj = new std::decay_t(std::forward(args)...); + As* obj = nullptr; + + if constexpr (Size != 0) + { + obj = new (m_data + stx::typeoffset>()) std::decay_t(std::forward(args)...); + } + else + { + obj = new (m_list + stx::typeoffset>()) std::decay_t(std::forward(args)...); + } + *m_order++ = obj; - *m_info++ = &stx::typedata>(); - ptr = static_cast(obj); + *m_info++ = &stx::typedata, std::decay_t>(); return obj; } @@ -163,11 +208,36 @@ namespace stx return init(std::forward(args)...); } + template + bool is_init() const noexcept + { + return m_init[stx::typeindex>()]; + } + // Obtain object reference template T& get() const noexcept { - return *static_cast(m_list[stx::typeindex>()]); + if constexpr (Size != 0) + { + return *std::launder(reinterpret_cast(m_data + stx::typeoffset>())); + } + else + { + return *std::launder(reinterpret_cast(m_list + stx::typeoffset>())); + } + } + + // Obtain object pointer if initialized + template + T* try_get() const noexcept + { + if (is_init()) + { + [[likely]] return &get(); + } + + [[unlikely]] return nullptr; } }; }