mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-05-08 15:18:22 +00:00
VirtualBuffer<> would be recreated each time due to the `operator=()` from the unique_ptr<> when initializing a new process, this change makes it so said thing doesn't happen (instead it resizes the existing buffer) this means that consecutive launches of the same process that happen to have the same process page table (or reuse it) will no longer incur a ctor/dtor path for VirtualBuffer and instead just resize the existing one Signed-off-by: lizzie <lizzie@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3891 Reviewed-by: crueter <crueter@eden-emu.dev> Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
84 lines
2.5 KiB
C++
84 lines
2.5 KiB
C++
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#include <utility>
|
|
|
|
namespace Common {
|
|
|
|
void* AllocateMemoryPages(std::size_t size) noexcept;
|
|
void FreeMemoryPages(void* base, std::size_t size) noexcept;
|
|
|
|
template <typename T>
|
|
class VirtualBuffer final {
|
|
public:
|
|
// TODO: Uncomment this and change Common::PageTable::PageInfo to be trivially constructible
|
|
// using std::atomic_ref once libc++ has support for it
|
|
// static_assert(
|
|
// std::is_trivially_constructible_v<T>,
|
|
// "T must be trivially constructible, as non-trivial constructors will not be executed "
|
|
// "with the current allocator");
|
|
|
|
constexpr VirtualBuffer() = default;
|
|
explicit VirtualBuffer(std::size_t count) noexcept
|
|
: alloc_size{count * sizeof(T)}
|
|
{
|
|
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
|
}
|
|
|
|
~VirtualBuffer() noexcept {
|
|
FreeMemoryPages(base_ptr, alloc_size);
|
|
}
|
|
|
|
VirtualBuffer(const VirtualBuffer&) = delete;
|
|
VirtualBuffer& operator=(const VirtualBuffer&) = delete;
|
|
|
|
VirtualBuffer(VirtualBuffer&& other) noexcept
|
|
: alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr), nullptr}
|
|
{}
|
|
|
|
VirtualBuffer& operator=(VirtualBuffer&& other) noexcept {
|
|
alloc_size = std::exchange(other.alloc_size, 0);
|
|
base_ptr = std::exchange(other.base_ptr, nullptr);
|
|
return *this;
|
|
}
|
|
|
|
void resize(std::size_t count) noexcept {
|
|
if (auto const new_size = count * sizeof(T); new_size != alloc_size) {
|
|
FreeMemoryPages(base_ptr, alloc_size);
|
|
alloc_size = new_size;
|
|
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] constexpr const T& operator[](std::size_t index) const noexcept {
|
|
return base_ptr[index];
|
|
}
|
|
|
|
[[nodiscard]] constexpr T& operator[](std::size_t index) noexcept {
|
|
return base_ptr[index];
|
|
}
|
|
|
|
[[nodiscard]] constexpr T* data() noexcept {
|
|
return base_ptr;
|
|
}
|
|
|
|
[[nodiscard]] constexpr const T* data() const noexcept {
|
|
return base_ptr;
|
|
}
|
|
|
|
[[nodiscard]] constexpr std::size_t size() const noexcept {
|
|
return alloc_size / sizeof(T);
|
|
}
|
|
|
|
private:
|
|
std::size_t alloc_size{};
|
|
T* base_ptr{};
|
|
};
|
|
|
|
} // namespace Common
|