fixed_typemap.hpp: reduce indirection

Backported some changes from auto_typemap.hpp
Implemented methods init(), reset(), clear()
Disabled recreation support.
This commit is contained in:
Nekotekina 2021-02-03 21:14:31 +03:00
parent 8a9320c4ef
commit d788b12a8e
20 changed files with 229 additions and 181 deletions

View file

@ -33,7 +33,6 @@ target_include_directories(rpcs3_emu
# Utilities # Utilities
target_sources(rpcs3_emu PRIVATE target_sources(rpcs3_emu PRIVATE
../util/atomic.cpp ../util/atomic.cpp
../util/fixed_typemap.cpp
../util/logs.cpp ../util/logs.cpp
../util/yaml.cpp ../util/yaml.cpp
../util/cereal.cpp ../util/cereal.cpp

View file

@ -429,7 +429,7 @@ void cpu_thread::operator()()
} }
} }
while (!g_fxo->get<cpu_profiler>()) while (!g_fxo->is_init<cpu_profiler>())
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
@ -1151,7 +1151,7 @@ void cpu_thread::stop_all() noexcept
void cpu_thread::flush_profilers() noexcept void cpu_thread::flush_profilers() noexcept
{ {
if (!g_fxo->get<cpu_profiler>()) if (!g_fxo->is_init<cpu_profiler>())
{ {
profiler.fatal("cpu_thread::flush_profilers() has been called incorrectly."); profiler.fatal("cpu_thread::flush_profilers() has been called incorrectly.");
return; return;

View file

@ -107,7 +107,7 @@ struct msg_dlg_thread_info
thread_ctrl::wait_for(10'000); thread_ctrl::wait_for(10'000);
} }
if (auto manager = g_fxo->get<rsx::overlays::display_manager>()) if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{ {
if (auto dlg = manager->get<rsx::overlays::message_dialog>()) if (auto dlg = manager->get<rsx::overlays::message_dialog>())
{ {
@ -149,7 +149,7 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
const MsgDialogType _type{ type }; const MsgDialogType _type{ type };
if (auto manager = g_fxo->get<rsx::overlays::display_manager>()) if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{ {
if (manager->get<rsx::overlays::message_dialog>()) if (manager->get<rsx::overlays::message_dialog>())
{ {
@ -433,7 +433,7 @@ error_code cellMsgDialogClose(f32 delay)
const u64 wait_until = get_guest_system_time() + static_cast<s64>(std::max<float>(delay, 0.0f) * 1000); const u64 wait_until = get_guest_system_time() + static_cast<s64>(std::max<float>(delay, 0.0f) * 1000);
if (auto manager = g_fxo->get<rsx::overlays::display_manager>()) if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{ {
if (auto dlg = manager->get<rsx::overlays::message_dialog>()) if (auto dlg = manager->get<rsx::overlays::message_dialog>())
{ {
@ -463,7 +463,7 @@ error_code cellMsgDialogAbort()
{ {
cellSysutil.warning("cellMsgDialogAbort()"); cellSysutil.warning("cellMsgDialogAbort()");
if (auto manager = g_fxo->get<rsx::overlays::display_manager>()) if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{ {
if (auto dlg = manager->get<rsx::overlays::message_dialog>()) if (auto dlg = manager->get<rsx::overlays::message_dialog>())
{ {
@ -514,7 +514,7 @@ error_code cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::cptr<char> m
return CELL_MSGDIALOG_ERROR_PARAM; return CELL_MSGDIALOG_ERROR_PARAM;
} }
if (auto manager = g_fxo->get<rsx::overlays::display_manager>()) if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{ {
if (auto dlg = manager->get<rsx::overlays::message_dialog>()) if (auto dlg = manager->get<rsx::overlays::message_dialog>())
{ {
@ -546,7 +546,7 @@ error_code cellMsgDialogProgressBarReset(u32 progressBarIndex)
{ {
cellSysutil.warning("cellMsgDialogProgressBarReset(progressBarIndex=%d)", progressBarIndex); cellSysutil.warning("cellMsgDialogProgressBarReset(progressBarIndex=%d)", progressBarIndex);
if (auto manager = g_fxo->get<rsx::overlays::display_manager>()) if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{ {
if (auto dlg = manager->get<rsx::overlays::message_dialog>()) if (auto dlg = manager->get<rsx::overlays::message_dialog>())
{ {
@ -578,7 +578,7 @@ error_code cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta)
{ {
cellSysutil.warning("cellMsgDialogProgressBarInc(progressBarIndex=%d, delta=%d)", progressBarIndex, delta); cellSysutil.warning("cellMsgDialogProgressBarInc(progressBarIndex=%d, delta=%d)", progressBarIndex, delta);
if (auto manager = g_fxo->get<rsx::overlays::display_manager>()) if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{ {
if (auto dlg = manager->get<rsx::overlays::message_dialog>()) if (auto dlg = manager->get<rsx::overlays::message_dialog>())
{ {

View file

@ -64,7 +64,7 @@ std::shared_ptr<OskDialogBase> _get_osk_dialog(bool create = false)
return nullptr; return nullptr;
} }
if (auto manager = g_fxo->get<rsx::overlays::display_manager>()) if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{ {
std::shared_ptr<rsx::overlays::osk_dialog> dlg = std::make_shared<rsx::overlays::osk_dialog>(); std::shared_ptr<rsx::overlays::osk_dialog> dlg = std::make_shared<rsx::overlays::osk_dialog>();
osk->dlg = manager->add(dlg); osk->dlg = manager->add(dlg);

View file

@ -646,6 +646,6 @@ public:
#include "util/fixed_typemap.hpp" #include "util/fixed_typemap.hpp"
extern stx::manual_fixed_typemap<void> g_fixed_typemap; extern stx::manual_typemap<void, 0x20'00000, 128> g_fixed_typemap;
constexpr stx::manual_fixed_typemap<void>* g_fxo = &g_fixed_typemap; constexpr auto* g_fxo = &g_fixed_typemap;

View file

@ -15,12 +15,12 @@ namespace input
pad::SetIntercepted(intercepted); pad::SetIntercepted(intercepted);
if (const auto handler = g_fxo->get<KeyboardHandlerBase>()) if (const auto handler = g_fxo->try_get<KeyboardHandlerBase>())
{ {
handler->SetIntercepted(intercepted); handler->SetIntercepted(intercepted);
} }
if (const auto handler = g_fxo->get<MouseHandlerBase>()) if (const auto handler = g_fxo->try_get<MouseHandlerBase>())
{ {
handler->SetIntercepted(intercepted); handler->SetIntercepted(intercepted);
} }

View file

@ -718,7 +718,7 @@ namespace vm
// Notify rsx that range has become valid // Notify rsx that range has become valid
// Note: This must be done *before* memory gets mapped while holding the vm lock, otherwise // 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 // the RSX might try to invalidate memory that got unmapped and remapped
if (const auto rsxthr = g_fxo->get<rsx::thread>()) if (const auto rsxthr = g_fxo->try_get<rsx::thread>())
{ {
rsxthr->on_notify_memory_mapped(addr, size); rsxthr->on_notify_memory_mapped(addr, size);
} }
@ -906,7 +906,7 @@ namespace vm
// Notify rsx to invalidate range // Notify rsx to invalidate range
// Note: This must be done *before* memory gets unmapped while holding the vm lock, otherwise // 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 // the RSX might try to call VirtualProtect on memory that is already unmapped
if (const auto rsxthr = g_fxo->get<rsx::thread>()) if (const auto rsxthr = g_fxo->get<rsx::thread>(); g_fxo->is_init<rsx::thread>())
{ {
rsxthr->on_notify_memory_unmapped(addr, size); rsxthr->on_notify_memory_unmapped(addr, size);
} }

View file

@ -268,7 +268,7 @@ namespace rsx
// Only update the screen at about 60fps since updating it everytime slows down the process // Only update the screen at about 60fps since updating it everytime slows down the process
std::this_thread::sleep_for(16ms); std::this_thread::sleep_for(16ms);
if (!g_fxo->get<display_manager>()) if (!g_fxo->is_init<display_manager>())
{ {
rsx_log.fatal("display_manager was improperly destroyed"); rsx_log.fatal("display_manager was improperly destroyed");
break; break;

View file

@ -974,7 +974,7 @@ namespace rsx
inline thread* get_current_renderer() inline thread* get_current_renderer()
{ {
return g_fxo->get<rsx::thread>(); return g_fxo->try_get<rsx::thread>();
} }
template<bool IsFullLock = false> template<bool IsFullLock = false>

View file

@ -55,7 +55,8 @@
LOG_CHANNEL(sys_log, "SYS"); LOG_CHANNEL(sys_log, "SYS");
stx::manual_fixed_typemap<void> g_fixed_typemap; // Preallocate 32 MiB
stx::manual_typemap<void, 0x20'00000, 128> g_fixed_typemap;
bool g_use_rtm = false; bool g_use_rtm = false;
u64 g_rtm_tx_limit1 = 0; u64 g_rtm_tx_limit1 = 0;
@ -138,7 +139,7 @@ void Emulator::Init(bool add_only)
idm::init(); idm::init();
g_fxo->reset(); g_fxo->reset();
g_fxo->init<named_thread<progress_dialog_server>>(); g_fxo->need<named_thread<progress_dialog_server>>();
// Reset defaults, cache them // Reset defaults, cache them
g_cfg.from_default(); 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); g_cfg.video.disable_on_disk_shader_cache.set(true);
vm::init(); vm::init();
g_fxo->init(); g_fxo->init(false);
// PS3 'executable' // PS3 'executable'
m_state = system_state::ready; 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; m_state = system_state::ready;
GetCallbacks().on_ready(); GetCallbacks().on_ready();
vm::init(); vm::init();
g_fxo->init(); g_fxo->init(false);
Run(false); Run(false);
m_force_boot = false; m_force_boot = false;
@ -1591,7 +1592,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
{ {
ConfigurePPUCache(); ConfigurePPUCache();
g_fxo->init(); g_fxo->init(false);
Emu.GetCallbacks().init_gs_render(); Emu.GetCallbacks().init_gs_render();
Emu.GetCallbacks().init_pad_handler(m_title_id); Emu.GetCallbacks().init_pad_handler(m_title_id);
Emu.GetCallbacks().init_kb_handler(); 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; m_state = system_state::ready;
GetCallbacks().on_ready(); GetCallbacks().on_ready();
vm::init(); vm::init();
g_fxo->init(); g_fxo->init(false);
ppu_load_prx(ppu_prx, m_path); ppu_load_prx(ppu_prx, m_path);
} }
else if (spu_exec.open(elf_file) == elf_error::ok) 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; m_state = system_state::ready;
GetCallbacks().on_ready(); GetCallbacks().on_ready();
vm::init(); vm::init();
g_fxo->init(); g_fxo->init(false);
spu_load_exec(spu_exec); spu_load_exec(spu_exec);
} }
else else
@ -1706,7 +1707,7 @@ void Emulator::Run(bool start_playtime)
cpu.state.notify_one(cpu_flag::stop); cpu.state.notify_one(cpu_flag::stop);
}); });
if (auto thr = g_fxo->get<named_thread<rsx::rsx_replay_thread>>()) if (auto thr = g_fxo->try_get<named_thread<rsx::rsx_replay_thread>>())
{ {
thr->state -= cpu_flag::stop; thr->state -= cpu_flag::stop;
thr->state.notify_one(cpu_flag::stop); thr->state.notify_one(cpu_flag::stop);
@ -1747,7 +1748,7 @@ bool Emulator::Pause()
idm::select<named_thread<ppu_thread>>(on_select); idm::select<named_thread<ppu_thread>>(on_select);
idm::select<named_thread<spu_thread>>(on_select); idm::select<named_thread<spu_thread>>(on_select);
if (auto rsx = g_fxo->get<rsx::thread>()) if (auto rsx = g_fxo->try_get<rsx::thread>())
{ {
rsx->state += cpu_flag::dbg_global_pause; rsx->state += cpu_flag::dbg_global_pause;
} }
@ -1820,7 +1821,7 @@ void Emulator::Resume()
idm::select<named_thread<ppu_thread>>(on_select); idm::select<named_thread<ppu_thread>>(on_select);
idm::select<named_thread<spu_thread>>(on_select); idm::select<named_thread<spu_thread>>(on_select);
if (auto rsx = g_fxo->get<rsx::thread>()) if (auto rsx = g_fxo->try_get<rsx::thread>())
{ {
// TODO: notify? // TODO: notify?
rsx->state -= cpu_flag::dbg_global_pause; rsx->state -= cpu_flag::dbg_global_pause;
@ -1876,7 +1877,7 @@ void Emulator::Stop(bool restart)
GetCallbacks().on_stop(); GetCallbacks().on_stop();
if (auto rsx = g_fxo->get<rsx::thread>()) if (auto rsx = g_fxo->try_get<rsx::thread>())
{ {
// TODO: notify? // TODO: notify?
rsx->state += cpu_flag::exit; rsx->state += cpu_flag::exit;
@ -1962,7 +1963,7 @@ bool Emulator::Quit(bool force_quit)
const auto on_exit = []() const auto on_exit = []()
{ {
// Deinitialize object manager to prevent any hanging objects at program 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); return GetCallbacks().try_to_quit(force_quit, on_exit);
} }

View file

@ -111,9 +111,6 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<RuntimeTypeInfo>true</RuntimeTypeInfo> <RuntimeTypeInfo>true</RuntimeTypeInfo>
</ClCompile> </ClCompile>
<ClCompile Include="util\fixed_typemap.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\Utilities\bin_patch.cpp"> <ClCompile Include="..\Utilities\bin_patch.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile> </ClCompile>

View file

@ -881,9 +881,6 @@
<ClCompile Include="util\cereal.cpp"> <ClCompile Include="util\cereal.cpp">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="util\fixed_typemap.cpp">
<Filter>Utilities</Filter>
</ClCompile>
<ClCompile Include="util\cpu_stats.cpp"> <ClCompile Include="util\cpu_stats.cpp">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClCompile> </ClCompile>

View file

@ -447,7 +447,8 @@ bool cheat_engine::is_addr_safe(const u32 offset)
if (Emu.IsStopped()) if (Emu.IsStopped())
return false; return false;
const auto ppum = g_fxo->get<ppu_module>(); const auto ppum = g_fxo->try_get<ppu_module>();
if (!ppum) if (!ppum)
{ {
log_cheat.fatal("Failed to get ppu_module"); log_cheat.fatal("Failed to get ppu_module");

View file

@ -431,7 +431,7 @@ cpu_thread* debugger_frame::get_cpu()
return m_rsx; return m_rsx;
} }
if (g_fxo->get<rsx::thread>() != m_rsx) if (!g_fxo->is_init<rsx::thread>())
{ {
m_rsx = nullptr; m_rsx = nullptr;
return m_rsx; return m_rsx;

View file

@ -971,7 +971,7 @@ void main_window::DecryptSPRXLibraries()
// Always start with no KLIC // Always start with no KLIC
std::vector<u128> klics{u128{}}; std::vector<u128> klics{u128{}};
if (const auto keys = g_fxo->get<loaded_npdrm_keys>()) if (const auto keys = g_fxo->try_get<loaded_npdrm_keys>())
{ {
// Second klic: get it from a running game // Second klic: get it from a running game
if (const u128 klic = keys->devKlic) if (const u128 klic = keys->devKlic)

View file

@ -373,8 +373,8 @@ void Buffer::showImage(const QImage& image)
void Buffer::ShowWindowed() void Buffer::ShowWindowed()
{ {
const auto render = rsx::get_current_renderer(); //const auto render = rsx::get_current_renderer();
if (!render) if (!g_fxo->is_init<rsx::thread>())
return; return;
// TODO: Is there any better way to choose the color buffers // TODO: Is there any better way to choose the color buffers

View file

@ -11,7 +11,7 @@
s32 save_data_dialog::ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet) s32 save_data_dialog::ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet)
{ {
// TODO: Install native shell as an Emu callback // TODO: Install native shell as an Emu callback
if (auto manager = g_fxo->get<rsx::overlays::display_manager>()) if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{ {
auto result = manager->create<rsx::overlays::save_dialog>()->show(save_entries, focused, op, listSet); auto result = manager->create<rsx::overlays::save_dialog>()->show(save_entries, focused, op, listSet);
if (result != rsx::overlays::user_interface::selection_code::error) if (result != rsx::overlays::user_interface::selection_code::error)

View file

@ -7,7 +7,7 @@
s32 trophy_notification_helper::ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophy_icon_buffer) s32 trophy_notification_helper::ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophy_icon_buffer)
{ {
if (auto manager = g_fxo->get<rsx::overlays::display_manager>()) if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
{ {
// Allow adding more than one trophy notification. The notification class manages scheduling // Allow adding more than one trophy notification. The notification class manages scheduling
auto popup = std::make_shared<rsx::overlays::trophy_notification>(); auto popup = std::make_shared<rsx::overlays::trophy_notification>();

View file

@ -1,15 +0,0 @@
#include "fixed_typemap.hpp"
#include <algorithm>
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;
});
}
}

View file

@ -1,54 +1,49 @@
#pragma once #pragma once
#include <memory> // Backported from auto_typemap.hpp as a more simple alternative
#include "util/types.hpp"
#include "util/typeindices.hpp"
#include <utility> #include <utility>
#include <type_traits> #include <type_traits>
#include <util/typeindices.hpp>
namespace stx namespace stx
{ {
namespace detail // Simplified typemap with exactly one object of each used type, non-moveable. Initialized on init(). Destroyed on clear().
{ template <typename Tag /*Tag should be unique*/, u32 Size = 0, u32 Align = (Size ? 64 : __STDCPP_DEFAULT_NEW_ALIGNMENT__)>
// Destroy list element class alignas(Align) manual_typemap
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 <typename Tag>
class manual_fixed_typemap
{ {
// Save default constructor and destructor // Save default constructor and destructor
struct typeinfo struct typeinfo
{ {
void(*create)(void*& ptr) noexcept; bool(*create)(uchar* ptr, manual_typemap&) noexcept;
void(*destroy)(void*& ptr) noexcept; void(*destroy)(void* ptr) noexcept;
template <typename T> template <typename T>
static void call_ctor(void*& ptr) noexcept static bool call_ctor(uchar* ptr, manual_typemap& _this) noexcept
{ {
// Don't overwrite if already exists // Allow passing reference to "this"
if (!ptr) if constexpr (std::is_constructible_v<T, manual_typemap&>)
{ {
new (ptr) T(_this);
return true;
}
// Call default constructor only if available // Call default constructor only if available
if constexpr (std::is_default_constructible_v<T>) if constexpr (std::is_default_constructible_v<T>)
{ {
ptr = new T(); new (ptr) T();
} return true;
} }
return false;
} }
template <typename T> template <typename T>
static void call_dtor(void*& ptr) noexcept static void call_dtor(void* ptr) noexcept
{ {
delete static_cast<T*>(ptr); std::launder(static_cast<T*>(ptr))->~T();
ptr = nullptr;
} }
template <typename T> template <typename T>
@ -61,111 +56,140 @@ namespace stx
} }
}; };
// Raw pointers to existing objects (may be nullptr) // Objects
std::unique_ptr<void*[]> m_list; union
{
uchar* m_list = nullptr;
mutable uchar m_data[Size ? Size : 1];
};
// Creation order for each object (used to reverse destruction order) // Creation order for each object (used to reverse destruction order)
std::unique_ptr<unsigned long long[]> m_order; void** m_order = nullptr;
// Used to generate creation order (increased on every construction) // Helper for destroying in reverse order
unsigned long long m_init_count = 0; const typeinfo** m_info = nullptr;
// Indicates whether object is created at given index
bool* m_init = nullptr;
public: 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 manual_typemap& operator=(const manual_typemap&) = delete;
: m_list(std::move(r.m_list))
, m_order(std::move(r.m_order)) ~manual_typemap()
, m_init_count(r.m_init_count)
{ {
r.m_init_count = 0; ensure(!m_init);
} }
manual_fixed_typemap& operator=(const manual_fixed_typemap&) = delete; void reset()
manual_fixed_typemap& operator=(manual_fixed_typemap&& r) noexcept
{ {
manual_fixed_typemap x(std::move(r)); if (m_init)
std::swap(m_list, x.m_list); {
std::swap(m_order, x.m_order); clear();
std::swap(m_init_count, x.m_init_count);
return *this;
} }
~manual_fixed_typemap() m_order = new void*[stx::typelist<typeinfo>().count()];
m_info = new const typeinfo*[stx::typelist<typeinfo>().count()];
m_init = new bool[stx::typelist<typeinfo>().count()]{};
if constexpr (Size == 0)
{ {
if (!m_list && !m_order) if (stx::typelist<typeinfo>().align() > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{ {
return; m_list = static_cast<uchar*>(::operator new(usz{stx::typelist<typeinfo>().size()}, std::align_val_t{stx::typelist<typeinfo>().align()}));
}
else
{
m_list = new uchar[stx::typelist<typeinfo>().size()];
}
}
else
{
ensure(Size >= stx::typelist<typeinfo>().size());
ensure(Align >= stx::typelist<typeinfo>().align());
m_data[0] = 0;
}
} }
reset(); void init(bool reset = true)
{
if (reset)
{
this->reset();
} }
// Destroy all objects and keep them in uninitialized state, must be called first for (const auto& type : stx::typelist<typeinfo>())
void reset() noexcept
{ {
const auto total_count = stx::typelist<typeinfo>().count(); const u32 id = type.index();
uchar* data = (Size ? +m_data : m_list) + type.pos();
if (!m_list) // Allocate initialization order id
if (m_init[id])
{ {
m_list = std::make_unique<void*[]>(total_count);
m_order = std::make_unique<unsigned long long[]>(total_count);
return;
}
using detail::destroy_info;
auto all_data = std::make_unique<destroy_info[]>(stx::typelist<typeinfo>().count());
// Actual number of created objects
unsigned _max = 0;
// Create destroy list
for (auto& type : stx::typelist<typeinfo>())
{
if (m_order[type.index()] == 0)
{
// Skip object if not created
continue; continue;
} }
all_data[_max].object_pointer = &m_list[type.index()]; if (type.create(data, *this))
all_data[_max].created = m_order[type.index()]; {
all_data[_max].destroy = type.destroy; *m_order++ = data;
*m_info++ = &type;
m_init[id] = true;
}
}
}
// Clear creation order void clear()
m_order[type.index()] = 0; {
if (!m_init)
{
return;
}
// Get actual number of created objects
u32 _max = 0;
for (const auto& type : stx::typelist<typeinfo>())
{
if (m_init[type.index()])
{
// Skip object if not created
_max++; _max++;
} }
// 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 // Destroy objects in reverse order
m_init_count = 0; for (; _max; _max--)
{
(*--m_info)->destroy(*--m_order);
} }
// Default initialize all objects if possible and not already initialized // Pointers should be restored to their positions
void init() noexcept delete[] m_init;
{ delete[] m_info;
for (auto& type : stx::typelist<typeinfo>()) delete[] m_order;
{
type.create(m_list[type.index()]);
// Allocate initialization order id if constexpr (Size == 0)
if (m_list[type.index()])
{ {
m_order[type.index()] = ++m_init_count; if (stx::typelist<typeinfo>().align() > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
{
::operator delete[](m_list, std::align_val_t{stx::typelist<typeinfo>().align()});
} }
else
{
delete[] m_list;
}
}
m_init = nullptr;
m_info = nullptr;
m_order = nullptr;
if constexpr (Size == 0)
{
m_list = nullptr;
} }
} }
@ -173,26 +197,45 @@ namespace stx
template <typename T> template <typename T>
void need() noexcept void need() noexcept
{ {
if (!get<T>()) if (!m_init[stx::typeindex<typeinfo, std::decay_t<T>>()])
{
if constexpr (std::is_constructible_v<T, manual_typemap&>)
{
init<T>(*this);
return;
}
if constexpr (std::is_default_constructible_v<T>)
{ {
init<T>(); init<T>();
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 <typename T, typename As = T, typename... Args> template <typename T, typename As = T, typename... Args>
As* init(Args&&... args) noexcept As* init(Args&&... args) noexcept
{ {
auto& ptr = m_list[stx::typeindex<typeinfo, std::decay_t<T>>()]; if (std::exchange(m_init[stx::typeindex<typeinfo, std::decay_t<T>, std::decay_t<As>>()], true))
if (ptr)
{ {
delete static_cast<T*>(ptr); // Already exists, recreation is not supported (may be added later)
return nullptr;
} }
As* obj = new std::decay_t<As>(std::forward<Args>(args)...); As* obj = nullptr;
m_order[stx::typeindex<typeinfo, std::decay_t<T>>()] = ++m_init_count;
ptr = static_cast<T*>(obj); if constexpr (Size != 0)
{
obj = new (m_data + stx::typeoffset<typeinfo, std::decay_t<T>>()) std::decay_t<As>(std::forward<Args>(args)...);
}
else
{
obj = new (m_list + stx::typeoffset<typeinfo, std::decay_t<T>>()) std::decay_t<As>(std::forward<Args>(args)...);
}
*m_order++ = obj;
*m_info++ = &stx::typedata<typeinfo, std::decay_t<T>, std::decay_t<As>>();
return obj; return obj;
} }
@ -205,11 +248,36 @@ namespace stx
return init<T>(std::forward<Args>(args)...); return init<T>(std::forward<Args>(args)...);
} }
// Obtain object pointer (thread safe just against other get calls) template <typename T>
bool is_init() const noexcept
{
return m_init[stx::typeindex<typeinfo, std::decay_t<T>>()];
}
// Obtain object pointer (may be uninitialized memory)
template <typename T> template <typename T>
T* get() const noexcept T* get() const noexcept
{ {
return static_cast<T*>(m_list[stx::typeindex<typeinfo, std::decay_t<T>>()]); if constexpr (Size != 0)
{
return std::launder(reinterpret_cast<T*>(m_data + stx::typeoffset<typeinfo, std::decay_t<T>>()));
}
else
{
return std::launder(reinterpret_cast<T*>(m_list + stx::typeoffset<typeinfo, std::decay_t<T>>()));
}
}
// Obtain object pointer if initialized
template <typename T>
T* try_get() const noexcept
{
if (is_init<T>())
{
[[likely]] return get<T>();
}
[[unlikely]] return nullptr;
} }
}; };
} }