This commit is contained in:
Jordan Woyak 2025-04-19 10:35:33 -05:00 committed by GitHub
commit 7876d2c2e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 97 additions and 40 deletions

View file

@ -0,0 +1,66 @@
// Copyright 2025 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
// UniqueBuffer<T> and SharedBuffer<T> are a lighter alternative to std::vector<T>.
// The main benefit is that elements are not value-initialized like in vector.
// That can be quite a bit of unecessary overhead when allocating a large buffer.
namespace Common
{
namespace detail
{
template <auto MakeFunc, typename T>
class BufferBase final
{
public:
using PtrType = decltype(MakeFunc(1));
using value_type = T;
using size_type = std::size_t;
BufferBase() {}
BufferBase(size_type size) : m_ptr{MakeFunc(size)}, m_size{size} {}
void swap(BufferBase& other)
{
std::swap(m_ptr, other.m_ptr);
std::swap(m_size, other.m_size);
}
size_type size() const { return m_size; }
bool empty() const { return m_size == 0; }
T* get() { return m_ptr.get(); }
const T* get() const { return m_ptr.get(); }
T* data() { return m_ptr.get(); }
const T* data() const { return m_ptr.get(); }
T* begin() { return m_ptr.get(); }
T* end() { return m_ptr.get() + m_size; }
const T* begin() const { return m_ptr.get(); }
const T* end() const { return m_ptr.get() + m_size; }
T& operator[](size_type index) { return m_ptr[index]; }
const T& operator[](size_type index) const { return m_ptr[index]; }
private:
PtrType m_ptr;
size_type m_size = 0;
};
} // namespace detail
template <typename T>
using UniqueBuffer = detail::BufferBase<std::make_unique_for_overwrite<T[]>, T>;
// TODO: std::make_shared_for_overwrite requires GCC 12.1+
// template <typename T>
// using SharedBuffer = detail::BufferBase<std::make_shared_for_overwrite<T[]>, T>;
} // namespace Common

View file

@ -18,6 +18,7 @@ add_library(common
BitSet.h
BitUtils.h
BlockingLoop.h
Buffer.h
ChunkFile.h
CodeBlock.h
ColorUtil.cpp

View file

@ -85,8 +85,7 @@ public:
if (next_extent > file_size)
break;
// TODO: use make_unique_for_overwrite in C++20
value = std::unique_ptr<V[]>(new V[value_size]);
value = std::make_unique_for_overwrite<V[]>(value_size);
// read key/value and pass to reader
if (m_file.ReadArray(&key, 1) && m_file.ReadArray(value.get(), value_size) &&

View file

@ -4,7 +4,6 @@
#include "Core/State.h"
#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <filesystem>
#include <locale>
@ -12,7 +11,6 @@
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include <vector>
@ -31,12 +29,10 @@
#include "Common/MsgHandler.h"
#include "Common/Thread.h"
#include "Common/TimeUtil.h"
#include "Common/Timer.h"
#include "Common/Version.h"
#include "Common/WorkQueueThread.h"
#include "Core/AchievementManager.h"
#include "Core/Config/AchievementSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
@ -46,7 +42,7 @@
#include "Core/HW/Wiimote.h"
#include "Core/Host.h"
#include "Core/Movie.h"
#include "Core/NetPlayClient.h"
#include "Core/NetPlayProto.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
@ -71,14 +67,14 @@ static unsigned char __LZO_MMODEL out[OUT_LEN];
static AfterLoadCallbackFunc s_on_after_load_callback;
// Temporary undo state buffer
static std::vector<u8> s_undo_load_buffer;
static Common::UniqueBuffer<u8> s_undo_load_buffer;
static std::mutex s_undo_load_buffer_mutex;
static std::mutex s_load_or_save_in_progress_mutex;
struct CompressAndDumpState_args
{
std::vector<u8> buffer_vector;
Common::UniqueBuffer<u8> buffer;
std::string filename;
std::shared_ptr<Common::Event> state_write_done_event;
};
@ -205,7 +201,7 @@ static void DoState(Core::System& system, PointerWrap& p)
#endif // USE_RETRO_ACHIEVEMENTS
}
void LoadFromBuffer(Core::System& system, std::vector<u8>& buffer)
void LoadFromBuffer(Core::System& system, Common::UniqueBuffer<u8>& buffer)
{
if (NetPlay::IsNetPlayRunning())
{
@ -229,7 +225,7 @@ void LoadFromBuffer(Core::System& system, std::vector<u8>& buffer)
true);
}
void SaveToBuffer(Core::System& system, std::vector<u8>& buffer)
void SaveToBuffer(Core::System& system, Common::UniqueBuffer<u8>& buffer)
{
Core::RunOnCPUThread(
system,
@ -239,7 +235,7 @@ void SaveToBuffer(Core::System& system, std::vector<u8>& buffer)
DoState(system, p_measure);
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
buffer.resize(buffer_size);
buffer = Common::UniqueBuffer<u8>(buffer_size);
ptr = buffer.data();
PointerWrap p(&ptr, buffer_size, PointerWrap::Mode::Write);
@ -318,15 +314,14 @@ static void CompressBufferToFile(const u8* raw_buffer, u64 size, File::IOFile& f
while (true)
{
u64 bytes_left_to_compress = size - total_bytes_compressed;
const u64 bytes_left_to_compress = size - total_bytes_compressed;
int bytes_to_compress =
const int bytes_to_compress =
static_cast<int>(std::min(static_cast<u64>(LZ4_MAX_INPUT_SIZE), bytes_left_to_compress));
int compressed_buffer_size = LZ4_compressBound(bytes_to_compress);
auto compressed_buffer = std::make_unique<char[]>(compressed_buffer_size);
s32 compressed_len =
LZ4_compress_default(reinterpret_cast<const char*>(raw_buffer) + total_bytes_compressed,
compressed_buffer.get(), bytes_to_compress, compressed_buffer_size);
Common::UniqueBuffer<char> compressed_buffer(LZ4_compressBound(bytes_to_compress));
const int compressed_len = LZ4_compress_default(
reinterpret_cast<const char*>(raw_buffer) + total_bytes_compressed, compressed_buffer.get(),
bytes_to_compress, int(compressed_buffer.size()));
if (compressed_len == 0)
{
@ -380,8 +375,8 @@ static void WriteHeadersToFile(size_t uncompressed_size, File::IOFile& f)
static void CompressAndDumpState(Core::System& system, CompressAndDumpState_args& save_args)
{
const u8* const buffer_data = save_args.buffer_vector.data();
const size_t buffer_size = save_args.buffer_vector.size();
const u8* const buffer_data = save_args.buffer.data();
const size_t buffer_size = save_args.buffer.size();
const std::string& filename = save_args.filename;
// Find free temporary filename.
@ -485,8 +480,7 @@ void SaveAs(Core::System& system, const std::string& filename, bool wait)
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
// Then actually do the write.
std::vector<u8> current_buffer;
current_buffer.resize(buffer_size);
Common::UniqueBuffer<u8> current_buffer(buffer_size);
ptr = current_buffer.data();
PointerWrap p(&ptr, buffer_size, PointerWrap::Mode::Write);
DoState(system, p);
@ -498,7 +492,7 @@ void SaveAs(Core::System& system, const std::string& filename, bool wait)
std::shared_ptr<Common::Event> sync_event;
CompressAndDumpState_args save_args;
save_args.buffer_vector = std::move(current_buffer);
save_args.buffer = std::move(current_buffer);
save_args.filename = filename;
if (wait)
{
@ -531,8 +525,7 @@ static bool GetVersionFromLZO(StateHeader& header, File::IOFile& f)
// Just read the first block, since it will contain the full revision string
lzo_uint32 cur_len = 0; // size of compressed bytes
lzo_uint new_len = 0; // size of uncompressed bytes
std::vector<u8> buffer;
buffer.resize(header.legacy_header.lzo_size);
Common::UniqueBuffer<u8> buffer(header.legacy_header.lzo_size);
if (!f.ReadArray(&cur_len, 1) || !f.ReadBytes(out, cur_len))
return false;
@ -563,11 +556,9 @@ static bool GetVersionFromLZO(StateHeader& header, File::IOFile& f)
// Read in the string
if (buffer.size() >= sizeof(StateHeaderVersion) + header.version_header.version_string_length)
{
auto version_buffer = std::make_unique<char[]>(header.version_header.version_string_length);
memcpy(version_buffer.get(), buffer.data() + sizeof(StateHeaderVersion),
header.version_header.version_string_length);
header.version_string =
std::string(version_buffer.get(), header.version_header.version_string_length);
header.version_string.assign(
reinterpret_cast<char*>(buffer.data() + sizeof(StateHeaderVersion)),
header.version_header.version_string_length);
}
else
{
@ -613,15 +604,14 @@ static bool ReadStateHeaderFromFile(StateHeader& header, File::IOFile& f,
return false;
}
auto version_buffer = std::make_unique<char[]>(header.version_header.version_string_length);
if (!f.ReadBytes(version_buffer.get(), header.version_header.version_string_length))
std::string version_buffer(header.version_header.version_string_length, '\0');
if (!f.ReadBytes(version_buffer.data(), version_buffer.size()))
{
Core::DisplayMessage("Failed to read state version string", 2000);
return false;
}
header.version_string =
std::string(version_buffer.get(), header.version_header.version_string_length);
header.version_string = std::move(version_buffer);
}
return true;
@ -681,7 +671,7 @@ static bool DecompressLZ4(std::vector<u8>& raw_buffer, u64 size, File::IOFile& f
return false;
}
auto compressed_data = std::make_unique<char[]>(compressed_data_len);
Common::UniqueBuffer<char> compressed_data(compressed_data_len);
if (!f.ReadBytes(compressed_data.get(), compressed_data_len))
{
PanicAlertFmt("Could not read state data");
@ -959,7 +949,7 @@ void Shutdown()
// never)
{
std::lock_guard lk(s_undo_load_buffer_mutex);
std::vector<u8>().swap(s_undo_load_buffer);
decltype(s_undo_load_buffer)().swap(s_undo_load_buffer);
}
}

View file

@ -9,8 +9,8 @@
#include <functional>
#include <string>
#include <type_traits>
#include <vector>
#include "Common/Buffer.h"
#include "Common/CommonTypes.h"
namespace Core
@ -106,8 +106,8 @@ void Load(Core::System& system, int slot);
void SaveAs(Core::System& system, const std::string& filename, bool wait = false);
void LoadAs(Core::System& system, const std::string& filename);
void SaveToBuffer(Core::System& system, std::vector<u8>& buffer);
void LoadFromBuffer(Core::System& system, std::vector<u8>& buffer);
void SaveToBuffer(Core::System& system, Common::UniqueBuffer<u8>& buffer);
void LoadFromBuffer(Core::System& system, const Common::UniqueBuffer<u8>& buffer);
void LoadLastSaved(Core::System& system, int i = 1);
void SaveFirstSaved(Core::System& system);

View file

@ -26,6 +26,7 @@
<ClInclude Include="Common\BitSet.h" />
<ClInclude Include="Common\BitUtils.h" />
<ClInclude Include="Common\BlockingLoop.h" />
<ClInclude Include="Common\Buffer.h" />
<ClInclude Include="Common\ChunkFile.h" />
<ClInclude Include="Common\CodeBlock.h" />
<ClInclude Include="Common\ColorUtil.h" />