From 4ba2428c86d95fdfe9c580dd62e4a94309a4661c Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 8 Apr 2020 17:35:07 -0400
Subject: [PATCH] common: Add VirtualBuffer class, to abstract memory
 virtualization.

---
 src/common/CMakeLists.txt     |  2 ++
 src/common/virtual_buffer.cpp | 52 +++++++++++++++++++++++++++++++
 src/common/virtual_buffer.h   | 58 +++++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+)
 create mode 100644 src/common/virtual_buffer.cpp
 create mode 100644 src/common/virtual_buffer.h

diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index eeceaa655..6ffc612e7 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -155,6 +155,8 @@ add_library(common STATIC
     uuid.cpp
     uuid.h
     vector_math.h
+    virtual_buffer.cpp
+    virtual_buffer.h
     web_result.h
     zstd_compression.cpp
     zstd_compression.h
diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp
new file mode 100644
index 000000000..b426f4747
--- /dev/null
+++ b/src/common/virtual_buffer.cpp
@@ -0,0 +1,52 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#if defined __APPLE__ || defined __FreeBSD__ || defined __OpenBSD__
+#include <sys/sysctl.h>
+#elif defined __HAIKU__
+#include <OS.h>
+#else
+#include <sys/sysinfo.h>
+#endif
+#endif
+
+#include "common/assert.h"
+#include "common/virtual_buffer.h"
+
+namespace Common {
+
+void* AllocateMemoryPages(std::size_t size) {
+#ifdef _WIN32
+    void* base{VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE)};
+#else
+    void* base{mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0)};
+
+    if (base == MAP_FAILED) {
+        base = nullptr;
+    }
+#endif
+
+    ASSERT(base);
+
+    return base;
+}
+
+void FreeMemoryPages(void* base, std::size_t size) {
+    if (!base) {
+        return;
+    }
+#ifdef _WIN32
+    ASSERT(VirtualFree(base, 0, MEM_RELEASE));
+#else
+    ASSERT(munmap(base, size) == 0);
+#endif
+}
+
+} // namespace Common
diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h
new file mode 100644
index 000000000..da064e59e
--- /dev/null
+++ b/src/common/virtual_buffer.h
@@ -0,0 +1,58 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_funcs.h"
+
+namespace Common {
+
+void* AllocateMemoryPages(std::size_t size);
+void FreeMemoryPages(void* base, std::size_t size);
+
+template <typename T>
+class VirtualBuffer final : NonCopyable {
+public:
+    constexpr VirtualBuffer() = default;
+    explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} {
+        base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
+    }
+
+    ~VirtualBuffer() {
+        FreeMemoryPages(base_ptr, alloc_size);
+    }
+
+    void resize(std::size_t count) {
+        FreeMemoryPages(base_ptr, alloc_size);
+
+        alloc_size = count * sizeof(T);
+        base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
+    }
+
+    constexpr const T& operator[](std::size_t index) const {
+        return base_ptr[index];
+    }
+
+    constexpr T& operator[](std::size_t index) {
+        return base_ptr[index];
+    }
+
+    constexpr T* data() {
+        return base_ptr;
+    }
+
+    constexpr const T* data() const {
+        return base_ptr;
+    }
+
+    constexpr std::size_t size() const {
+        return alloc_size / sizeof(T);
+    }
+
+private:
+    std::size_t alloc_size{};
+    T* base_ptr{};
+};
+
+} // namespace Common