From d788b12a8eba7266861d6df3a11c2743b6725dac Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 3 Feb 2021 21:14:31 +0300 Subject: [PATCH] fixed_typemap.hpp: reduce indirection Backported some changes from auto_typemap.hpp Implemented methods init(), reset(), clear() Disabled recreation support. --- rpcs3/Emu/CMakeLists.txt | 1 - rpcs3/Emu/CPU/CPUThread.cpp | 4 +- rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp | 14 +- rpcs3/Emu/Cell/Modules/cellOskDialog.cpp | 2 +- rpcs3/Emu/IdManager.h | 4 +- rpcs3/Emu/Io/interception.cpp | 4 +- rpcs3/Emu/Memory/vm.cpp | 4 +- .../RSX/Overlays/overlay_message_dialog.cpp | 2 +- rpcs3/Emu/RSX/RSXThread.h | 4 +- rpcs3/Emu/System.cpp | 25 +- rpcs3/emucore.vcxproj | 3 - rpcs3/emucore.vcxproj.filters | 3 - rpcs3/rpcs3qt/cheat_manager.cpp | 3 +- rpcs3/rpcs3qt/debugger_frame.cpp | 4 +- rpcs3/rpcs3qt/main_window.cpp | 2 +- rpcs3/rpcs3qt/rsx_debugger.cpp | 4 +- rpcs3/rpcs3qt/save_data_dialog.cpp | 2 +- rpcs3/rpcs3qt/trophy_notification_helper.cpp | 2 +- rpcs3/util/fixed_typemap.cpp | 15 - rpcs3/util/fixed_typemap.hpp | 308 +++++++++++------- 20 files changed, 229 insertions(+), 181 deletions(-) delete mode 100644 rpcs3/util/fixed_typemap.cpp diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 2f9aef197c..1091e1832f 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -33,7 +33,6 @@ target_include_directories(rpcs3_emu # Utilities target_sources(rpcs3_emu PRIVATE ../util/atomic.cpp - ../util/fixed_typemap.cpp ../util/logs.cpp ../util/yaml.cpp ../util/cereal.cpp diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 9325d00c28..9dab9762cf 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -429,7 +429,7 @@ void cpu_thread::operator()() } } - while (!g_fxo->get()) + while (!g_fxo->is_init()) { if (Emu.IsStopped()) { @@ -1151,7 +1151,7 @@ void cpu_thread::stop_all() noexcept void cpu_thread::flush_profilers() noexcept { - if (!g_fxo->get()) + if (!g_fxo->is_init()) { profiler.fatal("cpu_thread::flush_profilers() has been called incorrectly."); return; diff --git a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp index 9290a3d6cd..d419e82703 100644 --- a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp @@ -107,7 +107,7 @@ struct msg_dlg_thread_info thread_ctrl::wait_for(10'000); } - if (auto manager = g_fxo->get()) + if (auto manager = g_fxo->try_get()) { if (auto dlg = manager->get()) { @@ -149,7 +149,7 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr msgString, const MsgDialogType _type{ type }; - if (auto manager = g_fxo->get()) + if (auto manager = g_fxo->try_get()) { if (manager->get()) { @@ -433,7 +433,7 @@ error_code cellMsgDialogClose(f32 delay) const u64 wait_until = get_guest_system_time() + static_cast(std::max(delay, 0.0f) * 1000); - if (auto manager = g_fxo->get()) + if (auto manager = g_fxo->try_get()) { if (auto dlg = manager->get()) { @@ -463,7 +463,7 @@ error_code cellMsgDialogAbort() { cellSysutil.warning("cellMsgDialogAbort()"); - if (auto manager = g_fxo->get()) + if (auto manager = g_fxo->try_get()) { if (auto dlg = manager->get()) { @@ -514,7 +514,7 @@ error_code cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::cptr m return CELL_MSGDIALOG_ERROR_PARAM; } - if (auto manager = g_fxo->get()) + if (auto manager = g_fxo->try_get()) { if (auto dlg = manager->get()) { @@ -546,7 +546,7 @@ error_code cellMsgDialogProgressBarReset(u32 progressBarIndex) { cellSysutil.warning("cellMsgDialogProgressBarReset(progressBarIndex=%d)", progressBarIndex); - if (auto manager = g_fxo->get()) + if (auto manager = g_fxo->try_get()) { if (auto dlg = manager->get()) { @@ -578,7 +578,7 @@ error_code cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta) { cellSysutil.warning("cellMsgDialogProgressBarInc(progressBarIndex=%d, delta=%d)", progressBarIndex, delta); - if (auto manager = g_fxo->get()) + if (auto manager = g_fxo->try_get()) { if (auto dlg = manager->get()) { diff --git a/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp index 4df615ff18..6afa0de1f3 100644 --- a/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp @@ -64,7 +64,7 @@ std::shared_ptr _get_osk_dialog(bool create = false) return nullptr; } - if (auto manager = g_fxo->get()) + if (auto manager = g_fxo->try_get()) { std::shared_ptr dlg = std::make_shared(); osk->dlg = manager->add(dlg); diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index f33e5ac0da..53d8a2b087 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -646,6 +646,6 @@ public: #include "util/fixed_typemap.hpp" -extern stx::manual_fixed_typemap g_fixed_typemap; +extern stx::manual_typemap g_fixed_typemap; -constexpr stx::manual_fixed_typemap* g_fxo = &g_fixed_typemap; +constexpr auto* g_fxo = &g_fixed_typemap; diff --git a/rpcs3/Emu/Io/interception.cpp b/rpcs3/Emu/Io/interception.cpp index 8a7fd12e13..3cbc3fa625 100644 --- a/rpcs3/Emu/Io/interception.cpp +++ b/rpcs3/Emu/Io/interception.cpp @@ -15,12 +15,12 @@ namespace input pad::SetIntercepted(intercepted); - if (const auto handler = g_fxo->get()) + if (const auto handler = g_fxo->try_get()) { handler->SetIntercepted(intercepted); } - if (const auto handler = g_fxo->get()) + if (const auto handler = g_fxo->try_get()) { handler->SetIntercepted(intercepted); } diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 76a0cf3079..e2c1ed43ec 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -718,7 +718,7 @@ namespace vm // Notify rsx that range has become valid // Note: This must be done *before* memory gets mapped while holding the vm lock, otherwise // the RSX might try to invalidate memory that got unmapped and remapped - if (const auto rsxthr = g_fxo->get()) + if (const auto rsxthr = g_fxo->try_get()) { rsxthr->on_notify_memory_mapped(addr, size); } @@ -906,7 +906,7 @@ namespace vm // Notify rsx to invalidate range // Note: This must be done *before* memory gets unmapped while holding the vm lock, otherwise // the RSX might try to call VirtualProtect on memory that is already unmapped - if (const auto rsxthr = g_fxo->get()) + if (const auto rsxthr = g_fxo->get(); g_fxo->is_init()) { rsxthr->on_notify_memory_unmapped(addr, size); } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message_dialog.cpp b/rpcs3/Emu/RSX/Overlays/overlay_message_dialog.cpp index c46d8a9037..f08510ed72 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_message_dialog.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_message_dialog.cpp @@ -268,7 +268,7 @@ namespace rsx // Only update the screen at about 60fps since updating it everytime slows down the process std::this_thread::sleep_for(16ms); - if (!g_fxo->get()) + if (!g_fxo->is_init()) { rsx_log.fatal("display_manager was improperly destroyed"); break; diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index ea059e9ed1..c22908ea26 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -656,7 +656,7 @@ namespace rsx void recover_fifo(); static void fifo_wake_delay(u64 div = 1); u32 get_fifo_cmd() const; - + std::string dump_regs() const override; void cpu_wait(bs_t old) override; @@ -974,7 +974,7 @@ namespace rsx inline thread* get_current_renderer() { - return g_fxo->get(); + return g_fxo->try_get(); } template diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index da1938452f..b4011014af 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -55,7 +55,8 @@ LOG_CHANNEL(sys_log, "SYS"); -stx::manual_fixed_typemap g_fixed_typemap; +// Preallocate 32 MiB +stx::manual_typemap g_fixed_typemap; bool g_use_rtm = false; u64 g_rtm_tx_limit1 = 0; @@ -138,7 +139,7 @@ void Emulator::Init(bool add_only) idm::init(); g_fxo->reset(); - g_fxo->init>(); + g_fxo->need>(); // Reset defaults, cache them g_cfg.from_default(); @@ -569,7 +570,7 @@ bool Emulator::BootRsxCapture(const std::string& path) g_cfg.video.disable_on_disk_shader_cache.set(true); vm::init(); - g_fxo->init(); + g_fxo->init(false); // PS3 'executable' m_state = system_state::ready; @@ -1095,7 +1096,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool m_state = system_state::ready; GetCallbacks().on_ready(); vm::init(); - g_fxo->init(); + g_fxo->init(false); Run(false); m_force_boot = false; @@ -1591,7 +1592,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool { ConfigurePPUCache(); - g_fxo->init(); + g_fxo->init(false); Emu.GetCallbacks().init_gs_render(); Emu.GetCallbacks().init_pad_handler(m_title_id); Emu.GetCallbacks().init_kb_handler(); @@ -1618,7 +1619,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool m_state = system_state::ready; GetCallbacks().on_ready(); vm::init(); - g_fxo->init(); + g_fxo->init(false); ppu_load_prx(ppu_prx, m_path); } else if (spu_exec.open(elf_file) == elf_error::ok) @@ -1627,7 +1628,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool m_state = system_state::ready; GetCallbacks().on_ready(); vm::init(); - g_fxo->init(); + g_fxo->init(false); spu_load_exec(spu_exec); } else @@ -1706,7 +1707,7 @@ void Emulator::Run(bool start_playtime) cpu.state.notify_one(cpu_flag::stop); }); - if (auto thr = g_fxo->get>()) + if (auto thr = g_fxo->try_get>()) { thr->state -= cpu_flag::stop; thr->state.notify_one(cpu_flag::stop); @@ -1747,7 +1748,7 @@ bool Emulator::Pause() idm::select>(on_select); idm::select>(on_select); - if (auto rsx = g_fxo->get()) + if (auto rsx = g_fxo->try_get()) { rsx->state += cpu_flag::dbg_global_pause; } @@ -1820,7 +1821,7 @@ void Emulator::Resume() idm::select>(on_select); idm::select>(on_select); - if (auto rsx = g_fxo->get()) + if (auto rsx = g_fxo->try_get()) { // TODO: notify? rsx->state -= cpu_flag::dbg_global_pause; @@ -1876,7 +1877,7 @@ void Emulator::Stop(bool restart) GetCallbacks().on_stop(); - if (auto rsx = g_fxo->get()) + if (auto rsx = g_fxo->try_get()) { // TODO: notify? rsx->state += cpu_flag::exit; @@ -1962,7 +1963,7 @@ bool Emulator::Quit(bool force_quit) const auto on_exit = []() { // Deinitialize object manager to prevent any hanging objects at program exit - *g_fxo = {}; + g_fxo->clear(); }; return GetCallbacks().try_to_quit(force_quit, on_exit); } diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 5ece3eea46..13c246b6dd 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -111,9 +111,6 @@ NotUsing true - - NotUsing - NotUsing diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 33c1897318..4f0d3f676d 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -881,9 +881,6 @@ Utilities - - Utilities - Utilities diff --git a/rpcs3/rpcs3qt/cheat_manager.cpp b/rpcs3/rpcs3qt/cheat_manager.cpp index 23baab8300..51e7760a40 100644 --- a/rpcs3/rpcs3qt/cheat_manager.cpp +++ b/rpcs3/rpcs3qt/cheat_manager.cpp @@ -447,7 +447,8 @@ bool cheat_engine::is_addr_safe(const u32 offset) if (Emu.IsStopped()) return false; - const auto ppum = g_fxo->get(); + const auto ppum = g_fxo->try_get(); + if (!ppum) { log_cheat.fatal("Failed to get ppu_module"); diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index 02bd401df9..1c3b48199b 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -264,7 +264,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) "\nKey R: Registers Editor for selected thread." "\nKey N: Show next instruction the thread will execute after marked instruction, does nothing if target is not predictable." "\nKey M: Show the Memory Viewer with initial address pointing to the marked instruction." - "\nKey I: Show RSX method detail." + "\nKey I: Show RSX method detail." "\nKey F10: Perform single-stepping on instructions." "\nKey F11: Perform step-over on instructions. (skip function calls)" "\nKey F1: Show this help dialog." @@ -431,7 +431,7 @@ cpu_thread* debugger_frame::get_cpu() return m_rsx; } - if (g_fxo->get() != m_rsx) + if (!g_fxo->is_init()) { m_rsx = nullptr; return m_rsx; diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index bdc6678233..e7effc555c 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -971,7 +971,7 @@ void main_window::DecryptSPRXLibraries() // Always start with no KLIC std::vector klics{u128{}}; - if (const auto keys = g_fxo->get()) + if (const auto keys = g_fxo->try_get()) { // Second klic: get it from a running game if (const u128 klic = keys->devKlic) diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index 85a4ec304a..63ebadec3a 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -373,8 +373,8 @@ void Buffer::showImage(const QImage& image) void Buffer::ShowWindowed() { - const auto render = rsx::get_current_renderer(); - if (!render) + //const auto render = rsx::get_current_renderer(); + if (!g_fxo->is_init()) return; // TODO: Is there any better way to choose the color buffers diff --git a/rpcs3/rpcs3qt/save_data_dialog.cpp b/rpcs3/rpcs3qt/save_data_dialog.cpp index 4ede1197c2..d1ea7dc87d 100644 --- a/rpcs3/rpcs3qt/save_data_dialog.cpp +++ b/rpcs3/rpcs3qt/save_data_dialog.cpp @@ -11,7 +11,7 @@ s32 save_data_dialog::ShowSaveDataList(std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet) { // TODO: Install native shell as an Emu callback - if (auto manager = g_fxo->get()) + if (auto manager = g_fxo->try_get()) { auto result = manager->create()->show(save_entries, focused, op, listSet); if (result != rsx::overlays::user_interface::selection_code::error) diff --git a/rpcs3/rpcs3qt/trophy_notification_helper.cpp b/rpcs3/rpcs3qt/trophy_notification_helper.cpp index f5aa7f2363..7eaa431e80 100644 --- a/rpcs3/rpcs3qt/trophy_notification_helper.cpp +++ b/rpcs3/rpcs3qt/trophy_notification_helper.cpp @@ -7,7 +7,7 @@ s32 trophy_notification_helper::ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector& trophy_icon_buffer) { - if (auto manager = g_fxo->get()) + if (auto manager = g_fxo->try_get()) { // Allow adding more than one trophy notification. The notification class manages scheduling auto popup = std::make_shared(); diff --git a/rpcs3/util/fixed_typemap.cpp b/rpcs3/util/fixed_typemap.cpp deleted file mode 100644 index 25616ffd71..0000000000 --- a/rpcs3/util/fixed_typemap.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "fixed_typemap.hpp" - -#include - -namespace stx::detail -{ - void destroy_info::sort_by_reverse_creation_order(destroy_info* begin, destroy_info* end) - { - std::sort(begin, end, [](const destroy_info& a, const destroy_info& b) - { - // Destroy order is the inverse of creation order - return a.created > b.created; - }); - } -} diff --git a/rpcs3/util/fixed_typemap.hpp b/rpcs3/util/fixed_typemap.hpp index bb18ba4685..b0a568ee16 100644 --- a/rpcs3/util/fixed_typemap.hpp +++ b/rpcs3/util/fixed_typemap.hpp @@ -1,54 +1,49 @@ #pragma once -#include +// Backported from auto_typemap.hpp as a more simple alternative + +#include "util/types.hpp" +#include "util/typeindices.hpp" + #include #include -#include namespace stx { - namespace detail - { - // Destroy list element - struct destroy_info - { - void** object_pointer; - unsigned long long created; - void(*destroy)(void*& ptr) noexcept; - - static void sort_by_reverse_creation_order(destroy_info* begin, destroy_info* end); - }; - } - - // Typemap with exactly one object of each used type, created on init() and destroyed on clear() - template - class manual_fixed_typemap + // Simplified typemap with exactly one object of each used type, non-moveable. Initialized on init(). Destroyed on clear(). + template + class alignas(Align) manual_typemap { // Save default constructor and destructor struct typeinfo { - void(*create)(void*& ptr) noexcept; - void(*destroy)(void*& ptr) noexcept; + bool(*create)(uchar* ptr, manual_typemap&) noexcept; + void(*destroy)(void* ptr) noexcept; template - static void call_ctor(void*& ptr) noexcept + static bool call_ctor(uchar* ptr, manual_typemap& _this) noexcept { - // Don't overwrite if already exists - if (!ptr) + // Allow passing reference to "this" + if constexpr (std::is_constructible_v) { - // Call default constructor only if available - if constexpr (std::is_default_constructible_v) - { - ptr = new T(); - } + new (ptr) T(_this); + return true; } + + // Call default constructor only if available + if constexpr (std::is_default_constructible_v) + { + new (ptr) T(); + return true; + } + + return false; } template - static void call_dtor(void*& ptr) noexcept + static void call_dtor(void* ptr) noexcept { - delete static_cast(ptr); - ptr = nullptr; + std::launder(static_cast(ptr))->~T(); } template @@ -61,138 +56,186 @@ namespace stx } }; - // Raw pointers to existing objects (may be nullptr) - std::unique_ptr m_list; + // Objects + union + { + uchar* m_list = nullptr; + mutable uchar m_data[Size ? Size : 1]; + }; // Creation order for each object (used to reverse destruction order) - std::unique_ptr m_order; + void** m_order = nullptr; - // Used to generate creation order (increased on every construction) - unsigned long long m_init_count = 0; + // Helper for destroying in reverse order + const typeinfo** m_info = nullptr; + + // Indicates whether object is created at given index + bool* m_init = nullptr; public: - constexpr manual_fixed_typemap() noexcept = default; + manual_typemap() noexcept = default; - manual_fixed_typemap(const manual_fixed_typemap&) = delete; + manual_typemap(const manual_typemap&) = delete; - manual_fixed_typemap(manual_fixed_typemap&& r) noexcept - : m_list(std::move(r.m_list)) - , m_order(std::move(r.m_order)) - , m_init_count(r.m_init_count) + manual_typemap& operator=(const manual_typemap&) = delete; + + ~manual_typemap() { - r.m_init_count = 0; + ensure(!m_init); } - manual_fixed_typemap& operator=(const manual_fixed_typemap&) = delete; - - manual_fixed_typemap& operator=(manual_fixed_typemap&& r) noexcept + void reset() { - manual_fixed_typemap x(std::move(r)); - std::swap(m_list, x.m_list); - std::swap(m_order, x.m_order); - std::swap(m_init_count, x.m_init_count); - return *this; - } - - ~manual_fixed_typemap() - { - if (!m_list && !m_order) + if (m_init) { - return; + clear(); } - reset(); - } + m_order = new void*[stx::typelist().count()]; + m_info = new const typeinfo*[stx::typelist().count()]; + m_init = new bool[stx::typelist().count()]{}; - // Destroy all objects and keep them in uninitialized state, must be called first - void reset() noexcept - { - const auto total_count = stx::typelist().count(); - - if (!m_list) + if constexpr (Size == 0) { - m_list = std::make_unique(total_count); - m_order = std::make_unique(total_count); - return; - } - - using detail::destroy_info; - - auto all_data = std::make_unique(stx::typelist().count()); - - // Actual number of created objects - unsigned _max = 0; - - // Create destroy list - for (auto& type : stx::typelist()) - { - if (m_order[type.index()] == 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; + } + } + + void init(bool reset = true) + { + if (reset) + { + this->reset(); + } + + for (const auto& type : stx::typelist()) + { + const u32 id = type.index(); + uchar* data = (Size ? +m_data : m_list) + type.pos(); + + // Allocate initialization order id + if (m_init[id]) { - // 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++; + if (type.create(data, *this)) + { + *m_order++ = data; + *m_info++ = &type; + m_init[id] = true; + } } - - // Sort destroy list according to absolute creation order - destroy_info::sort_by_reverse_creation_order(all_data.get(), all_data.get() + _max); - - // Destroy objects in correct order - for (unsigned i = 0; i < _max; i++) - { - all_data[i].destroy(*all_data[i].object_pointer); - } - - // Reset creation order since it now may be printed - m_init_count = 0; } - // Default initialize all objects if possible and not already initialized - void init() noexcept + void clear() { - for (auto& type : stx::typelist()) + if (!m_init) { - type.create(m_list[type.index()]); + return; + } - // Allocate initialization order id - if (m_list[type.index()]) + // Get actual number of created objects + u32 _max = 0; + + for (const auto& type : stx::typelist()) + { + if (m_init[type.index()]) { - m_order[type.index()] = ++m_init_count; + // Skip object if not created + _max++; } } + + // Destroy objects in reverse order + for (; _max; _max--) + { + (*--m_info)->destroy(*--m_order); + } + + // Pointers should be restored to their positions + delete[] m_init; + delete[] m_info; + delete[] m_order; + + 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; + } + } + + m_init = nullptr; + m_info = nullptr; + m_order = nullptr; + + if constexpr (Size == 0) + { + m_list = nullptr; + } } // Check if object is not initialized but shall be initialized first (to use in initializing other objects) template void need() noexcept { - if (!get()) + if (!m_init[stx::typeindex>()]) { - init(); + if constexpr (std::is_constructible_v) + { + init(*this); + return; + } + + if constexpr (std::is_default_constructible_v) + { + init(); + return; + } } } - // Explicitly (re)initialize object of type T possibly with dynamic type As and arguments + // Explicitly initialize object of type T possibly with dynamic type As and arguments 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)) { - delete static_cast(ptr); + // Already exists, recreation is not supported (may be added later) + return nullptr; } - As* obj = new std::decay_t(std::forward(args)...); - m_order[stx::typeindex>()] = ++m_init_count; - ptr = static_cast(obj); + 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, std::decay_t>(); return obj; } @@ -205,11 +248,36 @@ namespace stx return init(std::forward(args)...); } - // Obtain object pointer (thread safe just against other get calls) + template + bool is_init() const noexcept + { + return m_init[stx::typeindex>()]; + } + + // Obtain object pointer (may be uninitialized memory) 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; } }; }