This commit is contained in:
digant 2025-01-06 14:41:21 +01:00
parent 9d8f3b7bc4
commit dc2e45bc89
30 changed files with 177 additions and 79 deletions

View file

@ -22,6 +22,5 @@ else()
add_subdirectory(wolfssl EXCLUDE_FROM_ALL)
target_compile_definitions(wolfssl PUBLIC WOLFSSL_DES_ECB HAVE_WRITE_DUP)
target_compile_definitions(wolfssl PUBLIC FP_MAX_BITS=8192)
target_compile_definitions(wolfssl PUBLIC WOLFSSL_DES_ECB HAVE_WRITE_DUP FP_MAX_BITS=8192 WOLFSSL_NO_OPTIONS_H)
endif()

View file

@ -33,7 +33,8 @@ enum class thread_state : u32
aborting = 1, // The thread has been joined in the destructor or explicitly aborted
errored = 2, // Set after the emergency_exit call
finished = 3, // Final state, always set at the end of thread execution
mask = 3
mask = 3,
destroying_context = 7, // Special value assigned to destroy data explicitly before the destructor
};
template <class Context>
@ -702,14 +703,17 @@ public:
thread::m_sync.notify_all();
}
if (s == thread_state::finished)
if (s == thread_state::finished || s == thread_state::destroying_context)
{
// This participates in emulation stopping, use destruction-alike semantics
thread::join(true);
}
if (s == thread_state::destroying_context)
{
if constexpr (std::is_assignable_v<Context&, thread_state>)
{
static_cast<Context&>(*this) = thread_state::finished;
static_cast<Context&>(*this) = thread_state::destroying_context;
}
}

View file

@ -14,6 +14,7 @@ enum class cheat_type : u8
signed_16_cheat,
signed_32_cheat,
signed_64_cheat,
float_32_cheat,
max
};

View file

@ -164,7 +164,7 @@ elseif(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git
COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt
--no-translations --no-quick --no-system-d3d-compiler --no-quick-import
--no-translations --no-system-d3d-compiler --no-quick-import
--plugindir "$<IF:$<CXX_COMPILER_ID:MSVC>,$<TARGET_FILE_DIR:rpcs3>/plugins,$<TARGET_FILE_DIR:rpcs3>/share/qt6/plugins>"
--verbose 0 "$<TARGET_FILE:rpcs3>")
endif()

View file

@ -71,7 +71,7 @@ CellError lv2_cond::on_id_create()
std::function<void(void*)> lv2_cond::load(utils::serial& ar)
{
return load_func(make_shared<lv2_cond>(ar));
return load_func(make_shared<lv2_cond>(stx::exact_t<utils::serial&>(ar)));
}
void lv2_cond::save(utils::serial& ar)

View file

@ -122,7 +122,7 @@ void lv2_config::remove_service_event(u32 id)
lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) noexcept
{
if (s == thread_state::finished)
if (s == thread_state::destroying_context && !m_destroyed.exchange(true))
{
if (auto global = g_fxo->try_get<lv2_config>())
{
@ -133,6 +133,23 @@ lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) no
return *this;
}
lv2_config_service_event::~lv2_config_service_event() noexcept
{
operator=(thread_state::destroying_context);
}
lv2_config::~lv2_config() noexcept
{
for (auto& [key, event] : events)
{
if (event)
{
// Avoid collision with lv2_config_service_event destructor
event->m_destroyed = true;
}
}
}
// LV2 Config Service Listener
bool lv2_config_service_listener::check_service(const lv2_config_service& service) const
{

View file

@ -161,6 +161,8 @@ public:
return null_ptr;
}
~lv2_config() noexcept;
};
/*
@ -276,7 +278,7 @@ public:
// Utilities
usz get_size() const { return sizeof(sys_config_service_event_t)-1 + data.size(); }
shared_ptr<lv2_config_service> get_shared_ptr () const { return idm::get_unlocked<lv2_config_service>(idm_id); }
shared_ptr<lv2_config_service> get_shared_ptr () const { return stx::make_shared_from_this<lv2_config_service>(this); }
u32 get_id() const { return idm_id; }
};
@ -342,7 +344,7 @@ public:
// Utilities
u32 get_id() const { return idm_id; }
shared_ptr<lv2_config_service_listener> get_shared_ptr() const { return idm::get_unlocked<lv2_config_service_listener>(idm_id); }
shared_ptr<lv2_config_service_listener> get_shared_ptr() const { return stx::make_shared_from_this<lv2_config_service_listener>(this); }
};
/*
@ -360,6 +362,10 @@ class lv2_config_service_event
return g_fxo->get<service_event_id>().next_id++;
}
atomic_t<bool> m_destroyed = false;
friend class lv2_config;
public:
const u32 id;
@ -391,8 +397,7 @@ public:
// Destructor
lv2_config_service_event& operator=(thread_state s) noexcept;
~lv2_config_service_event() noexcept = default;
~lv2_config_service_event() noexcept;
// Notify queue that this event exists
bool notify() const;

View file

@ -37,8 +37,8 @@ lv2_event_queue::lv2_event_queue(utils::serial& ar) noexcept
std::function<void(void*)> lv2_event_queue::load(utils::serial& ar)
{
auto queue = make_shared<lv2_event_queue>(ar);
return [ptr = lv2_obj::load(queue->key, queue)](void* storage) { *static_cast<shared_ptr<lv2_obj>*>(storage) = ptr; };
auto queue = make_shared<lv2_event_queue>(stx::exact_t<utils::serial&>(ar));
return [ptr = lv2_obj::load(queue->key, queue)](void* storage) { *static_cast<atomic_ptr<lv2_obj>*>(storage) = ptr; };
}
void lv2_event_queue::save(utils::serial& ar)

View file

@ -24,7 +24,7 @@ lv2_event_flag::lv2_event_flag(utils::serial& ar)
std::function<void(void*)> lv2_event_flag::load(utils::serial& ar)
{
return load_func(make_shared<lv2_event_flag>(ar));
return load_func(make_shared<lv2_event_flag>(stx::exact_t<utils::serial&>(ar)));
}
void lv2_event_flag::save(utils::serial& ar)

View file

@ -33,7 +33,7 @@ std::function<void(void*)> lv2_memory_container::load(utils::serial& ar)
// Use idm::last_id() only for the instances at IDM
return [ptr = make_shared<lv2_memory_container>(stx::exact_t<utils::serial&>(ar), true)](void* storage)
{
*static_cast<shared_ptr<lv2_memory_container>*>(storage) = ptr;
*static_cast<atomic_ptr<lv2_memory_container>*>(storage) = ptr;
};
}

View file

@ -84,7 +84,7 @@ CellError lv2_memory::on_id_create()
std::function<void(void*)> lv2_memory::load(utils::serial& ar)
{
auto mem = make_shared<lv2_memory>(ar);
auto mem = make_shared<lv2_memory>(stx::exact_t<utils::serial&>(ar));
mem->exists++; // Disable on_id_create()
auto func = load_func(mem, +mem->pshared);
mem->exists--;

View file

@ -27,7 +27,7 @@ lv2_mutex::lv2_mutex(utils::serial& ar)
std::function<void(void*)> lv2_mutex::load(utils::serial& ar)
{
return load_func(make_shared<lv2_mutex>(ar));
return load_func(make_shared<lv2_mutex>(stx::exact_t<utils::serial&>(ar)));
}
void lv2_mutex::save(utils::serial& ar)

View file

@ -293,7 +293,7 @@ std::function<void(void*)> lv2_socket::load(utils::serial& ar)
sock_lv2->bind(sock_lv2->last_bound_addr);
}
return [ptr = sock_lv2](void* storage) { *static_cast<shared_ptr<lv2_socket>*>(storage) = ptr; };;
return [ptr = sock_lv2](void* storage) { *static_cast<atomic_ptr<lv2_socket>*>(storage) = ptr; };;
}
void lv2_socket::save(utils::serial& ar, bool save_only_this_class)

View file

@ -178,7 +178,7 @@ void lv2_socket::queue_wake(ppu_thread* ppu)
lv2_socket& lv2_socket::operator=(thread_state s) noexcept
{
if (s == thread_state::finished)
if (s == thread_state::destroying_context)
{
close();
}

View file

@ -112,7 +112,7 @@ std::function<void(void*)> lv2_overlay::load(utils::serial& ar)
return [ovlm](void* storage)
{
*static_cast<shared_ptr<lv2_obj>*>(storage) = ovlm;
*static_cast<atomic_ptr<lv2_obj>*>(storage) = ovlm;
};
}

View file

@ -372,7 +372,7 @@ std::function<void(void*)> lv2_prx::load(utils::serial& ar)
return [prx](void* storage)
{
*static_cast<shared_ptr<lv2_obj>*>(storage) = prx;
*static_cast<atomic_ptr<lv2_obj>*>(storage) = prx;
};
}

View file

@ -449,7 +449,7 @@ public:
static std::function<void(void*)> load_func(shared_ptr<T> make, u64 pshared = umax)
{
const u64 key = make->key;
return [ptr = load<T>(key, make, pshared)](void* storage) { *static_cast<shared_ptr<Storage>*>(storage) = ptr; };
return [ptr = load<T>(key, make, pshared)](void* storage) { *static_cast<atomic_ptr<Storage>*>(storage) = ptr; };
}
static bool wait_timeout(u64 usec, ppu_thread* cpu = {}, bool scale = true, bool is_usleep = false);

View file

@ -123,7 +123,7 @@ namespace id_manager
ptr = stx::make_shared<T>(stx::exact_t<utils::serial&>(ar));
}
return [ptr](void* storage) { *static_cast<stx::shared_ptr<T>*>(storage) = ptr; };
return [ptr](void* storage) { *static_cast<stx::atomic_ptr<T>*>(storage) = ptr; };
};
};
@ -805,8 +805,8 @@ public:
{
if (ptr)
{
constexpr thread_state finished{3};
*static_cast<Get*>(ptr.get()) = finished;
constexpr thread_state destroying_context{7};
*static_cast<Get*>(ptr.get()) = destroying_context;
}
}
@ -837,8 +837,8 @@ public:
{
if (ptr)
{
constexpr thread_state finished{3};
*static_cast<Get*>(ptr.get()) = finished;
constexpr thread_state destroying_context{7};
*static_cast<Get*>(ptr.get()) = destroying_context;
}
}

View file

@ -78,6 +78,7 @@ namespace vk
break;
case vk::driver_vendor::LAVAPIPE:
case vk::driver_vendor::V3DV:
case vk::driver_vendor::PANVK:
// TODO: Actually bench this. Using 32 for now to match other common configurations.
case vk::driver_vendor::DOZEN:
// Actual optimal size depends on the D3D device. Use 32 since it should work well on both AMD and NVIDIA

View file

@ -144,6 +144,9 @@ namespace vk
case driver_vendor::HONEYKRISP:
// Needs more testing
break;
case driver_vendor::PANVK:
// Needs more testing
break;
default:
rsx_log.warning("Unsupported device: %s", gpu_name);
}

View file

@ -190,6 +190,7 @@ namespace vk
case driver_vendor::LAVAPIPE:
case driver_vendor::V3DV:
case driver_vendor::HONEYKRISP:
case driver_vendor::PANVK:
break;
}

View file

@ -54,7 +54,8 @@ namespace vk
LAVAPIPE,
NVK,
V3DV,
HONEYKRISP
HONEYKRISP,
PANVK
};
driver_vendor get_driver_vendor();

View file

@ -302,6 +302,11 @@ namespace vk
return driver_vendor::HONEYKRISP;
}
if (gpu_name.find("Panfrost") != umax)
{
return driver_vendor::PANVK;
}
return driver_vendor::unknown;
}
else
@ -329,6 +334,8 @@ namespace vk
return driver_vendor::V3DV;
case VK_DRIVER_ID_MESA_HONEYKRISP:
return driver_vendor::HONEYKRISP;
case VK_DRIVER_ID_MESA_PANVK:
return driver_vendor::PANVK;
default:
// Mobile?
return driver_vendor::unknown;
@ -659,6 +666,12 @@ namespace vk
enabled_features.textureCompressionBC = VK_FALSE;
}
if (!pgpu->features.textureCompressionBC && pgpu->get_driver_vendor() == driver_vendor::PANVK)
{
rsx_log.error("Your GPU running on the PANVK driver does not support full texture block compression. Graphics may not render correctly.");
enabled_features.textureCompressionBC = VK_FALSE;
}
VkDeviceCreateInfo device = {};
device.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device.pNext = nullptr;

View file

@ -41,6 +41,7 @@ void progress_dialog_server::operator()()
{
std::shared_ptr<rsx::overlays::progress_dialog> native_dlg;
g_system_progress_stopping = false;
g_system_progress_canceled = false;
const auto get_state = []()
{

View file

@ -43,6 +43,7 @@ void fmt_class_string<cheat_type>::format(std::string& out, u64 arg)
case cheat_type::signed_16_cheat: return "Signed 16 bits";
case cheat_type::signed_32_cheat: return "Signed 32 bits";
case cheat_type::signed_64_cheat: return "Signed 64 bits";
case cheat_type::float_32_cheat: return "Float 32 bits";
case cheat_type::max: break;
}
@ -612,8 +613,9 @@ cheat_manager_dialog::cheat_manager_dialog(QWidget* parent)
return;
}
bool success;
u64 result_value;
bool success = false;
u64 result_value {};
f64 result_value_f {};
switch (cheat->type)
{
@ -625,6 +627,7 @@ cheat_manager_dialog::cheat_manager_dialog(QWidget* parent)
case cheat_type::signed_16_cheat: result_value = cheat_engine::get_value<s16>(final_offset, success); break;
case cheat_type::signed_32_cheat: result_value = cheat_engine::get_value<s32>(final_offset, success); break;
case cheat_type::signed_64_cheat: result_value = cheat_engine::get_value<s64>(final_offset, success); break;
case cheat_type::float_32_cheat: result_value_f = cheat_engine::get_value<f32>(final_offset, success); break;
default: log_cheat.fatal("Unsupported cheat type"); return;
}
@ -632,6 +635,8 @@ cheat_manager_dialog::cheat_manager_dialog(QWidget* parent)
{
if (cheat->type >= cheat_type::signed_8_cheat && cheat->type <= cheat_type::signed_64_cheat)
edt_value_final->setText(tr("%1").arg(static_cast<s64>(result_value)));
else if (cheat->type == cheat_type::float_32_cheat)
edt_value_final->setText(tr("%1").arg(result_value_f));
else
edt_value_final->setText(tr("%1").arg(result_value));
}
@ -795,6 +800,7 @@ cheat_manager_dialog::cheat_manager_dialog(QWidget* parent)
case cheat_type::signed_16_cheat: results = convert_and_set<s16>(final_offset); break;
case cheat_type::signed_32_cheat: results = convert_and_set<s32>(final_offset); break;
case cheat_type::signed_64_cheat: results = convert_and_set<s64>(final_offset); break;
case cheat_type::float_32_cheat: results = convert_and_set<f32>(final_offset); break;
default: log_cheat.fatal("Unsupported cheat type"); return;
}
@ -888,8 +894,6 @@ cheat_manager_dialog* cheat_manager_dialog::get_dlg(QWidget* parent)
template <typename T>
T cheat_manager_dialog::convert_from_QString(const QString& str, bool& success)
{
T result;
if constexpr (std::is_same_v<T, u8>)
{
const u16 result_16 = str.toUShort(&success);
@ -897,17 +901,17 @@ T cheat_manager_dialog::convert_from_QString(const QString& str, bool& success)
if (result_16 > 0xFF)
success = false;
result = static_cast<T>(result_16);
return static_cast<T>(result_16);
}
if constexpr (std::is_same_v<T, u16>)
result = str.toUShort(&success);
return str.toUShort(&success);
if constexpr (std::is_same_v<T, u32>)
result = str.toUInt(&success);
return str.toUInt(&success);
if constexpr (std::is_same_v<T, u64>)
result = str.toULongLong(&success);
return str.toULongLong(&success);
if constexpr (std::is_same_v<T, s8>)
{
@ -915,28 +919,31 @@ T cheat_manager_dialog::convert_from_QString(const QString& str, bool& success)
if (result_16 < -128 || result_16 > 127)
success = false;
result = static_cast<T>(result_16);
return static_cast<T>(result_16);
}
if constexpr (std::is_same_v<T, s16>)
result = str.toShort(&success);
return str.toShort(&success);
if constexpr (std::is_same_v<T, s32>)
result = str.toInt(&success);
return str.toInt(&success);
if constexpr (std::is_same_v<T, s64>)
result = str.toLongLong(&success);
return str.toLongLong(&success);
return result;
if constexpr (std::is_same_v<T, f32>)
return str.toFloat(&success);
return {};
}
template <typename T>
bool cheat_manager_dialog::convert_and_search()
{
bool res_conv;
bool res_conv = false;
const QString to_search = edt_cheat_search_value->text();
T value = convert_from_QString<T>(to_search, res_conv);
const T value = convert_from_QString<T>(to_search, res_conv);
if (!res_conv)
return false;
@ -948,10 +955,10 @@ bool cheat_manager_dialog::convert_and_search()
template <typename T>
std::pair<bool, bool> cheat_manager_dialog::convert_and_set(u32 offset)
{
bool res_conv;
bool res_conv = false;
const QString to_set = edt_value_final->text();
T value = convert_from_QString<T>(to_set, res_conv);
const T value = convert_from_QString<T>(to_set, res_conv);
if (!res_conv)
return {false, false};
@ -974,6 +981,7 @@ void cheat_manager_dialog::do_the_search()
case cheat_type::signed_16_cheat: res_conv = convert_and_search<s16>(); break;
case cheat_type::signed_32_cheat: res_conv = convert_and_search<s32>(); break;
case cheat_type::signed_64_cheat: res_conv = convert_and_search<s64>(); break;
case cheat_type::float_32_cheat: res_conv = convert_and_search<f32>(); break;
default: log_cheat.fatal("Unsupported cheat type"); break;
}
@ -1065,6 +1073,7 @@ QString cheat_manager_dialog::get_localized_cheat_type(cheat_type type)
case cheat_type::signed_16_cheat: return tr("Signed 16 bits");
case cheat_type::signed_32_cheat: return tr("Signed 32 bits");
case cheat_type::signed_64_cheat: return tr("Signed 64 bits");
case cheat_type::float_32_cheat: return tr("Float 32 bits");
case cheat_type::max: break;
}
std::string type_formatted;

View file

@ -2277,11 +2277,13 @@ void game_list_frame::RemoveHDD1Cache(const std::string& base_dir, const std::st
game_list_log.fatal("Only %d/%d HDD1 cache directories could be removed in %s (%s)", dirs_removed, dirs_total, base_dir, title_id);
}
void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set<std::string>& serials, QString progressLabel, std::function<bool(const std::string&)> action, std::function<void(u32, u32)> cancel_log, bool refresh_on_finish, bool can_be_concurrent, std::function<bool()> should_wait_cb)
void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set<std::string>& serials, QString progressLabel, std::function<bool(const std::string&)> action, std::function<void(u32, u32)> cancel_log, bool refresh_on_finish, bool can_be_concurrent, std::function<bool()> should_wait_cb)
{
// Concurrent tasks should not wait (at least not in current implementation)
ensure(!should_wait_cb || !can_be_concurrent);
g_system_progress_canceled = false;
const std::shared_ptr<std::function<bool(int)>> iterate_over_serial = std::make_shared<std::function<bool(int)>>();
const std::shared_ptr<atomic_t<int>> index = std::make_shared<atomic_t<int>>(0);
@ -2297,12 +2299,16 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set
const std::string& serial = *std::next(serials.begin(), index);
if (pdlg->wasCanceled() || g_system_progress_canceled)
if (pdlg->wasCanceled() || g_system_progress_canceled.exchange(false))
{
cancel_log(index, serials_size);
if (cancel_log)
{
cancel_log(index, serials_size);
}
return false;
}
else if (action(serial))
if (action(serial))
{
const int done = index_ptr->load();
pdlg->setLabelText(progressLabel.arg(done + 1).arg(serials_size));
@ -2360,19 +2366,17 @@ void game_list_frame::BatchActionBySerials(progress_dialog* pdlg, const std::set
if ((*iterate_over_serial)(*index))
{
QTimer::singleShot(1, this, *periodic_func);
return;
}
else
pdlg->setLabelText(progressLabel.arg(*index).arg(serials_size));
pdlg->setCancelButtonText(tr("OK"));
connect(pdlg, &progress_dialog::canceled, this, [pdlg](){ pdlg->deleteLater(); });
QApplication::beep();
if (refresh_on_finish && index)
{
pdlg->setLabelText(progressLabel.arg(*index).arg(serials_size));
pdlg->setCancelButtonText(tr("OK"));
QApplication::beep();
if (refresh_on_finish && index)
{
Refresh(true);
}
pdlg->deleteLater();
Refresh(true);
}
};
@ -2414,6 +2418,14 @@ void game_list_frame::BatchCreateCPUCaches(const std::vector<game_info>& game_da
pdlg->setAutoReset(false);
pdlg->open();
connect(pdlg, &progress_dialog::canceled, this, []()
{
if (!Emu.IsStopped())
{
Emu.GracefulShutdown(false, true);
}
});
BatchActionBySerials(pdlg, serials, tr("%0\nProgress: %1/%2 caches compiled").arg(main_label),
[&, game_data](const std::string& serial)
{

View file

@ -394,7 +394,7 @@ void main_window::OnMissingFw()
{
const QString title = tr("Missing Firmware Detected!");
const QString message = tr("Commercial games require the firmware (PS3UPDAT.PUP file) to be installed."
"\n<br>For information about how to obtain the required firmware read the <a %0 href=\"https://rpcs3.net/quickstart\">quickstart guide</a>.").arg(gui::utils::get_link_style());
"\n<br>For information about how to obtain the required firmware read the <a %0 href=\"https://rpcs3.net/quickstart\">quickstart guide</a>.").arg(gui::utils::get_link_style());
QMessageBox* mb = new QMessageBox(QMessageBox::Question, title, message, QMessageBox::Ok | QMessageBox::Cancel, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowStaysOnTopHint);
mb->setTextFormat(Qt::RichText);
@ -2852,6 +2852,7 @@ void main_window::CreateConnects()
connect(dlg, &settings_dialog::EmuSettingsApplied, this, &main_window::NotifyEmuSettingsChange);
connect(dlg, &settings_dialog::EmuSettingsApplied, this, &main_window::update_gui_pad_thread);
connect(dlg, &settings_dialog::EmuSettingsApplied, m_log_frame, &log_frame::LoadSettings);
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->open();
};

View file

@ -1247,7 +1247,16 @@ bool patch_manager_dialog::handle_json(const QByteArray& data)
if (patch_engine::load(patches, "From Download", content, true, &log_message))
{
patch_log.notice("Successfully validated downloaded patch file");
const std::string path = patch_engine::get_patches_path() + "patch.yml";
const std::string patches_path = patch_engine::get_patches_path();
if (!fs::create_path(patches_path))
{
patch_log.fatal("Failed to create path: %s (%s)", patches_path, fs::g_tls_error);
return false;
}
const std::string path = patches_path + "patch.yml";
// Back up current patch file if possible
if (fs::is_file(path))

View file

@ -347,6 +347,19 @@ namespace stx
}
}
// Order semi-destructors before the actual destructors
// This allows to safely access data that may be deallocated or destroyed from other members of FXO regardless of their intialization time
for (u32 i = 0; i < _max; i++)
{
const auto info = (*std::prev(m_info, i + 1));
if (auto op = info->thread_op)
{
constexpr thread_state destroying_context{7};
op(*std::prev(m_order, i + 1), destroying_context);
}
}
// Destroy objects in reverse order
for (; _max; _max--)
{

View file

@ -361,13 +361,8 @@ namespace stx
[[deprecated("Use null_ptr")]] shared_ptr(std::nullptr_t) = delete;
// Not-so-aliasing constructor: emulates std::enable_shared_from_this without its overhead
explicit shared_ptr(T* _this) noexcept
: m_ptr(_this)
{
// Random checks which may fail on invalid pointer
ensure((reinterpret_cast<u64>(d()->destroy) - 0x10000) >> 47 == 0);
ensure((d()->refs++ - 1) >> 58 == 0);
}
template <typename Type>
friend shared_ptr<Type> make_shared_from_this(const Type* _this) noexcept;
template <typename U> requires same_ptr_implicit_v<T, U>
shared_ptr(const shared_ptr<U>& r) noexcept
@ -562,11 +557,29 @@ namespace stx
template <typename T>
requires (std::is_constructible_v<std::remove_reference_t<T>, T&&>)
static shared_ptr<std::remove_reference_t<T>> make_shared_value(T&& value)
static shared_ptr<std::remove_reference_t<T>> make_shared_value(T&& value) noexcept
{
return make_single_value(std::forward<T>(value));
}
// Not-so-aliasing constructor: emulates std::enable_shared_from_this without its overhead
template <typename T>
static shared_ptr<T> make_shared_from_this(const T* _this) noexcept
{
shared_ptr<T> r;
r.m_ptr = const_cast<T*>(_this);
if (!_this) [[unlikely]]
{
return r;
}
// Random checks which may fail on invalid pointer
ensure((reinterpret_cast<u64>(r.d()->destroy.load()) - 0x10000) >> 47 == 0);
ensure((r.d()->refs++ - 1) >> 58 == 0);
return r;
}
// Atomic simplified shared pointer
template <typename T>
class atomic_ptr
@ -1059,9 +1072,9 @@ namespace stx
do
{
// Update old head with current value
next.m_ptr = reinterpret_cast<T*>(old.m_val.raw() >> c_ref_size);
next.m_ptr = std::launder(ptr_to(old.m_val.raw()));
} while (!m_val.compare_exchange(old.m_val.raw(), reinterpret_cast<uptr>(exch.m_ptr) << c_ref_size));
} while (!m_val.compare_exchange(old.m_val.raw(), to_val(exch.m_ptr)));
// This argument is consumed (moved from)
exch.m_ptr = nullptr;
@ -1076,7 +1089,7 @@ namespace stx
// Simple atomic load is much more effective than load(), but it's a non-owning reference
T* observe() const noexcept
{
return reinterpret_cast<T*>(m_val >> c_ref_size);
return std::launder(ptr_to(m_val));
}
explicit constexpr operator bool() const noexcept
@ -1138,11 +1151,6 @@ namespace stx
return false;
}
constexpr std::nullptr_t get() const noexcept
{
return nullptr;
}
} null_ptr;
}