MemoryMappedFile + File + BigFIle more representative numbers

This commit is contained in:
2026-08-28 01:00:38 +02:00
parent ed5061dc52
commit 3e3e3798ae
17 changed files with 913 additions and 159 deletions
+35 -11
View File
@@ -1,6 +1,12 @@
/*********************************************************************
* \file BigFile.cpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#include <Engine/BigFile/BigFile.hpp>
#include <System/File.hpp>
#include <System/File/File.hpp>
#include <System/UUID/UUID.hpp>
#include <EngineBenchmarks/BigFileInfo_generated.hpp>
@@ -71,6 +77,20 @@ class Fixture: public benchmark::Fixture
return batch;
}
[[nodiscard]]
eastl::vector<eastl::vector<UUID>> RandomBatchPool(const std::size_t p_batchSize,
const std::size_t p_poolSize) const
{
eastl::vector<eastl::vector<UUID>> pool;
pool.reserve(p_poolSize);
for (std::size_t i = 0; i < p_poolSize; ++i)
{
pool.push_back(RandomBatch(p_batchSize));
}
return pool;
}
BigFile m_bigFile {File {BIGFILE_ENGINEBENCHMARKS_LOCATION}};
eastl::vector<UUID> m_uuids;
};
@@ -105,21 +125,24 @@ BENCHMARK_REGISTER_F(Fixture, GetAssetFlatbuffer)->Name("BigFile/GetAssetFlatbuf
BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffers)(benchmark::State& state)
{
const auto batchSize = static_cast<std::size_t>(state.range(0));
constexpr std::size_t BATCH_POOL_SIZE = 64;
const eastl::vector<eastl::vector<UUID>> batchPool = RandomBatchPool(batchSize, BATCH_POOL_SIZE);
std::int64_t bytesProcessed = 0;
std::size_t batchIndex = 0;
for (auto _: state)
{
state.PauseTiming();
const eastl::vector<UUID> batch = RandomBatch(batchSize);
state.ResumeTiming();
eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile.GetAssetFlatbuffers(batch);
eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile.GetAssetFlatbuffers(batchPool[batchIndex]);
benchmark::DoNotOptimize(flatbuffers);
for (const eastl::vector<std::byte>& flatbuffer: flatbuffers)
{
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
}
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
}
state.SetItemsProcessed(state.iterations() * batchSize);
@@ -154,13 +177,14 @@ BENCHMARK_DEFINE_F(Fixture, GetAssetMetadatas)(benchmark::State& state)
{
const auto batchSize = static_cast<std::size_t>(state.range(0));
constexpr std::size_t BATCH_POOL_SIZE = 64;
const eastl::vector<eastl::vector<UUID>> batchPool = RandomBatchPool(batchSize, BATCH_POOL_SIZE);
std::size_t batchIndex = 0;
for (auto _: state)
{
state.PauseTiming();
const eastl::vector<UUID> batch = RandomBatch(batchSize);
state.ResumeTiming();
benchmark::DoNotOptimize(m_bigFile.GetAssetMetadatas(batch));
benchmark::DoNotOptimize(m_bigFile.GetAssetMetadatas(batchPool[batchIndex]));
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
}
state.SetItemsProcessed(state.iterations() * batchSize);
@@ -9,6 +9,8 @@
#include <EASTL/string_view.h>
#if defined BIGFOOT_TOOLMODE
namespace Bigfoot
{
/*
@@ -17,3 +19,4 @@ namespace Bigfoot
constexpr eastl::string_view BIGFILE_ENGINEBENCHMARKS_LOCATION {"./EngineBenchmarks-bigfile.db"};
} // namespace Bigfoot
#endif
#endif
@@ -102,6 +102,19 @@ eastl::vector<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffers(const eastl
return flatbuffers;
}
flatbuffers.reserve(p_uuids.size());
if (p_uuids.size() == 1)
{
if (eastl::optional<eastl::vector<std::byte>> flatbuffer = GetAssetFlatbuffer(p_uuids[0]);
flatbuffer.has_value())
{
flatbuffers.push_back(std::move(*flatbuffer));
}
return flatbuffers;
}
eastl::vector<UUID> uniqueUUIDs {p_uuids.begin(), p_uuids.end()};
eastl::sort(uniqueUUIDs.begin(), uniqueUUIDs.end());
uniqueUUIDs.erase(eastl::unique(uniqueUUIDs.begin(), uniqueUUIDs.end()), uniqueUUIDs.end());
@@ -174,6 +187,18 @@ eastl::vector<AssetMetadata> BigFile::GetAssetMetadatas(const eastl::span<const
return metadatas;
}
metadatas.reserve(p_uuids.size());
if (p_uuids.size() == 1)
{
if (eastl::optional<AssetMetadata> metadata = GetAssetMetadata(p_uuids[0]); metadata.has_value())
{
metadatas.push_back(std::move(*metadata));
}
return metadatas;
}
eastl::vector<UUID> uniqueUUIDs {p_uuids.begin(), p_uuids.end()};
eastl::sort(uniqueUUIDs.begin(), uniqueUUIDs.end());
uniqueUUIDs.erase(eastl::unique(uniqueUUIDs.begin(), uniqueUUIDs.end()), uniqueUUIDs.end());
@@ -8,7 +8,7 @@
#define BIGFOOT_ENGINE_BIGFILE_BIGFILE_HPP
#include <Engine/DataAccessor/DataAccessor.hpp>
#include <System/File.hpp>
#include <System/File/File.hpp>
#include <Utils/TaggedType.hpp>
@@ -9,6 +9,8 @@
#include <EASTL/string_view.h>
#if defined BIGFOOT_TOOLMODE
namespace Bigfoot
{
/*
@@ -16,4 +18,5 @@ namespace Bigfoot
*/
constexpr eastl::string_view BIGFILE_@BIGFILE_NAME@_LOCATION {"@BIGFILE_LOCATION@"};
} // namespace Bigfoot
#endif
#endif
-66
View File
@@ -1,66 +0,0 @@
/*********************************************************************
* \file File.cpp
*
* \author Romain BOULLARD
* \date December 2025
*********************************************************************/
#include <System/File.hpp>
namespace Bigfoot
{
File::File(const eastl::string_view p_path):
m_path(p_path.data()),
m_pathString(p_path)
{
}
/****************************************************************************************/
bool File::IsAbsolute() const
{
return m_path.is_absolute();
}
/****************************************************************************************/
bool File::IsRelative() const
{
return m_path.is_relative();
}
/****************************************************************************************/
bool File::Exists() const
{
return std::filesystem::exists(m_path);
}
/****************************************************************************************/
eastl::string_view File::GetPath() const
{
return m_pathString;
}
/****************************************************************************************/
File File::ToAbsolute() const
{
return File {std::filesystem::absolute(m_path)};
}
/****************************************************************************************/
File File::ToRelative() const
{
return File {std::filesystem::relative(m_path)};
}
/****************************************************************************************/
File::File(const std::filesystem::path& p_path):
m_path(p_path),
m_pathString(m_path.string().c_str())
{
}
} // namespace Bigfoot
+120
View File
@@ -0,0 +1,120 @@
/*********************************************************************
* \file File.cpp
*
* \author Romain BOULLARD
* \date December 2025
*********************************************************************/
#include <System/File/File.hpp>
#include <System/SystemAssertHandler.hpp>
#include <bit>
#include <fstream>
#include <string>
namespace Bigfoot
{
File::File(const eastl::string_view p_path):
m_path(p_path.data()),
m_pathString(p_path)
{
}
/****************************************************************************************/
bool File::IsAbsolute() const
{
return m_path.is_absolute();
}
/****************************************************************************************/
bool File::IsRelative() const
{
return m_path.is_relative();
}
/****************************************************************************************/
bool File::Exists() const
{
return std::filesystem::exists(m_path);
}
/****************************************************************************************/
eastl::string_view File::GetPath() const
{
return m_pathString;
}
/****************************************************************************************/
File File::ToAbsolute() const
{
return File {std::filesystem::absolute(m_path)};
}
/****************************************************************************************/
File File::ToRelative() const
{
return File {std::filesystem::relative(m_path)};
}
/****************************************************************************************/
std::size_t File::GetSize() const
{
return static_cast<std::size_t>(std::filesystem::file_size(m_path));
}
/****************************************************************************************/
eastl::vector<std::byte> File::Read(const std::size_t p_offset, const std::size_t p_size) const
{
const File absoluteFile = ToAbsolute();
const eastl::string_view path = absoluteFile.GetPath();
std::ifstream file {path.data(), std::ios::binary};
CRITICAL_ASSERT(SystemAssertHandler, file.is_open(), "Failed to open file {} for reading", path);
file.seekg(static_cast<std::streamoff>(p_offset), std::ios::beg);
eastl::vector<std::byte> data;
data.resize(p_size);
file.read(std::bit_cast<char*>(data.data()), static_cast<std::streamsize>(data.size()));
return data;
}
/****************************************************************************************/
void File::Write(const eastl::span<const std::byte> p_data, const std::size_t p_offset) const
{
const File absoluteFile = ToAbsolute();
const eastl::string_view path = absoluteFile.GetPath();
std::ofstream {path.data(), std::ios::binary | std::ios::app};
std::fstream file {path.data(), std::ios::binary | std::ios::in | std::ios::out};
CRITICAL_ASSERT(SystemAssertHandler, file.is_open(), "Failed to open file {} for writing", path);
file.seekp(static_cast<std::streamoff>(p_offset), std::ios::beg);
file.write(std::bit_cast<const char*>(p_data.data()), static_cast<std::streamsize>(p_data.size()));
}
/****************************************************************************************/
void File::Delete() const
{
std::filesystem::remove(m_path);
}
/****************************************************************************************/
File::File(const std::filesystem::path& p_path):
m_path(p_path),
m_pathString(m_path.string().c_str())
{
}
} // namespace Bigfoot
@@ -0,0 +1,229 @@
/*********************************************************************
* \file MemoryMappedFile.cpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#include <System/File/MemoryMappedFile.hpp>
#include <System/SystemAssertHandler.hpp>
#include <string>
#if defined BIGFOOT_WINDOWS
#include <Windows.h>
#elif defined BIGFOOT_LINUX
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
namespace Bigfoot
{
MemoryMappedFile::MemoryMappedFile(const File& p_file)
{
const File absoluteFile = p_file.ToAbsolute();
const eastl::string_view path = absoluteFile.GetPath();
#if defined BIGFOOT_WINDOWS
m_fileHandle = CreateFileA(path.data(),
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
nullptr);
CRITICAL_ASSERT(SystemAssertHandler, m_fileHandle != INVALID_HANDLE_VALUE, "Failed to open file {}", path);
LARGE_INTEGER fileSize {};
[[maybe_unused]]
const BOOL gotFileSize = GetFileSizeEx(m_fileHandle, &fileSize);
CRITICAL_ASSERT(SystemAssertHandler, gotFileSize, "Failed to get the size of file {}", path);
m_size = static_cast<std::size_t>(fileSize.QuadPart);
if (m_size != 0)
{
m_mappingHandle = CreateFileMappingA(m_fileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr);
CRITICAL_ASSERT(SystemAssertHandler, m_mappingHandle != nullptr, "Failed create the file mapping {}", path);
m_data = static_cast<std::byte*>(MapViewOfFile(m_mappingHandle, FILE_MAP_READ, 0, 0, 0));
CRITICAL_ASSERT(SystemAssertHandler, m_data != nullptr, "Failed to map the file {}", path);
}
#elif defined BIGFOOT_LINUX
m_fileDescriptor = open(path.data(), O_RDONLY);
CRITICAL_ASSERT(SystemAssertHandler, m_fileDescriptor != -1, "Failed to open file {}", path);
struct stat fileStat {};
[[maybe_unused]]
const int statResult = fstat(m_fileDescriptor, &fileStat);
CRITICAL_ASSERT(SystemAssertHandler, statResult == 0, "Failed to get the size of file {}", path);
m_size = static_cast<std::size_t>(fileStat.st_size);
if (m_size != 0)
{
void* const mapped = mmap(nullptr, m_size, PROT_READ, MAP_PRIVATE, m_fileDescriptor, 0);
CRITICAL_ASSERT(SystemAssertHandler, mapped != MAP_FAILED, "Failed to map file {}", path);
m_data = static_cast<std::byte*>(mapped);
[[maybe_unused]]
const int adviseResult = madvise(mapped, m_size, MADV_RANDOM);
}
#else
CRITICAL_ASSERT(SystemAssertHandler, false, "MemoryMappedFileBase is not implemented on this platform");
#endif
}
/****************************************************************************************/
MemoryMappedFile::~MemoryMappedFile()
{
#if defined BIGFOOT_WINDOWS
if (m_data != nullptr)
{
[[maybe_unused]]
const BOOL unmapped = UnmapViewOfFile(m_data);
CRITICAL_ASSERT(SystemAssertHandler, unmapped, "Failed to unmap the file");
}
if (m_mappingHandle != nullptr)
{
[[maybe_unused]]
const BOOL closedMapping = CloseHandle(m_mappingHandle);
CRITICAL_ASSERT(SystemAssertHandler, closedMapping, "Failed to close the file mapping");
}
if (m_fileHandle != INVALID_HANDLE_VALUE)
{
[[maybe_unused]]
const BOOL closedFile = CloseHandle(m_fileHandle);
CRITICAL_ASSERT(SystemAssertHandler, closedFile, "Failed to close the file");
}
#elif defined BIGFOOT_LINUX
if (m_data != nullptr)
{
[[maybe_unused]]
const int unmapped = munmap(m_data, m_size);
CRITICAL_ASSERT(SystemAssertHandler, unmapped == 0, "Failed to unmap the file");
}
if (m_fileDescriptor != -1)
{
[[maybe_unused]]
const int closedFile = close(m_fileDescriptor);
CRITICAL_ASSERT(SystemAssertHandler, closedFile == 0, "Failed to close the file");
}
#else
CRITICAL_ASSERT(SystemAssertHandler, false, "MemoryMappedFileBase is not implemented on this platform");
#endif
}
/****************************************************************************************/
eastl::span<const std::byte> MemoryMappedFile::GetData() const
{
return eastl::span<const std::byte> {m_data, m_size};
}
/****************************************************************************************/
WritableMemoryMappedFile::WritableMemoryMappedFile(const File& p_file, const std::size_t p_size):
m_size(p_size)
{
const File absoluteFile = p_file.ToAbsolute();
const eastl::string_view path = absoluteFile.GetPath();
#if defined BIGFOOT_WINDOWS
m_fileHandle =
CreateFileA(path.data(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
CRITICAL_ASSERT(SystemAssertHandler, m_fileHandle != INVALID_HANDLE_VALUE, "Failed to create file {}", path);
const LARGE_INTEGER size {.QuadPart = static_cast<LONGLONG>(p_size)};
m_mappingHandle = CreateFileMappingA(m_fileHandle, nullptr, PAGE_READWRITE, size.HighPart, size.LowPart, nullptr);
CRITICAL_ASSERT(SystemAssertHandler, m_mappingHandle != nullptr, "Failed create the file mapping {}", path);
m_data = static_cast<std::byte*>(MapViewOfFile(m_mappingHandle, FILE_MAP_WRITE, 0, 0, 0));
CRITICAL_ASSERT(SystemAssertHandler, m_data != nullptr, "Failed to map the file {}", path);
#elif defined BIGFOOT_LINUX
m_fileDescriptor = open(path.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
CRITICAL_ASSERT(SystemAssertHandler, m_fileDescriptor != -1, "Failed to create file {}", path);
[[maybe_unused]]
const int truncateResult = ftruncate(m_fileDescriptor, static_cast<off_t>(p_size));
CRITICAL_ASSERT(SystemAssertHandler, truncateResult == 0, "Failed to size file {}", path);
void* const mapped = mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fileDescriptor, 0);
CRITICAL_ASSERT(SystemAssertHandler, mapped != MAP_FAILED, "Failed to map file {}", path);
m_data = static_cast<std::byte*>(mapped);
#else
CRITICAL_ASSERT(SystemAssertHandler, false, "MemoryMappedFileBase is not implemented on this platform");
#endif
}
/****************************************************************************************/
WritableMemoryMappedFile::~WritableMemoryMappedFile()
{
#if defined BIGFOOT_WINDOWS
if (m_data != nullptr)
{
[[maybe_unused]]
const BOOL unmapped = UnmapViewOfFile(m_data);
CRITICAL_ASSERT(SystemAssertHandler, unmapped, "Failed to unmap the file");
}
if (m_mappingHandle != nullptr)
{
[[maybe_unused]]
const BOOL closedMapping = CloseHandle(m_mappingHandle);
CRITICAL_ASSERT(SystemAssertHandler, closedMapping, "Failed to close the file mapping");
}
if (m_fileHandle != INVALID_HANDLE_VALUE)
{
[[maybe_unused]]
const BOOL closedFile = CloseHandle(m_fileHandle);
CRITICAL_ASSERT(SystemAssertHandler, closedFile, "Failed to close the file");
}
#elif defined BIGFOOT_LINUX
if (m_data != nullptr)
{
[[maybe_unused]]
const int unmapped = munmap(m_data, m_size);
CRITICAL_ASSERT(SystemAssertHandler, unmapped == 0, "Failed to unmap the file");
}
if (m_fileDescriptor != -1)
{
[[maybe_unused]]
const int closedFile = close(m_fileDescriptor);
CRITICAL_ASSERT(SystemAssertHandler, closedFile == 0, "Failed to close the file");
}
#else
CRITICAL_ASSERT(SystemAssertHandler, false, "MemoryMappedFileBase is not implemented on this platform");
#endif
}
/****************************************************************************************/
eastl::span<std::byte> WritableMemoryMappedFile::GetData() const
{
return eastl::span<std::byte> {m_data, m_size};
}
/****************************************************************************************/
void WritableMemoryMappedFile::Prefetch(const std::size_t p_offset, const std::size_t p_size) const
{
#if defined BIGFOOT_WINDOWS
WIN32_MEMORY_RANGE_ENTRY range {.VirtualAddress = m_data + p_offset, .NumberOfBytes = p_size};
[[maybe_unused]]
const BOOL prefetched = PrefetchVirtualMemory(GetCurrentProcess(), 1, &range, 0);
#elif defined BIGFOOT_LINUX
[[maybe_unused]]
const int adviseResult = madvise(m_data + p_offset, p_size, MADV_WILLNEED);
#else
CRITICAL_ASSERT(SystemAssertHandler, false, "MemoryMappedFileBase is not implemented on this platform");
#endif
}
} // namespace Bigfoot
@@ -7,8 +7,10 @@
#ifndef BIGFOOT_SYSTEM_FILE_HPP
#define BIGFOOT_SYSTEM_FILE_HPP
#include <EASTL/span.h>
#include <EASTL/string.h>
#include <EASTL/string_view.h>
#include <EASTL/vector.h>
#include <filesystem>
@@ -72,6 +74,38 @@ class File
[[nodiscard]]
File ToAbsolute() const;
/**
* Get the size of the file
*
* \return The size in bytes
*/
[[nodiscard]]
std::size_t GetSize() const;
/**
* Read bytes from the file
*
* \param p_offset The offset in bytes
* \param p_size The number of bytes to read
* \return The bytes read
*/
[[nodiscard]]
eastl::vector<std::byte> Read(std::size_t p_offset, std::size_t p_size) const;
/**
* Write bytes to the file at a given offset, creating the file if needed. Content before
* p_offset, or from past p_offset + p_data.size(), is left untouched.
*
* \param p_data The bytes to write
* \param p_offset The offset, in bytes, to start writing at
*/
void Write(eastl::span<const std::byte> p_data, std::size_t p_offset) const;
/**
* Delete the file
*/
void Delete() const;
private:
/**
* Constructor
@@ -0,0 +1,150 @@
/*********************************************************************
* \file MemoryMappedFile.hpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#ifndef BIGFOOT_SYSTEM_MEMORYMAPPEDFILE_HPP
#define BIGFOOT_SYSTEM_MEMORYMAPPEDFILE_HPP
#include <System/File/File.hpp>
#include <EASTL/span.h>
#include <cstddef>
#include <cstdint>
namespace Bigfoot
{
class MemoryMappedFile
{
public:
/**
* Constructor
* Opens and maps the whole file
*
* \param p_file The file to map
*/
explicit MemoryMappedFile(const File& p_file);
MemoryMappedFile(const MemoryMappedFile& p_file) = delete;
MemoryMappedFile(MemoryMappedFile&& p_file) = delete;
/**
* Destructor
*
*/
~MemoryMappedFile();
/**
* Get the mapped content of the file
*
* \return The mapped bytes
*/
[[nodiscard]]
eastl::span<const std::byte> GetData() const;
MemoryMappedFile& operator=(const MemoryMappedFile& p_file) = delete;
MemoryMappedFile& operator=(MemoryMappedFile&& p_file) = delete;
private:
#if defined BIGFOOT_WINDOWS
/**
* Handle to the file
*/
void* m_fileHandle = nullptr;
/**
* Handle to the file mapping
*/
void* m_mappingHandle = nullptr;
#elif defined BIGFOOT_LINUX
/**
* Handle to the file
*/
int m_fileDescriptor = -1;
#endif
/**
* The mapped size
*/
std::size_t m_size = 0;
/**
* The mapped data
*/
std::byte* m_data = nullptr;
};
/****************************************************************************************/
class WritableMemoryMappedFile
{
public:
/**
* Constructor
* Creates and maps the file
*
* \param p_file The file to create and map
* \param p_size The size to map
*/
WritableMemoryMappedFile(const File& p_file, std::size_t p_size);
WritableMemoryMappedFile(const WritableMemoryMappedFile& p_file) = delete;
WritableMemoryMappedFile(WritableMemoryMappedFile&& p_file) = delete;
/**
* Destructor
*
*/
~WritableMemoryMappedFile();
/**
* Get the mapped content of the file
*
* \return The mapped bytes
*/
[[nodiscard]]
eastl::span<std::byte> GetData() const;
/**
* Hint the OS to prefetch a range of data, so writes into that range do not each pay a page fault
*
* \param p_offset The offset, in bytes, to start prefetching from
* \param p_size The number of bytes to prefetch
*/
void Prefetch(std::size_t p_offset, std::size_t p_size) const;
WritableMemoryMappedFile& operator=(const WritableMemoryMappedFile& p_file) = delete;
WritableMemoryMappedFile& operator=(WritableMemoryMappedFile&& p_file) = delete;
private:
#if defined BIGFOOT_WINDOWS
/**
* Handle to the file
*/
void* m_fileHandle = nullptr;
/**
* Handle to the file mapping
*/
void* m_mappingHandle = nullptr;
#elif defined BIGFOOT_LINUX
/**
* Handle to the file
*/
int m_fileDescriptor = -1;
#endif
/**
* The mapped size
*/
std::size_t m_size = 0;
/**
* The mapped data
*/
std::byte* m_data = nullptr;
};
} // namespace Bigfoot
#endif
+1 -1
View File
@@ -6,7 +6,7 @@
*********************************************************************/
#include <Engine/BigFile/BigFile.hpp>
#include <System/File.hpp>
#include <System/File/File.hpp>
#include <EngineTests/BigFileInfo_generated.hpp>
@@ -9,6 +9,8 @@
#include <EASTL/string_view.h>
#if defined BIGFOOT_TOOLMODE
namespace Bigfoot
{
/*
@@ -17,3 +19,4 @@ namespace Bigfoot
constexpr eastl::string_view BIGFILE_ENGINETESTS_LOCATION {"./EngineTests-bigfile.db"};
} // namespace Bigfoot
#endif
#endif
-80
View File
@@ -1,80 +0,0 @@
/*********************************************************************
* \file File.cpp
*
* \author Romain BOULLARD
* \date December 2025
*********************************************************************/
#include <System/File.hpp>
#include <gtest/gtest.h>
namespace Bigfoot
{
class FileFixture: public ::testing::Test
{
public:
File m_file {eastl::string_view {"Fixture/file"}};
File m_nonExistent {eastl::string_view {"Fixture/bigfoot"}};
};
/****************************************************************************************/
TEST_F(FileFixture, IsRelative_ShouldReturnTrueOnRelativeFile)
{
EXPECT_TRUE(m_file.IsRelative());
}
/****************************************************************************************/
TEST_F(FileFixture, IsRelative_ShouldReturnFalseOnAbsoluteFile)
{
EXPECT_FALSE(m_file.ToAbsolute().IsRelative());
}
/****************************************************************************************/
TEST_F(FileFixture, IsAbsolute_ShouldReturnTrueOnAbsoluteFile)
{
EXPECT_TRUE(m_file.ToAbsolute().IsAbsolute());
}
TEST_F(FileFixture, IsAbsolute_ShouldReturnFalseOnRelativeFile)
{
EXPECT_FALSE(m_file.IsAbsolute());
}
/****************************************************************************************/
TEST_F(FileFixture, Exists_ShouldReturnTrueOnExistingFile)
{
EXPECT_TRUE(m_file.Exists());
}
/****************************************************************************************/
TEST_F(FileFixture, Exists_ShouldReturnFalseOnNonExistingFile)
{
EXPECT_FALSE(m_nonExistent.Exists());
}
/****************************************************************************************/
TEST_F(FileFixture, GetPath_ShouldReturnThePath)
{
EXPECT_STREQ(m_file.GetPath().data(), "Fixture/file");
}
/****************************************************************************************/
TEST_F(FileFixture, ToAbsolute_ShouldReturnTheAbsolutePath)
{
EXPECT_STREQ(std::filesystem::absolute("Fixture/file").string().c_str(), m_file.ToAbsolute().GetPath().data());
}
/****************************************************************************************/
TEST_F(FileFixture, ToRelative_ShouldReturnTheRelativePath)
{
EXPECT_STREQ(std::filesystem::relative("Fixture/file").string().c_str(), m_file.ToRelative().GetPath().data());
}
} // namespace Bigfoot
+194
View File
@@ -0,0 +1,194 @@
/*********************************************************************
* \file File.cpp
*
* \author Romain BOULLARD
* \date December 2025
*********************************************************************/
#include <System/File/File.hpp>
#include <gtest/gtest.h>
#include <array>
#include <cstring>
#include <type_traits>
namespace Bigfoot
{
class FileFixture: public ::testing::Test
{
public:
File m_file {eastl::string_view {"Fixture/file"}};
File m_nonExistent {eastl::string_view {"Fixture/bigfoot"}};
File m_writeScratchFile {eastl::string_view {"Fixture/scratch"}};
protected:
void SetUp() override
{
m_writeScratchFile.Delete();
}
};
/****************************************************************************************/
TEST_F(FileFixture, IsRelative_ShouldReturnTrueOnRelativeFile)
{
EXPECT_TRUE(m_file.IsRelative());
}
/****************************************************************************************/
TEST_F(FileFixture, IsRelative_ShouldReturnFalseOnAbsoluteFile)
{
EXPECT_FALSE(m_file.ToAbsolute().IsRelative());
}
/****************************************************************************************/
TEST_F(FileFixture, IsAbsolute_ShouldReturnTrueOnAbsoluteFile)
{
EXPECT_TRUE(m_file.ToAbsolute().IsAbsolute());
}
/****************************************************************************************/
TEST_F(FileFixture, IsAbsolute_ShouldReturnFalseOnRelativeFile)
{
EXPECT_FALSE(m_file.IsAbsolute());
}
/****************************************************************************************/
TEST_F(FileFixture, Exists_ShouldReturnTrueOnExistingFile)
{
EXPECT_TRUE(m_file.Exists());
}
/****************************************************************************************/
TEST_F(FileFixture, Exists_ShouldReturnFalseOnNonExistingFile)
{
EXPECT_FALSE(m_nonExistent.Exists());
}
/****************************************************************************************/
TEST_F(FileFixture, GetPath_ShouldReturnThePath)
{
EXPECT_STREQ(m_file.GetPath().data(), "Fixture/file");
}
/****************************************************************************************/
TEST_F(FileFixture, ToAbsolute_ShouldReturnTheAbsolutePath)
{
EXPECT_STREQ(std::filesystem::absolute("Fixture/file").string().c_str(), m_file.ToAbsolute().GetPath().data());
}
/****************************************************************************************/
TEST_F(FileFixture, ToRelative_ShouldReturnTheRelativePath)
{
EXPECT_STREQ(std::filesystem::relative("Fixture/file").string().c_str(), m_file.ToRelative().GetPath().data());
}
/****************************************************************************************/
TEST_F(FileFixture, GetSize_ShouldReturnZeroForAnEmptyFile)
{
EXPECT_EQ(m_file.GetSize(), 0);
}
/****************************************************************************************/
TEST_F(FileFixture, GetSize_ShouldReturnTheFileSize)
{
constexpr eastl::string_view content = "Hello, Sasquatch!";
m_writeScratchFile.Write({std::bit_cast<const std::byte*>(content.data()), content.size()}, 0);
EXPECT_EQ(m_writeScratchFile.GetSize(), content.size());
}
/****************************************************************************************/
TEST_F(FileFixture, Read_ShouldReturnTheRequestedBytesAtTheGivenOffset)
{
constexpr eastl::string_view content = "Hello, Sasquatch!";
m_writeScratchFile.Write({std::bit_cast<const std::byte*>(content.data()), content.size()}, 0);
const eastl::vector<std::byte> data = m_writeScratchFile.Read(7, 10);
ASSERT_EQ(data.size(), 10);
EXPECT_EQ(std::memcmp(data.data(), "Sasquatch!", data.size()), 0);
}
/****************************************************************************************/
TEST_F(FileFixture, Write_ShouldCreateTheFileWithTheGivenContent)
{
constexpr eastl::string_view content = "Hello, Sasquatch!";
m_writeScratchFile.Write({std::bit_cast<const std::byte*>(content.data()), content.size()}, 0);
const eastl::vector<std::byte> data = m_writeScratchFile.Read(0, m_writeScratchFile.GetSize());
ASSERT_EQ(data.size(), content.size());
EXPECT_EQ(std::memcmp(data.data(), content.data(), data.size()), 0);
}
/****************************************************************************************/
TEST_F(FileFixture, Write_ShouldNotTouchContentOutsideTheWrittenRange)
{
constexpr eastl::string_view initial = "Hello, Sasquatch!";
m_writeScratchFile.Write({std::bit_cast<const std::byte*>(initial.data()), initial.size()}, 0);
constexpr eastl::string_view patch = "BIGFOOT";
m_writeScratchFile.Write({std::bit_cast<const std::byte*>(patch.data()), patch.size()}, 7);
const eastl::vector<std::byte> data = m_writeScratchFile.Read(0, m_writeScratchFile.GetSize());
ASSERT_EQ(data.size(), initial.size());
EXPECT_EQ(std::memcmp(data.data(), "Hello, ", 7), 0);
EXPECT_EQ(std::memcmp(data.data() + 7, "BIGFOOT", 7), 0);
EXPECT_EQ(std::memcmp(data.data() + 14, "ch!", 3), 0);
}
/****************************************************************************************/
TEST_F(FileFixture, Write_ShouldRoundTripArbitraryData)
{
struct Payload
{
int m_intValue;
double m_doubleValue;
std::array<char, 4> m_tag;
bool operator==(const Payload&) const = default;
};
constexpr Payload payload {.m_intValue = 42, .m_doubleValue = 3.14, .m_tag = {'B', 'I', 'G', 'F'}};
m_writeScratchFile.Write({std::bit_cast<const std::byte*>(&payload), sizeof(payload)}, 0);
const eastl::vector<std::byte> data = m_writeScratchFile.Read(0, m_writeScratchFile.GetSize());
ASSERT_EQ(data.size(), sizeof(Payload));
EXPECT_EQ(*std::bit_cast<const Payload*>(data.data()), payload);
}
/****************************************************************************************/
TEST_F(FileFixture, Delete_ShouldRemoveTheFile)
{
constexpr std::byte payload {1};
m_writeScratchFile.Write({&payload, 1}, 0);
ASSERT_TRUE(m_writeScratchFile.Exists());
m_writeScratchFile.Delete();
EXPECT_FALSE(m_writeScratchFile.Exists());
}
/****************************************************************************************/
TEST_F(FileFixture, Delete_ShouldDoNothingWhenTheFileDoesNotExist)
{
ASSERT_FALSE(m_writeScratchFile.Exists());
m_writeScratchFile.Delete();
EXPECT_FALSE(m_writeScratchFile.Exists());
}
} // namespace Bigfoot
@@ -0,0 +1,92 @@
/*********************************************************************
* \file MemoryMappedFile.cpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#include <System/File/MemoryMappedFile.hpp>
#include <EASTL/optional.h>
#include <gtest/gtest.h>
#include <array>
#include <cstring>
namespace Bigfoot
{
class MemoryMappedFileFixture: public ::testing::Test
{
protected:
MemoryMappedFile m_file {File {eastl::string_view {"Fixture/mappedFile"}}};
MemoryMappedFile m_emptyFile {File {eastl::string_view {"Fixture/file"}}};
};
/****************************************************************************************/
TEST_F(MemoryMappedFileFixture, GetData_ShouldReturnTheFileContent)
{
const eastl::span<const std::byte> data = m_file.GetData();
ASSERT_EQ(data.size(), std::strlen("Hello, Sasquatch!"));
EXPECT_EQ(std::memcmp(data.data(), "Hello, Sasquatch!", data.size()), 0);
}
/****************************************************************************************/
TEST_F(MemoryMappedFileFixture, GetData_ShouldReturnAnEmptySpanForAnEmptyFile)
{
EXPECT_TRUE(m_emptyFile.GetData().empty());
}
/****************************************************************************************/
class WritableMemoryMappedFileFixture: public ::testing::Test
{
protected:
static constexpr eastl::string_view LOCATION = "Fixture/WritableMemoryMappedFileTests-scratch";
void SetUp() override
{
File file {LOCATION};
file.Delete();
}
};
/****************************************************************************************/
TEST_F(WritableMemoryMappedFileFixture, GetData_ShouldReturnASpanOfTheRequestedSize)
{
WritableMemoryMappedFile file {File {LOCATION}, 17};
EXPECT_EQ(file.GetData().size(), 17);
}
/****************************************************************************************/
TEST_F(WritableMemoryMappedFileFixture, Write_ShouldWriteToTheFile)
{
{
WritableMemoryMappedFile file {File {LOCATION}, std::strlen("Hello, Sasquatch!")};
std::memcpy(file.GetData().data(), "Hello, Sasquatch!", file.GetData().size());
}
const MemoryMappedFile readBack {File {LOCATION}};
ASSERT_EQ(readBack.GetData().size(), std::strlen("Hello, Sasquatch!"));
EXPECT_EQ(std::memcmp(readBack.GetData().data(), "Hello, Sasquatch!", readBack.GetData().size()), 0);
}
/****************************************************************************************/
TEST_F(WritableMemoryMappedFileFixture, Constructor_ShouldNotTruncateAnyExistingContent)
{
{
WritableMemoryMappedFile file {File {LOCATION}, 100};
std::memset(file.GetData().data(), 0xAB, file.GetData().size());
}
const WritableMemoryMappedFile file {File {LOCATION}, 4};
constexpr std::array<std::byte, 4> reference {std::byte {0xAB},
std::byte {0xAB},
std::byte {0xAB},
std::byte {0xAB}};
EXPECT_EQ(std::memcmp(file.GetData().data(), reference.data(), reference.size()), 0);
}
} // namespace Bigfoot
+1
View File
@@ -0,0 +1 @@
Hello, Sasquatch!
@@ -0,0 +1,22 @@
// AUTO-GENERATED DO NOT TOUCH
/*********************************************************************
* \file BigFileInfo.generated.hpp
*
*********************************************************************/
#ifndef BIGFOOT_SASQUATCHBAKERTESTS_BIGFILEINFO_GENERATED_HPP
#define BIGFOOT_SASQUATCHBAKERTESTS_BIGFILEINFO_GENERATED_HPP
#include <EASTL/string_view.h>
#if defined BIGFOOT_TOOLMODE
namespace Bigfoot
{
/*
* BigFile location
*/
constexpr eastl::string_view BIGFILE_SASQUATCHBAKERTESTS_LOCATION {"./SasquatchBakerTests-bigfile.db"};
} // namespace Bigfoot
#endif
#endif