diff --git a/rpcs3/util/fixed_typemap.hpp b/rpcs3/util/fixed_typemap.hpp index 01c8526111..e84eb20587 100644 --- a/rpcs3/util/fixed_typemap.hpp +++ b/rpcs3/util/fixed_typemap.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace stx @@ -50,6 +51,9 @@ namespace stx std::unique_ptr m_list; + std::unique_ptr m_order; + unsigned long long m_init_count = 0; + public: constexpr manual_fixed_typemap() noexcept = default; @@ -58,6 +62,8 @@ namespace stx manual_fixed_typemap(manual_fixed_typemap&& r) noexcept { std::swap(m_list, r.m_list); + std::swap(m_order, r.m_order); + std::swap(m_init_count, r.m_init_count); } manual_fixed_typemap& operator=(const manual_fixed_typemap&) = delete; @@ -66,20 +72,64 @@ namespace stx { manual_fixed_typemap x(std::move(*this)); std::swap(m_list, x.m_list); + std::swap(m_order, x.m_order); + std::swap(m_init_count, x.m_init_count); } // Destroy all objects and keep them in uninitialized state, must be called first void reset() noexcept { + const auto total_count = stx::typelist_v.count(); + if (!m_list) { - m_list = std::make_unique(stx::typelist_v.count()); + m_list = std::make_unique(total_count); + m_order = std::make_unique(total_count); return; } + // Destroy list element + struct destroy_info + { + void** object_pointer; + unsigned long long created; + void(*destroy)(void*& ptr) noexcept; + }; + + auto all_data = std::make_unique(stx::typelist_v.count()); + + // Actual number of created objects + unsigned _max = 0; + + // Create destroy list for (auto& type : stx::typelist_v) { - type.destroy(m_list[type.index()]); + if (m_order[type.index()] == 0) + { + // Skip object if not created + continue; + } + + all_data[_max].object_pointer = &m_list[type.index()]; + all_data[_max].created = m_order[type.index()]; + all_data[_max].destroy = type.destroy; + + // Clear creation order + m_order[type.index()] = 0; + _max++; + } + + // Sort destroy list according to absolute creation order + std::sort(all_data.get(), all_data.get() + _max, [](const destroy_info& a, const destroy_info& b) + { + // Destroy order is the inverse of creation order + return a.created > b.created; + }); + + // Destroy objects in correct order + for (unsigned i = 0; i < _max; i++) + { + all_data[i].destroy(*all_data[i].object_pointer); } } @@ -89,6 +139,12 @@ namespace stx for (auto& type : stx::typelist_v) { type.create(m_list[type.index()]); + + // Allocate initialization order id + if (m_list[type.index()]) + { + m_order[type.index()] = ++m_init_count; + } } } @@ -104,6 +160,7 @@ namespace stx } As* obj = new std::decay_t(std::forward(args)...); + m_order[stx::typeindex>()] = ++m_init_count; ptr = static_cast(obj); return obj; }