memmappedfile-fix (#115)

Co-authored-by: Metehan Tuncbilek <mtuncbilek95@gmail.com>
Reviewed-by: Georg Hagen <georg.hagen@madvoxel.com>
Co-authored-by: mtuncbilek <metehan.tuncbilek@madvoxel.com>
Co-committed-by: mtuncbilek <metehan.tuncbilek@madvoxel.com>
This commit is contained in:
mtuncbilek
2024-09-21 14:46:39 +02:00
committed by Georg Hagen
parent f6c48edac6
commit 95ddd4b23f
11 changed files with 801 additions and 114 deletions

View File

@@ -18,6 +18,13 @@ FetchContent_Declare(
-DTINYUSDZ_BUILD_TESTS:BOOL=OFF -DTINYUSDZ_BUILD_TESTS:BOOL=OFF
-DTINYUSDZ_BUILD_EXAMPLES:BOOL=OFF -DTINYUSDZ_BUILD_EXAMPLES:BOOL=OFF
) )
set(TINYUSDZ_NO_WERROR ON)
set(TINYUSDZ_BUILD_TESTS OFF)
set(TINYUSDZ_BUILD_BENCHMARKS OFF)
set(TINYUSDZ_BUILD_EXAMPLES OFF)
set(TINYUSDZ_WITH_BUILTIN_IMAGE_LOADER OFF)
FetchContent_MakeAvailable(tinyusdz) FetchContent_MakeAvailable(tinyusdz)
function (LinkTinyUSDZ TARGET) function (LinkTinyUSDZ TARGET)

View File

@@ -0,0 +1,45 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "ErrorUtils.hpp"
#if defined(_MSC_VER)
#include "Windows.h"
#endif
namespace OpenVulkano
{
#if defined(_MSC_VER)
std::string ErrorUtils::GetLastErrorMessage()
{
// Get the error message ID, if any.
DWORD errorID = GetLastError();
if (errorID == 0)
{
return std::string();
}
LPSTR messageBuffer = nullptr;
// Format the error message
uint64_t size =
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &messageBuffer, 0, NULL);
// Buffer it up
std::string message(messageBuffer, size);
// Free the buffer and return the message
LocalFree(messageBuffer);
return message;
}
#else
std::string ErrorUtils::GetLastErrorMessage()
{
return std::string();
}
#endif
}

View File

@@ -0,0 +1,18 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <string>
namespace OpenVulkano
{
class ErrorUtils
{
public:
static std::string GetLastErrorMessage();
};
}

View File

@@ -6,121 +6,15 @@
#include "MemMappedFile.hpp" #include "MemMappedFile.hpp"
#include "Base/Logger.hpp" #include "Base/Logger.hpp"
#ifdef _MSC_VER #include "MemMappedFileInternal.hpp"
#include <windows.h>
#else
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif
namespace OpenVulkano namespace OpenVulkano
{ {
class MemMappedFile::Internal final
{
public:
void* address = nullptr;
size_t size = 0;
#ifdef _MSC_VER
HANDLE fileHandle;
HANDLE fileMappingHandle;
Internal(const char* file, FileMode fileMode)
{ //TODO handle other file modes than read
fileHandle = CreateFile(
TEXT(file), // file to open
GENERIC_READ, // open for reading
0, // do not share
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attribute template
if (fileHandle == INVALID_HANDLE_VALUE)
{
Logger::FILESYS->critical("Failed to open file: {}", file);
return;
}
LARGE_INTEGER fileSize;
if (!GetFileSizeEx(fileHandle, &fileSize))
{
Logger::FILESYS->critical("Failed to get size of file: {}", file);
CloseHandle(fileHandle);
return;
}
size = fileSize.QuadPart;
fileMappingHandle = CreateFileMapping(
fileHandle,
NULL, // default security
PAGE_READONLY, // read-only access
0, // maximum object size (high-order)
0, // maximum object size (low-order)
NULL); // name of the mapping object
if (fileMappingHandle == 0)
{
Logger::FILESYS->critical("Failed to create file mapping handle: {}", file);
CloseHandle(fileHandle);
size = 0;
return;
}
address = MapViewOfFile(
fileMappingHandle, // handle to the map object
FILE_MAP_READ, // read access
0, // max. object size
0, // size of the hFile
0); // map the entire file
if (address == nullptr)
{
Logger::FILESYS->critical("Failed to create file mapping: {}", file);
CloseHandle(fileMappingHandle);
CloseHandle(fileHandle);
size = 0;
}
}
~Internal()
{
UnmapViewOfFile(address);
CloseHandle(fileMappingHandle);
CloseHandle(fileHandle);
}
#else
int fileHandle;
struct stat fileStat;
Internal(const char* file, FileMode fileMode)
{
fileHandle = open(file, fileMode);
if (fstat(fileHandle, &fileStat) == -1)
{
Logger::FILESYS->critical("Failed to query stats for file: {}", file);
return;
}
address = mmap(nullptr, fileStat.st_size, fileMode + 1, MAP_PRIVATE, fileHandle, 0);
if (address == MAP_FAILED)
{
Logger::FILESYS->critical("Failed to memory map file: {}", file);
address = nullptr;
}
size = fileStat.st_size;
}
~Internal()
{
munmap(address, fileStat.st_size);
close(fileHandle);
}
#endif
};
MemMappedFile::MemMappedFile(const std::filesystem::path& path, FileMode fileMode) MemMappedFile::MemMappedFile(const std::filesystem::path& path, FileMode fileMode)
: m_data(nullptr), m_size(0)
{ {
m_internal = std::make_shared<Internal>(path.string().c_str(), fileMode); std::string file = path.string();
m_internal = std::make_shared<MemMappedFileInternal>(file.c_str(), fileMode);
m_data = m_internal->address; m_data = m_internal->address;
m_size = (m_data) ? m_internal->size : 0; m_size = (m_data) ? m_internal->size : 0;
} }

View File

@@ -10,16 +10,22 @@
namespace OpenVulkano namespace OpenVulkano
{ {
class MemMappedFileInternal;
class MemMappedFile class MemMappedFile
{ {
class Internal; friend class MemMappedFileWriteHelper;
std::shared_ptr<Internal> m_internal; std::shared_ptr<MemMappedFileInternal> m_internal;
void* m_data; void* m_data;
size_t m_size; size_t m_size;
public: public:
enum FileMode : int { READ_ONLY = 0, WRITE_ONLY, READ_WRITE }; enum FileMode : int
{
READ_ONLY = 0,
WRITE_ONLY,
READ_WRITE
};
MemMappedFile(const std::filesystem::path& path, FileMode fileMode = READ_ONLY); MemMappedFile(const std::filesystem::path& path, FileMode fileMode = READ_ONLY);

View File

@@ -0,0 +1,125 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "MemMappedFileInternal.hpp"
#include "Base/Logger.hpp"
#include "Host/Windows/ErrorUtils.hpp"
namespace OpenVulkano
{
#ifdef _MSC_VER
MemMappedFileInternal::MemMappedFileInternal(const char* file, MemMappedFile::FileMode fileMode)
: size(0), fileHandle(nullptr), fileMappingHandle(nullptr)
{
DWORD openMode { 0 }, mapMode { 0 }, viewMode { 0 };
switch (fileMode)
{
case MemMappedFile::FileMode::READ_ONLY:
openMode = GENERIC_READ;
mapMode = PAGE_READONLY;
viewMode = FILE_MAP_READ;
break;
case MemMappedFile::FileMode::WRITE_ONLY:
openMode = GENERIC_WRITE;
mapMode = PAGE_READWRITE;
viewMode = FILE_MAP_WRITE;
break;
case MemMappedFile::FileMode::READ_WRITE:
openMode = GENERIC_ALL;
mapMode = PAGE_READWRITE;
viewMode = FILE_MAP_ALL_ACCESS;
break;
default:
break;
}
fileHandle = CreateFileA(file, // file to open
openMode, // open for switch case
NULL, // share mode
NULL, // default security
OPEN_ALWAYS, // always
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attribute template
if (fileHandle == INVALID_HANDLE_VALUE || fileHandle == NULL)
{
Logger::FILESYS->critical("Failed to open file: {}.", ErrorUtils::GetLastErrorMessage());
return;
}
LARGE_INTEGER fileSize;
if (!GetFileSizeEx(fileHandle, &fileSize))
{
Logger::FILESYS->critical("Failed to get size of file: {}", ErrorUtils::GetLastErrorMessage());
CloseHandle(fileHandle);
return;
}
size = fileSize.QuadPart;
fileMappingHandle = CreateFileMappingA(fileHandle,
NULL, // default security
mapMode, // mod for switch case
0, // maximum object size (high-order)
0, // maximum object size (low-order)
NULL); // name of the mapping object
if (fileMappingHandle == INVALID_HANDLE_VALUE || fileMappingHandle == NULL)
{
Logger::FILESYS->critical("Failed to create file mapping handle: {}", ErrorUtils::GetLastErrorMessage());
CloseHandle(fileHandle);
size = 0;
return;
}
address = MapViewOfFile(fileMappingHandle, // handle to the map object
viewMode, // access for switch case
0, // max. object size
0, // size of the hFile
0); // map the entire file
if (address == nullptr)
{
Logger::FILESYS->critical("Failed to create file mapping: {}", ErrorUtils::GetLastErrorMessage());
CloseHandle(fileMappingHandle);
CloseHandle(fileHandle);
size = 0;
}
}
MemMappedFileInternal::~MemMappedFileInternal()
{
UnmapViewOfFile(address);
CloseHandle(fileMappingHandle);
CloseHandle(fileHandle);
}
#else
MemMappedFileInternal::MemMappedFileInternal(const char* file, MemMappedFile::FileMode fileMode)
{
fileHandle = open(file, fileMode);
if (fstat(fileHandle, &fileStat) == -1)
{
Logger::FILESYS->critical("Failed to query stats for file: {}", file);
return;
}
address = mmap(nullptr, fileStat.st_size, fileMode + 1, MAP_SHARED, fileHandle, 0);
if (address == MAP_FAILED)
{
Logger::FILESYS->critical("Failed to memory map file: {}", file);
address = nullptr;
}
size = fileStat.st_size;
}
MemMappedFileInternal::~MemMappedFileInternal()
{
munmap(address, fileStat.st_size);
close(fileHandle);
}
#endif
}

View File

@@ -0,0 +1,50 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "MemMappedFile.hpp"
#ifdef _MSC_VER
#include <Windows.h>
#else
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif
namespace OpenVulkano
{
class MemMappedFileInternal
{
friend class MemMappedFileWriteHelper;
friend class MemMappedFile;
public:
MemMappedFileInternal(const char* file, MemMappedFile::FileMode fileMode);
~MemMappedFileInternal();
private:
#if defined(_MSC_VER)
bool InvalidHandle() const { return fileHandle == INVALID_HANDLE_VALUE || fileHandle == NULL; }
#else
[[nodiscard]] bool InvalidHandle() const { return fileHandle == -1; }
#endif
private:
void* address = nullptr;
size_t size = 0;
#ifdef _MSC_VER
HANDLE fileHandle;
HANDLE fileMappingHandle;
#else
int fileHandle;
struct stat fileStat;
#endif
};
}

View File

@@ -0,0 +1,367 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "MemMappedFileWriteHelper.hpp"
#include "MemMappedFile.hpp"
#include "MemMappedFileInternal.hpp"
#if defined(_WIN32)
#include <windows.h>
#include <Host/Windows/ErrorUtils.hpp>
#else
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif
#include "Base/Logger.hpp"
#include <iostream>
namespace OpenVulkano
{
#if defined(_WIN32)
MemMappedFileWriteHelper::MemMappedFileWriteHelper(const std::filesystem::path& path, size_t maxFileSize)
: m_path(path), m_file(nullptr)
{
// Check if file exists, so we can open it in the correct mode
DWORD openMode = CREATE_ALWAYS;
if (std::filesystem::exists(path))
{
openMode = OPEN_ALWAYS;
}
// Open the file
HANDLE fileHandle =
CreateFileA(path.string().c_str(), GENERIC_ALL, FILE_SHARE_WRITE, NULL, openMode, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE || fileHandle == NULL)
{
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
}
// Control the file size
LARGE_INTEGER currentSize {};
if (fileHandle)
{
if (!GetFileSizeEx(fileHandle, &currentSize))
{
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
}
}
if (currentSize.QuadPart <= 0 && maxFileSize == 0)
{
throw std::runtime_error("Either the file size has to be greater than 0 or Initial Size!");
}
// Set the file size
if (maxFileSize > 0)
{
if (fileHandle)
{
// Set the file size
if (!SetFilePointer(fileHandle, DWORD(maxFileSize), NULL, FILE_BEGIN))
{
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
}
if (!SetEndOfFile(fileHandle))
{
throw std::runtime_error(ErrorUtils::GetLastErrorMessage().c_str());
}
}
}
if (fileHandle)
{
CloseHandle(fileHandle);
}
m_file = new MemMappedFile(path.string().c_str(), MemMappedFile::FileMode::READ_WRITE);
}
MemMappedFileWriteHelper::~MemMappedFileWriteHelper() = default;
bool MemMappedFileWriteHelper::Resize(const size_t newSize)
{
if (newSize == 0)
{
// Handle the case where the new size is zero
Logger::FILESYS->critical("New size is zero.");
return false;
}
// Get the current file handle
if (m_file->m_internal->fileHandle == INVALID_HANDLE_VALUE)
{
Logger::FILESYS->critical("Invalid file handle.");
return false;
}
// Unmap the old view of the file and close the file mapping handle
if (!(m_file->m_internal->fileMappingHandle == NULL)
&& !(m_file->m_internal->fileMappingHandle == INVALID_HANDLE_VALUE))
{
UnmapViewOfFile(m_file->m_internal->address);
CloseHandle(m_file->m_internal->fileMappingHandle);
}
// Resize the file
if (!SetFilePointer(m_file->m_internal->fileHandle, static_cast<DWORD>(newSize), NULL, FILE_BEGIN))
{
Logger::FILESYS->critical("Failed to set file pointer. Reason: {}", GetLastError());
return false;
}
if (!SetEndOfFile(m_file->m_internal->fileHandle))
{
Logger::FILESYS->critical("Failed to set end of file.");
return false;
}
// Create a new file mapping handle
m_file->m_internal->fileMappingHandle =
CreateFileMappingW(m_file->m_internal->fileHandle, NULL, PAGE_READWRITE, 0, 0, NULL);
if (m_file->m_internal->fileMappingHandle == NULL)
{
Logger::FILESYS->critical("Failed to create file mapping.");
return false;
}
// Map the file to a new view
m_file->m_internal->address =
MapViewOfFile(m_file->m_internal->fileMappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (m_file->m_internal->address == NULL || m_file->m_internal->address == INVALID_HANDLE_VALUE)
{
Logger::FILESYS->critical("Failed to map view of file.");
return false;
}
return true;
}
bool MemMappedFileWriteHelper::Trim(const size_t finalFileSize)
{
HANDLE fileHandle {};
if (m_file->m_internal->InvalidHandle())
{
auto file = m_path.string();
fileHandle = CreateFileA(file.c_str(), // file to open
GENERIC_WRITE, // open for reading
0, // do not share
NULL, // default security
CREATE_ALWAYS, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attribute template
}
else
{
fileHandle = m_file->m_internal->fileHandle;
}
if (m_file)
{
if (!UnmapViewOfFile(m_file->m_internal->address))
{
Logger::FILESYS->critical("Failed to unmap view of file on trim.");
return false;
}
if (!CloseHandle(m_file->m_internal->fileMappingHandle))
{
Logger::FILESYS->critical("Failed to close file mapping handle.");
return false;
}
}
LARGE_INTEGER liSize;
liSize.QuadPart = finalFileSize;
if (!SetFilePointerEx(fileHandle, liSize, NULL, FILE_BEGIN) || !SetEndOfFile(fileHandle))
{
Logger::FILESYS->critical("Failed to trim file: {}", ErrorUtils::GetLastErrorMessage());
return false;
}
// Create a new file mapping handle
if (m_file)
{
m_file->m_internal->fileMappingHandle = CreateFileMappingW(fileHandle, NULL, PAGE_READWRITE, 0, 0, NULL);
if (m_file->m_internal->fileMappingHandle == NULL)
{
Logger::FILESYS->critical("Failed to create file mapping.");
return false;
}
// Map the file to a new view
m_file->m_internal->address =
MapViewOfFile(m_file->m_internal->fileMappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (m_file->m_internal->address == NULL || m_file->m_internal->address == INVALID_HANDLE_VALUE)
{
Logger::FILESYS->critical("Failed to map view of file.");
return false;
}
}
if (m_file)
{
m_file->m_size = finalFileSize;
m_file->m_internal->size = finalFileSize;
}
return true;
}
#else
MemMappedFileWriteHelper::MemMappedFileWriteHelper(const std::filesystem::path& path, size_t maxFileSize)
{
const auto file = path.string();
const int fileHandle = open(file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fileHandle == -1)
{
throw std::runtime_error("Failed to open file: " + file);
}
struct stat fileStat
{
};
if (fstat(fileHandle, &fileStat) == -1)
{
close(fileHandle);
throw std::runtime_error("Failed to get file size: " + file);
}
if (const size_t fileSize = fileStat.st_size; fileSize < maxFileSize)
{
if (ftruncate(fileHandle, maxFileSize) == -1)
{
close(fileHandle);
throw std::runtime_error("Failed to resize file: " + file);
}
}
close(fileHandle);
m_file = new MemMappedFile(file.c_str(), MemMappedFile::FileMode::READ_WRITE);
}
MemMappedFileWriteHelper::~MemMappedFileWriteHelper() = default;
bool MemMappedFileWriteHelper::Resize(const size_t newSize)
{
if (newSize == 0)
{
// Handle the case where the new size is zero
Logger::FILESYS->error("New size is zero. New size must be greater than zero.");
return false;
}
// Get the current file handle
if (m_file->m_internal->fileHandle == -1)
{
Logger::FILESYS->critical("Invalid file handle.");
return false;
}
// Resize the file
if (ftruncate(m_file->m_internal->fileHandle, newSize) == -1)
{
Logger::FILESYS->critical("Failed to resize file.");
return false;
}
// Unmap the old view and map a new view of the resized file
if (m_file->m_internal->address != nullptr)
{
if (munmap(m_file->m_internal->address, m_file->m_internal->size) == -1)
{
Logger::FILESYS->critical("Failed to unmap view of file.");
return false;
}
}
// Map the file to a new view
m_file->m_internal->address =
mmap(nullptr, newSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_file->m_internal->fileHandle, 0);
if (m_file->m_internal->address == MAP_FAILED)
{
Logger::FILESYS->critical("Failed to map file.");
return false;
}
// Update the size of the file
m_file->m_internal->size = newSize;
return true;
}
bool MemMappedFileWriteHelper::Trim(const size_t finalFileSize)
{
// If getting handle returns invalid file recreate the file
if (m_file->m_internal->InvalidHandle())
{
const auto file = m_path.string();
m_file->m_internal->fileHandle = open(file.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
}
// Unmap the old view of the file
if(munmap(m_file->m_internal->address, m_file->m_internal->size) == -1)
{
Logger::FILESYS->critical("Failed to unmap address.");
}
// Trim the file
if (ftruncate(m_file->m_internal->fileHandle, finalFileSize) == -1)
{
Logger::FILESYS->critical("Failed to trim file.");
return false;
}
// Remap the file with the new size
m_file->m_internal->address = mmap(nullptr, finalFileSize, PROT_READ | PROT_WRITE, MAP_SHARED,
m_file->m_internal->fileHandle, 0);
if (m_file->m_internal->address == MAP_FAILED)
{
Logger::FILESYS->critical("Failed to map file.");
return false;
}
// Update the size in MemMappedFile structure
m_file->m_size = finalFileSize;
return true;
}
#endif
void MemMappedFileWriteHelper::Close()
{
if (m_file->IsOpen())
{
delete m_file;
}
}
MemMappedFileWriter::MemMappedFileWriter(const std::filesystem::path& path, size_t maxFileSize)
: m_helper(MemMappedFileWriteHelper(path, maxFileSize))
{
}
MemMappedFileWriter::~MemMappedFileWriter() { m_helper.Close(); }
void MemMappedFileWriter::Write(const char* data, const size_t size)
{
// If the new size is greater than the current size, resize the file
if (m_writtenSize + size > m_helper.Size())
{
m_helper.Resize(m_writtenSize + size);
}
// Write to the end of the file
memcpy(static_cast<char*>(m_helper.Data()) + m_writtenSize, data, size);
m_writtenSize += size;
}
}

View File

@@ -0,0 +1,48 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "IO/MemMappedFile.hpp"
#include <filesystem>
namespace OpenVulkano
{
class MemMappedFileWriteHelper
{
public:
MemMappedFileWriteHelper(const std::filesystem::path& path, size_t maxFileSize);
~MemMappedFileWriteHelper();
[[nodiscard]] void* Data() const { return m_file->Data(); }
[[nodiscard]] size_t Size() const { return m_file->Size(); }
bool Resize(size_t newSize);
void Close();
bool Trim(size_t finalFileSize);
static constexpr size_t USE_CURRENT_FILE_SIZE = 0;
private:
MemMappedFile* m_file;
std::filesystem::path m_path;
};
class MemMappedFileWriter final
{
public:
MemMappedFileWriter(const std::filesystem::path& path, size_t maxFileSize);
~MemMappedFileWriter();
void Write(const char* data, size_t size);
void SetOffset(size_t offset) { m_writtenSize = offset; }
[[nodiscard]] size_t GetOffset() const { return m_writtenSize; }
private:
MemMappedFileWriteHelper m_helper;
size_t m_writtenSize = 0;
};
}

View File

@@ -6,6 +6,7 @@
#pragma once #pragma once
#include "Base/Wrapper.hpp"
#include "Math/Math.hpp" #include "Math/Math.hpp"
#include "Image/Image.hpp" #include "Image/Image.hpp"
#include "Scene/Texture.hpp" #include "Scene/Texture.hpp"
@@ -56,7 +57,7 @@ namespace OpenVulkano::Scene
{ {
std::map<uint32_t, GlyphInfo> glyphs; std::map<uint32_t, GlyphInfo> glyphs;
AtlasMetadata meta; AtlasMetadata meta;
std::unique_ptr<Image::Image> img; Unique<Image::Image> img;
Texture texture; Texture texture;
}; };

126
tests/MemFileTests.cpp Normal file
View File

@@ -0,0 +1,126 @@
#include <catch2/catch_all.hpp>
#include "IO/MemMappedFile.hpp"
#include "IO/MemMappedFileWriteHelper.hpp"
#include "IO/AppFolders.hpp"
#include "Base/Logger.hpp"
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
TEST_CASE("MemMappedFileWrite")
{
OpenVulkano::Logger::SetupLogger("", "tests.log");
auto path = OpenVulkano::AppFolders::GetAppTempDir();
path += "/MemFileTest.txt";
std::string data = "Hello World X\n"
"Hello World Y\n"
"Hello World Z\n"
"Hello World W\n"
"Hello World A\n"
"Hello World B\n"
"Hello World C\n"
"Hello World D\n"
"Hello World E\n"
"Hello World F\n"
"Hello World G\n"
"Hello World H\n"
"Hello World I\n"
"Hello World J\n"
"Hello World K\n"
"Hello World L\n"
"Hello World M\n"
"Hello World N\n";
SECTION("Write to MemMappedFile")
{
OpenVulkano::MemMappedFileWriter writer(path, 1024);
writer.Write(data.data(), data.size());
REQUIRE(writer.GetOffset() == data.size());
}
SECTION("Control Size")
{
OpenVulkano::MemMappedFile memFile(path, OpenVulkano::MemMappedFile::READ_ONLY);
REQUIRE(memFile.Size() == 1024); // The size that comes from the first Test.
}
SECTION("Compare String Data for per char")
{
OpenVulkano::MemMappedFileWriteHelper memFileHelper(path, OpenVulkano::MemMappedFile::READ_ONLY);
REQUIRE(memFileHelper.Trim(data.size()));
std::string testData((char*) memFileHelper.Data());
for (size_t i = 0; i < data.size(); i++)
{
if (data[i] != testData[i])
{
REQUIRE(false);
}
}
memFileHelper.Close();
}
SECTION("Trim File")
{
OpenVulkano::MemMappedFileWriteHelper helper(path,
OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
REQUIRE(helper.Trim(100));
REQUIRE(helper.Size() == 100);
helper.Close();
}
SECTION("Write Data 2")
{
OpenVulkano::MemMappedFileWriter writer(path, OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
writer.Write(data.data(), data.size());
writer.Write(data.data(), data.size());
writer.Write(data.data(), data.size());
REQUIRE(writer.GetOffset() == data.size() * 3);
}
SECTION("Compare Data")
{
OpenVulkano::MemMappedFileWriteHelper helper(path,
OpenVulkano::MemMappedFileWriteHelper::USE_CURRENT_FILE_SIZE);
REQUIRE(helper.Data() != nullptr);
std::string testData((char*) helper.Data());
printf("size: %llu", helper.Size());
helper.Close();
std::ifstream file(path, std::ios::binary);
std::string streamData;
std::getline(file, streamData, '\0');
file.close();
for (size_t i = 0; i < testData.size(); i++)
{
if (streamData[i] != testData[i])
{
REQUIRE(false);
}
}
REQUIRE(streamData.size() == testData.size());
printf("helper size: %llu\n", helper.Size());
}
SECTION("Actual Size")
{
std::error_code ec;
std::uintmax_t size = fs::file_size(path, ec);
REQUIRE(size == 756);
}
}