mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
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:
parent
8a9320c4ef
commit
d788b12a8e
@ -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
|
||||
|
@ -429,7 +429,7 @@ void cpu_thread::operator()()
|
||||
}
|
||||
}
|
||||
|
||||
while (!g_fxo->get<cpu_profiler>())
|
||||
while (!g_fxo->is_init<cpu_profiler>())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
@ -1151,7 +1151,7 @@ void cpu_thread::stop_all() 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.");
|
||||
return;
|
||||
|
@ -107,7 +107,7 @@ struct msg_dlg_thread_info
|
||||
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>())
|
||||
{
|
||||
@ -149,7 +149,7 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
|
||||
|
||||
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>())
|
||||
{
|
||||
@ -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);
|
||||
|
||||
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>())
|
||||
{
|
||||
@ -463,7 +463,7 @@ error_code 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>())
|
||||
{
|
||||
@ -514,7 +514,7 @@ error_code cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::cptr<char> m
|
||||
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>())
|
||||
{
|
||||
@ -546,7 +546,7 @@ error_code cellMsgDialogProgressBarReset(u32 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>())
|
||||
{
|
||||
@ -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<rsx::overlays::display_manager>())
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
if (auto dlg = manager->get<rsx::overlays::message_dialog>())
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ std::shared_ptr<OskDialogBase> _get_osk_dialog(bool create = false)
|
||||
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>();
|
||||
osk->dlg = manager->add(dlg);
|
||||
|
@ -646,6 +646,6 @@ public:
|
||||
|
||||
#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;
|
||||
|
@ -15,12 +15,12 @@ namespace input
|
||||
|
||||
pad::SetIntercepted(intercepted);
|
||||
|
||||
if (const auto handler = g_fxo->get<KeyboardHandlerBase>())
|
||||
if (const auto handler = g_fxo->try_get<KeyboardHandlerBase>())
|
||||
{
|
||||
handler->SetIntercepted(intercepted);
|
||||
}
|
||||
|
||||
if (const auto handler = g_fxo->get<MouseHandlerBase>())
|
||||
if (const auto handler = g_fxo->try_get<MouseHandlerBase>())
|
||||
{
|
||||
handler->SetIntercepted(intercepted);
|
||||
}
|
||||
|
@ -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<rsx::thread>())
|
||||
if (const auto rsxthr = g_fxo->try_get<rsx::thread>())
|
||||
{
|
||||
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<rsx::thread>())
|
||||
if (const auto rsxthr = g_fxo->get<rsx::thread>(); g_fxo->is_init<rsx::thread>())
|
||||
{
|
||||
rsxthr->on_notify_memory_unmapped(addr, size);
|
||||
}
|
||||
|
@ -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<display_manager>())
|
||||
if (!g_fxo->is_init<display_manager>())
|
||||
{
|
||||
rsx_log.fatal("display_manager was improperly destroyed");
|
||||
break;
|
||||
|
@ -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<cpu_flag> old) override;
|
||||
|
||||
@ -974,7 +974,7 @@ namespace rsx
|
||||
|
||||
inline thread* get_current_renderer()
|
||||
{
|
||||
return g_fxo->get<rsx::thread>();
|
||||
return g_fxo->try_get<rsx::thread>();
|
||||
}
|
||||
|
||||
template<bool IsFullLock = false>
|
||||
|
@ -55,7 +55,8 @@
|
||||
|
||||
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;
|
||||
u64 g_rtm_tx_limit1 = 0;
|
||||
@ -138,7 +139,7 @@ void Emulator::Init(bool add_only)
|
||||
|
||||
idm::init();
|
||||
g_fxo->reset();
|
||||
g_fxo->init<named_thread<progress_dialog_server>>();
|
||||
g_fxo->need<named_thread<progress_dialog_server>>();
|
||||
|
||||
// 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<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.notify_one(cpu_flag::stop);
|
||||
@ -1747,7 +1748,7 @@ bool Emulator::Pause()
|
||||
idm::select<named_thread<ppu_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;
|
||||
}
|
||||
@ -1820,7 +1821,7 @@ void Emulator::Resume()
|
||||
idm::select<named_thread<ppu_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?
|
||||
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<rsx::thread>())
|
||||
if (auto rsx = g_fxo->try_get<rsx::thread>())
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
@ -111,9 +111,6 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\fixed_typemap.cpp">
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Utilities\bin_patch.cpp">
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
@ -881,9 +881,6 @@
|
||||
<ClCompile Include="util\cereal.cpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\fixed_typemap.cpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util\cpu_stats.cpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClCompile>
|
||||
|
@ -447,7 +447,8 @@ bool cheat_engine::is_addr_safe(const u32 offset)
|
||||
if (Emu.IsStopped())
|
||||
return false;
|
||||
|
||||
const auto ppum = g_fxo->get<ppu_module>();
|
||||
const auto ppum = g_fxo->try_get<ppu_module>();
|
||||
|
||||
if (!ppum)
|
||||
{
|
||||
log_cheat.fatal("Failed to get ppu_module");
|
||||
|
@ -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<rsx::thread>() != m_rsx)
|
||||
if (!g_fxo->is_init<rsx::thread>())
|
||||
{
|
||||
m_rsx = nullptr;
|
||||
return m_rsx;
|
||||
|
@ -971,7 +971,7 @@ void main_window::DecryptSPRXLibraries()
|
||||
// Always start with no KLIC
|
||||
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
|
||||
if (const u128 klic = keys->devKlic)
|
||||
|
@ -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<rsx::thread>())
|
||||
return;
|
||||
|
||||
// TODO: Is there any better way to choose the color buffers
|
||||
|
@ -11,7 +11,7 @@
|
||||
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
|
||||
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);
|
||||
if (result != rsx::overlays::user_interface::selection_code::error)
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
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
|
||||
auto popup = std::make_shared<rsx::overlays::trophy_notification>();
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
@ -1,54 +1,49 @@
|
||||
#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 <type_traits>
|
||||
#include <util/typeindices.hpp>
|
||||
|
||||
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 <typename Tag>
|
||||
class manual_fixed_typemap
|
||||
// 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__)>
|
||||
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 <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
|
||||
if (!ptr)
|
||||
// Allow passing reference to "this"
|
||||
if constexpr (std::is_constructible_v<T, manual_typemap&>)
|
||||
{
|
||||
// Call default constructor only if available
|
||||
if constexpr (std::is_default_constructible_v<T>)
|
||||
{
|
||||
ptr = new T();
|
||||
}
|
||||
new (ptr) T(_this);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Call default constructor only if available
|
||||
if constexpr (std::is_default_constructible_v<T>)
|
||||
{
|
||||
new (ptr) T();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void call_dtor(void*& ptr) noexcept
|
||||
static void call_dtor(void* ptr) noexcept
|
||||
{
|
||||
delete static_cast<T*>(ptr);
|
||||
ptr = nullptr;
|
||||
std::launder(static_cast<T*>(ptr))->~T();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -61,138 +56,186 @@ namespace stx
|
||||
}
|
||||
};
|
||||
|
||||
// Raw pointers to existing objects (may be nullptr)
|
||||
std::unique_ptr<void*[]> 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<unsigned long long[]> 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<typeinfo>().count()];
|
||||
m_info = new const typeinfo*[stx::typelist<typeinfo>().count()];
|
||||
m_init = new bool[stx::typelist<typeinfo>().count()]{};
|
||||
|
||||
// Destroy all objects and keep them in uninitialized state, must be called first
|
||||
void reset() noexcept
|
||||
{
|
||||
const auto total_count = stx::typelist<typeinfo>().count();
|
||||
|
||||
if (!m_list)
|
||||
if constexpr (Size == 0)
|
||||
{
|
||||
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)
|
||||
if (stx::typelist<typeinfo>().align() > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void init(bool reset = true)
|
||||
{
|
||||
if (reset)
|
||||
{
|
||||
this->reset();
|
||||
}
|
||||
|
||||
for (const auto& type : stx::typelist<typeinfo>())
|
||||
{
|
||||
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<typeinfo>())
|
||||
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<typeinfo>())
|
||||
{
|
||||
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<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;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if object is not initialized but shall be initialized first (to use in initializing other objects)
|
||||
template <typename T>
|
||||
void need() noexcept
|
||||
{
|
||||
if (!get<T>())
|
||||
if (!m_init[stx::typeindex<typeinfo, std::decay_t<T>>()])
|
||||
{
|
||||
init<T>();
|
||||
if constexpr (std::is_constructible_v<T, manual_typemap&>)
|
||||
{
|
||||
init<T>(*this);
|
||||
return;
|
||||
}
|
||||
|
||||
if constexpr (std::is_default_constructible_v<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>
|
||||
As* init(Args&&... args) noexcept
|
||||
{
|
||||
auto& ptr = m_list[stx::typeindex<typeinfo, std::decay_t<T>>()];
|
||||
|
||||
if (ptr)
|
||||
if (std::exchange(m_init[stx::typeindex<typeinfo, std::decay_t<T>, std::decay_t<As>>()], true))
|
||||
{
|
||||
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)...);
|
||||
m_order[stx::typeindex<typeinfo, std::decay_t<T>>()] = ++m_init_count;
|
||||
ptr = static_cast<T*>(obj);
|
||||
As* obj = nullptr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -205,11 +248,36 @@ namespace stx
|
||||
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>
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user