diff --git a/.clang-format b/.clang-format index e93c306..d96fdb2 100644 --- a/.clang-format +++ b/.clang-format @@ -51,7 +51,7 @@ CompactNamespaces: false Cpp11BracedListStyle: true EmptyLineBeforeAccessModifier: Always FixNamespaceComments: true -IncludeBlocks: Preserve +IncludeBlocks: Regroup IndentCaseBlocks: true IndentCaseLabels: false IndentPPDirectives: None @@ -119,4 +119,24 @@ SpaceAroundPointerQualifiers: Default SpaceBeforeCpp11BracedList: true SpaceInEmptyBlock: true PenaltyBreakAssignment: 200 -KeepEmptyLinesAtTheStartOfBlocks: false \ No newline at end of file +KeepEmptyLinesAtTheStartOfBlocks: false +IncludeCategories: + - Regex: '^' + Priority: 7 + - Regex: '^<[a-zA-Z0-9_/]+\.hpp>' + Priority: 7 + - Regex: '^<[a-zA-Z0-9_/]+>' + Priority: 8 +MainIncludeChar: AngleBracket \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 46a94d4..b50d3c9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,4 +1,4 @@ { "name": "Bigfoot", - "image": "git.romainboullard.com/bigfootdev/linuxbigfootbuilder:main" + "image": "git.romainboullard.com/bigfootdev/linuxcppbuilder:development" } diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 8c52204..a78a6fb 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -6,20 +6,19 @@ on: - '**' workflow_dispatch: -env: - CCACHE_BASEDIR: ${{ github.workspace }} - jobs: build-and-test: runs-on: ubuntu-latest timeout-minutes: 120 container: - image: git.romainboullard.com/bigfootdev/linuxbigfootbuilder:main + image: git.romainboullard.com/bigfootdev/linuxcppbuilder:development + strategy: matrix: build_type: ["Debug", "RelWithDebInfo", "Release"] unity_build: ["ON", "OFF"] - name: "Build & Test ${{ matrix.build_type }} (Unity Build: ${{ matrix.unity_build }})" + conan_profile: ["./ConanProfiles/clang", "./ConanProfiles/clang_asan"] + name: "Build & Test ${{ matrix.build_type }} with ${{ matrix.conan_profile }} (Unity Build: ${{ matrix.unity_build }})" steps: - name: Install Node.js run: apt-get update && apt-get install -y nodejs @@ -29,22 +28,20 @@ jobs: with: submodules: recursive - - name: Show ccache stats before - run: ccache --zero-stats - - name: Build run: | - conan install . --deployer=full_deploy --deployer-folder=build --remote=bigfootpackages -pr:h=clang -pr:b=clang --build=missing -s build_type=${{ matrix.build_type }} -o bigfoot/*:build_tests=True -o bigfoot/*:tracy=False -o bigfoot/*:build_tools=True -o bigfoot/*:vulkan=True -o bigfoot/*:build_benchmarks=True + conan install . --remote=bigfootpackages -pr:h=${{ matrix.conan_profile }} -pr:b=./ConanProfiles/Tools/clang --build=* -s build_type=${{ matrix.build_type }} -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=False -o bigfoot/*:vulkan=True + . ./build/${{ matrix.build_type }}/generators/conanbuild.sh cmake -S . -B ./build/${{ matrix.build_type }} --toolchain ./build/${{ matrix.build_type }}/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_UNITY_BUILD=${{ matrix.unity_build }} -G "Ninja" cmake --build build/${{ matrix.build_type }} --parallel $(nproc) - - - name: Show ccache stats after - run: ccache --show-stats + . ./build/${{ matrix.build_type }}/generators/deactivate_conanbuild.sh - name: Unit Tests run: | cd ./build/${{ matrix.build_type }} + . ../../build/${{ matrix.build_type }}/generators/conanbuild.sh xvfb-run ctest . --output-on-failure + . ../../build/${{ matrix.build_type }}/generators/deactivate_conanbuild.sh clang-format: runs-on: ubuntu-latest diff --git a/.gitea/workflows/sonarqube.yml b/.gitea/workflows/sonarqube.yml index 6e8c798..50c20ae 100644 --- a/.gitea/workflows/sonarqube.yml +++ b/.gitea/workflows/sonarqube.yml @@ -11,7 +11,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 120 container: - image: git.romainboullard.com/bigfootdev/linuxbigfootbuilder:main + image: git.romainboullard.com/bigfootdev/linuxcppbuilder:development + name: "Sonarqube" steps: - name: Install Node.js @@ -23,11 +24,13 @@ jobs: fetch-depth: 0 submodules: recursive - - name: Generate + - name: Build run: | - conan install . --deployer=full_deploy --deployer-folder=build --remote=bigfootpackages -pr:h=clang_coverage -pr:b=clang_coverage --build=missing -s build_type=Debug -o bigfoot/*:build_tests=True -o bigfoot/*:tracy=False -o bigfoot/*:build_tools=True -o bigfoot/*:vulkan=True -o bigfoot/*:build_benchmarks=True + conan install . --remote=bigfootpackages -pr:h=./ConanProfiles/clang_coverage -pr:b=./ConanProfiles/Tools/clang --build=* -s build_type=Debug -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=False -o bigfoot/*:build_tools=True -o bigfoot/*:vulkan=True + . ./build/Debug/generators/conanbuild.sh cmake -S . -B ./build/Debug --toolchain ./build/Debug/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -G "Ninja" cmake --build build/Debug --parallel $(nproc) + . ./build/Debug/generators/deactivate_conanbuild.sh - name: Clang-Tidy run: run-clang-tidy -p ./build/Debug/ >> tidy_result.txt diff --git a/.gitignore b/.gitignore index 129a851..ac60dd1 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,4 @@ graph_info.json test_package/Vendor -graphviz \ No newline at end of file +graphviz* \ No newline at end of file diff --git a/Bigfoot/Benchmarks/CMakeLists.txt b/Bigfoot/Benchmarks/CMakeLists.txt new file mode 100644 index 0000000..992910a --- /dev/null +++ b/Bigfoot/Benchmarks/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils) \ No newline at end of file diff --git a/Bigfoot/Benchmarks/Utils/CMakeLists.txt b/Bigfoot/Benchmarks/Utils/CMakeLists.txt new file mode 100644 index 0000000..53a5d66 --- /dev/null +++ b/Bigfoot/Benchmarks/Utils/CMakeLists.txt @@ -0,0 +1,5 @@ +get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +project(${PackageName}Benchmarks) + +bigfoot_create_package_benchmarks( + "") \ No newline at end of file diff --git a/Bigfoot/Benchmarks/Utils/Container/SlotMap.cpp b/Bigfoot/Benchmarks/Utils/Container/SlotMap.cpp new file mode 100644 index 0000000..6b11307 --- /dev/null +++ b/Bigfoot/Benchmarks/Utils/Container/SlotMap.cpp @@ -0,0 +1,254 @@ +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Bigfoot +{ +struct MyComplexStruct +{ + std::uint32_t m_actualValueForBench = 0; // field summed by the Iterate benchmark + + float m_position[3] = {0.0f, 0.0f, 0.0f}; + float m_rotation[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + float m_scale[3] = {1.0f, 1.0f, 1.0f}; + + std::uint64_t m_entityId = 0; + std::uint32_t m_parentSlot = 0; + std::uint32_t m_flags = 0; + + MyComplexStruct() = default; + + explicit MyComplexStruct(const std::uint32_t p_value): + m_actualValueForBench(p_value), + m_entityId(p_value) + { + } +}; + +static_assert(sizeof(MyComplexStruct) == 64, "Payload should be exactly one cache line."); +static_assert(std::is_trivially_copyable_v, + "Container moves should be a plain memcpy, not a heap-touching move."); + +template +class SlotMapAdaptor +{ + public: + using Key = SlotMapKey; + + SlotMapKey Add(MyComplexStruct&& p_value) + { + return m_container.Insert(std::move(p_value)); + } + + const MyComplexStruct* Find(const SlotMapKey p_key) const + { + return m_container.Get(p_key); + } + + void Remove(const SlotMapKey p_key) + { + m_container.Remove(p_key); + } + + void Clear() + { + m_container.Reset(); + } + + template + void ForEachValue(FUNC&& p_func) const + { + for (const MyComplexStruct& value: m_container) + { + p_func(value); + } + } + + private: + SLOTMAP m_container; +}; + +template +class HashMapHarnessAdaptor +{ + public: + using Key = typename MAP::key_type; + + Key Add(MyComplexStruct&& p_value) + { + const Key key = m_nextKey++; + m_container.emplace(key, std::move(p_value)); + return key; + } + + const MyComplexStruct* Find(const Key p_key) const + { + const auto it = m_container.find(p_key); + return it != m_container.end() ? &it->second : nullptr; + } + + void Remove(const Key p_key) + { + m_container.erase(p_key); + } + + void Clear() + { + m_container.clear(); + m_nextKey = 0; + } + + template + void ForEachValue(FUNC&& p_func) const + { + for (const auto& keyValue: m_container) + { + p_func(keyValue.second); + } + } + + private: + MAP m_container; + Key m_nextKey = 0; +}; + +template +void Insert(benchmark::State& state) +{ + const auto count = static_cast(state.range(0)); + + for (auto _: state) + { + ADAPTOR adaptor; + for (std::uint32_t i = 0; i < count; ++i) + { + benchmark::DoNotOptimize(adaptor.Add(MyComplexStruct {i})); + } + benchmark::DoNotOptimize(adaptor); + benchmark::ClobberMemory(); + } + + state.SetItemsProcessed(state.iterations() * count); +} + +template +void Remove(benchmark::State& state) +{ + const auto count = static_cast(state.range(0)); + + ADAPTOR adaptor; + std::vector keys; + keys.reserve(count); + std::mt19937 rng(0x5EEDU); + + for (auto _: state) + { + state.PauseTiming(); + adaptor.Clear(); + keys.clear(); + for (std::uint32_t i = 0; i < count; ++i) + { + keys.push_back(adaptor.Add(MyComplexStruct {i})); + } + std::shuffle(keys.begin(), keys.end(), rng); + state.ResumeTiming(); + + for (const typename ADAPTOR::Key key: keys) + { + adaptor.Remove(key); + } + benchmark::DoNotOptimize(adaptor); + benchmark::ClobberMemory(); + } + + state.SetItemsProcessed(state.iterations() * count); +} + +template +void Get(benchmark::State& state) +{ + const auto count = static_cast(state.range(0)); + + ADAPTOR adaptor; + std::vector keys; + keys.reserve(count); + for (std::uint32_t i = 0; i < count; ++i) + { + keys.push_back(adaptor.Add(MyComplexStruct {i})); + } + std::mt19937 rng(0x5EEDU); + std::shuffle(keys.begin(), keys.end(), rng); + + for (auto _: state) + { + std::uint64_t sum = 0; + for (const typename ADAPTOR::Key key: keys) + { + if (const MyComplexStruct* const value = adaptor.Find(key)) + { + sum += value->m_actualValueForBench; + } + } + benchmark::DoNotOptimize(sum); + } + + state.SetItemsProcessed(state.iterations() * count); +} + +template +void Iterate(benchmark::State& state) +{ + const auto count = static_cast(state.range(0)); + + ADAPTOR adaptor; + for (std::uint32_t i = 0; i < count; ++i) + { + adaptor.Add(MyComplexStruct {i}); + } + + for (auto _: state) + { + std::uint64_t sum = 0; + adaptor.ForEachValue( + [&sum](const MyComplexStruct& value) + { + sum += value.m_actualValueForBench; + }); + benchmark::DoNotOptimize(sum); + } + + state.SetItemsProcessed(state.iterations() * count); +} + +#define BIGFOOT_REGISTER_BENCHMARKS(ADAPTOR, NAME) \ + BENCHMARK_TEMPLATE(Insert, ADAPTOR)->Name(NAME "/Insert")->Arg(512)->Arg(8192)->Arg(262'144)->Arg(4'194'304); \ + BENCHMARK_TEMPLATE(Remove, ADAPTOR)->Name(NAME "/Remove")->Arg(512)->Arg(8192)->Arg(262'144)->Arg(4'194'304); \ + BENCHMARK_TEMPLATE(Get, ADAPTOR)->Name(NAME "/Get")->Arg(512)->Arg(8192)->Arg(262'144)->Arg(4'194'304); \ + BENCHMARK_TEMPLATE(Iterate, ADAPTOR)->Name(NAME "/Iterate")->Arg(512)->Arg(8192)->Arg(262'144)->Arg(4'194'304); + +using DenseSlotMapHarness = SlotMapAdaptor>; +using StableSlotMapHarness = SlotMapAdaptor>; +using UnorderedDenseMapHarness = HashMapHarnessAdaptor>; +using UnorderedDenseSegementedMapHarness = + HashMapHarnessAdaptor>; +using UnorderedMapHarness = HashMapHarnessAdaptor>; +using MapHarness = HashMapHarnessAdaptor>; + +BIGFOOT_REGISTER_BENCHMARKS(DenseSlotMapHarness, "Bigfoot::DenseSlotMap"); +BIGFOOT_REGISTER_BENCHMARKS(StableSlotMapHarness, "Bigfoot::StableSlotMap"); +BIGFOOT_REGISTER_BENCHMARKS(UnorderedDenseMapHarness, "ankerl::unordered_dense::map"); +BIGFOOT_REGISTER_BENCHMARKS(UnorderedDenseSegementedMapHarness, "ankerl::unordered_dense::segmented_map"); +BIGFOOT_REGISTER_BENCHMARKS(UnorderedMapHarness, "std::unordered_map"); +BIGFOOT_REGISTER_BENCHMARKS(MapHarness, "std::map"); + +#undef BIGFOOT_REGISTER_BENCHMARKS +#undef BIGFOOT_CACHE_TIER_ARGS +} // namespace Bigfoot diff --git a/Bigfoot/Sources/Engine/Asset/AssetTypeID.cpp b/Bigfoot/Sources/Engine/Asset/AssetTypeID.cpp new file mode 100644 index 0000000..9cf79bd --- /dev/null +++ b/Bigfoot/Sources/Engine/Asset/AssetTypeID.cpp @@ -0,0 +1,24 @@ +/********************************************************************* + * \file AssetTypeID.cpp + * + * \author Romain BOULLARD + * \date May 2026 + *********************************************************************/ +#include + +#include + +namespace flatbuffers +{ +Flat::Bigfoot::AssetTypeID Pack(const Bigfoot::AssetTypeID& p_assetTypeID) +{ + return Flat::Bigfoot::AssetTypeID {p_assetTypeID}; +} + +/****************************************************************************************/ + +Bigfoot::AssetTypeID UnPack(const Flat::Bigfoot::AssetTypeID& p_flatAssetTypeID) +{ + return Bigfoot::AssetTypeID {p_flatAssetTypeID.value()}; +} +} // namespace flatbuffers diff --git a/Bigfoot/Sources/Engine/BigFile/BigFile.cpp b/Bigfoot/Sources/Engine/BigFile/BigFile.cpp new file mode 100644 index 0000000..e2f8bc4 --- /dev/null +++ b/Bigfoot/Sources/Engine/BigFile/BigFile.cpp @@ -0,0 +1,299 @@ +/********************************************************************* + * \file BigFile.cpp + * + * \author Romain BOULLARD + * \date October 2025 + *********************************************************************/ +#include + +#include + +namespace Bigfoot +{ +BigFile::BigFile(const File& p_file) +{ + [[maybe_unused]] + const int result = sqlite3_open_v2(p_file.ToAbsolute().GetPath().data(), &m_db, SQLITE_OPEN_READWRITE, nullptr); + CRITICAL_ASSERT(EngineAssertHandler, + result == SQLITE_OK, + "Failed to open BigFile {} DB: {}", + p_file.ToAbsolute().GetPath(), + sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::BeginTransaction() +{ + [[maybe_unused]] + const int result = sqlite3_exec(m_db, "BEGIN TRANSACTION;", nullptr, nullptr, nullptr); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to begin transaction: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::CommitTransaction() +{ + [[maybe_unused]] + const int result = sqlite3_exec(m_db, "COMMIT TRANSACTION;", nullptr, nullptr, nullptr); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to commit: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::RollbackTransaction() +{ + [[maybe_unused]] + const int result = sqlite3_exec(m_db, "ROLLBACK TRANSACTION;", nullptr, nullptr, nullptr); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to rollback: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +BigFile::~BigFile() +{ + [[maybe_unused]] + const int result = sqlite3_close_v2(m_db); + CRITICAL_ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to close BigFile DB: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +BigFile::Request::Request(const BigFile& p_bigFile, const eastl::string_view p_request): + m_db(p_bigFile.m_db) +{ + [[maybe_unused]] + const int result = sqlite3_prepare_v2(m_db, + p_request.data(), + static_cast(p_request.size()), + &m_statement, + nullptr); + CRITICAL_ASSERT(EngineAssertHandler, + result == SQLITE_OK, + "Failed to create statement from BigFile DB: {}", + sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::Request::Bind(const std::uint32_t p_index, const std::int32_t p_value) +{ + ASSERT(EngineAssertHandler, + (p_index >= 1) && (p_index <= static_cast(sqlite3_bind_parameter_count(m_statement))), + "Invalid index for statement"); + + [[maybe_unused]] + const int result = sqlite3_bind_int(m_statement, p_index, p_value); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint32_t p_value) +{ + ASSERT(EngineAssertHandler, + (p_index >= 1) && (p_index <= static_cast(sqlite3_bind_parameter_count(m_statement))), + "Invalid index for statement"); + + [[maybe_unused]] + const int result = sqlite3_bind_int(m_statement, p_index, p_value); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::Request::Bind(const std::uint32_t p_index, const std::int64_t p_value) +{ + ASSERT(EngineAssertHandler, + (p_index >= 1) && (p_index <= static_cast(sqlite3_bind_parameter_count(m_statement))), + "Invalid index for statement"); + + [[maybe_unused]] + const int result = sqlite3_bind_int64(m_statement, p_index, p_value); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint64_t p_value) +{ + ASSERT(EngineAssertHandler, + (p_index >= 1) && (p_index <= static_cast(sqlite3_bind_parameter_count(m_statement))), + "Invalid index for statement"); + + [[maybe_unused]] + const int result = sqlite3_bind_int64(m_statement, p_index, std::bit_cast(p_value)); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::Request::Bind(const std::uint32_t p_index, const float p_value) +{ + ASSERT(EngineAssertHandler, + (p_index >= 1) && (p_index <= static_cast(sqlite3_bind_parameter_count(m_statement))), + "Invalid index for statement"); + + [[maybe_unused]] + const int result = sqlite3_bind_double(m_statement, p_index, p_value); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::Request::Bind(const std::uint32_t p_index, const double p_value) +{ + ASSERT(EngineAssertHandler, + (p_index >= 1) && (p_index <= static_cast(sqlite3_bind_parameter_count(m_statement))), + "Invalid index for statement"); + + [[maybe_unused]] + const int result = sqlite3_bind_double(m_statement, p_index, p_value); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::Request::Bind(const std::uint32_t p_index, const eastl::string_view p_value, const CopyValue p_copy) +{ + ASSERT(EngineAssertHandler, + (p_index >= 1) && (p_index <= static_cast(sqlite3_bind_parameter_count(m_statement))), + "Invalid index for statement"); + + [[maybe_unused]] + const int result = sqlite3_bind_text(m_statement, + p_index, + p_value.data(), + static_cast(p_value.size()), + p_copy ? SQLITE_TRANSIENT : SQLITE_STATIC); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +void BigFile::Request::Bind(const std::uint32_t p_index, + const eastl::span p_value, + const CopyValue p_copy) +{ + ASSERT(EngineAssertHandler, + (p_index >= 1) && (p_index <= static_cast(sqlite3_bind_parameter_count(m_statement))), + "Invalid index for statement"); + + [[maybe_unused]] + const int result = sqlite3_bind_blob(m_statement, + p_index, + p_value.data(), + static_cast(p_value.size()), + p_copy ? SQLITE_TRANSIENT : SQLITE_STATIC); + ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db)); +} + +/****************************************************************************************/ + +bool BigFile::Request::Step() +{ + const int result = sqlite3_step(m_statement); + ASSERT(EngineAssertHandler, + (result == SQLITE_DONE) || (result == SQLITE_ROW), + "Failed to step through the statement: {}", + sqlite3_errmsg(m_db)); + + return result == SQLITE_ROW; +} + +/****************************************************************************************/ + +std::uint32_t BigFile::Request::Execute() +{ + [[maybe_unused]] + const int result = sqlite3_step(m_statement); + ASSERT(EngineAssertHandler, (result == SQLITE_DONE), "Failed to execute the statement: {}", sqlite3_errmsg(m_db)); + + return sqlite3_changes(m_db); +} + +/****************************************************************************************/ + +BigFile::Request::Column::Column(const Request& p_request, const std::uint32_t p_index): + m_statement(p_request.m_statement), + m_index(p_index) +{ +} + +/****************************************************************************************/ + +BigFile::Request::Column::operator std::int32_t() const +{ + return sqlite3_column_int(m_statement, m_index); +} + +/****************************************************************************************/ + +BigFile::Request::Column::operator std::uint32_t() const +{ + return sqlite3_column_int(m_statement, m_index); +} + +/****************************************************************************************/ + +BigFile::Request::Column::operator std::int64_t() const +{ + return sqlite3_column_int64(m_statement, m_index); +} + +/****************************************************************************************/ + +BigFile::Request::Column::operator std::uint64_t() const +{ + return std::bit_cast(sqlite3_column_int64(m_statement, m_index)); +} + +/****************************************************************************************/ + +BigFile::Request::Column::operator float() const +{ + return static_cast(sqlite3_column_double(m_statement, m_index)); +} + +/****************************************************************************************/ + +BigFile::Request::Column::operator double() const +{ + return sqlite3_column_double(m_statement, m_index); +} + +/****************************************************************************************/ + +BigFile::Request::Column::operator eastl::string_view() const +{ + return eastl::string_view {reinterpret_cast(sqlite3_column_text(m_statement, m_index)), + static_cast(sqlite3_column_bytes(m_statement, m_index))}; +} + +/****************************************************************************************/ + +BigFile::Request::Column::operator eastl::span() const +{ + return eastl::span {static_cast(sqlite3_column_blob(m_statement, m_index)), + static_cast(sqlite3_column_bytes(m_statement, m_index))}; +} + +/****************************************************************************************/ + +BigFile::Request::Column BigFile::Request::Get(const std::uint32_t p_index) const +{ + ASSERT(EngineAssertHandler, + p_index < static_cast(sqlite3_column_count(m_statement)), + "Invalid index for column!"); + return {*this, p_index}; +} + +/****************************************************************************************/ + +BigFile::Request::~Request() +{ + [[maybe_unused]] + const int result = sqlite3_finalize(m_statement); + CRITICAL_ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to finalize statement: {}", sqlite3_errmsg(m_db)); +} +} // namespace Bigfoot diff --git a/Bigfoot/Sources/Engine/BigFile/BigFileSchema.sql b/Bigfoot/Sources/Engine/BigFile/BigFileSchema.sql index e307f48..e329324 100644 --- a/Bigfoot/Sources/Engine/BigFile/BigFileSchema.sql +++ b/Bigfoot/Sources/Engine/BigFile/BigFileSchema.sql @@ -1,7 +1,6 @@ PRAGMA journal_mode=WAL; PRAGMA foreign_keys = ON; -DROP TABLE IF EXISTS AssetHeader; CREATE TABLE IF NOT EXISTS AssetHeader ( UUID BLOB NOT NULL UNIQUE, Name TEXT NOT NULL UNIQUE, @@ -22,7 +21,6 @@ BEGIN WHERE UUID = NEW.UUID; END; -DROP TABLE IF EXISTS Asset; CREATE TABLE IF NOT EXISTS Asset ( UUID BLOB NOT NULL UNIQUE, diff --git a/Bigfoot/Sources/Engine/CMakeLists.txt b/Bigfoot/Sources/Engine/CMakeLists.txt index 943596b..32ebc90 100644 --- a/Bigfoot/Sources/Engine/CMakeLists.txt +++ b/Bigfoot/Sources/Engine/CMakeLists.txt @@ -5,8 +5,7 @@ set(PublicDependencies SQLite::SQLite3) set(PrivateDependencies) set(BigfootPublicDependencies - System - Utils) + System) set(BigfootPrivateDependencies) set(BIGFOOT_MAJOR 0) diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset.fbs b/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset.fbs new file mode 100644 index 0000000..7a4e0d3 --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset.fbs @@ -0,0 +1,22 @@ +include "Engine/Asset/AssetTypeID.fbs"; + +include "System/UUID/UUID.fbs"; + +namespace Flat.Bigfoot; + +table AssetHeader +{ + uuid: UUID (required, native_inline, id: 0); + name: string (required, id: 1); + type_id: AssetTypeID (required, native_inline, id: 2); + type_name: string (required, id: 3); + version: uint = 0 (id: 4); +} + +table Asset +{ + header: AssetHeader (required, id: 0); + inner_asset: [ubyte] (required, id: 1); +} + +root_type Asset; \ No newline at end of file diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset.hpp new file mode 100644 index 0000000..c4b945d --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset.hpp @@ -0,0 +1,142 @@ +/********************************************************************* + * \file Asset.hpp + * + * \author Romain BOULLARD + * \date April 2026 + *********************************************************************/ +#ifndef BIGFOOT_ENGINE_ASSET_ASSET_HPP +#define BIGFOOT_ENGINE_ASSET_ASSET_HPP +#include +#include + +#include +#include +#include +#include +#include + +namespace Bigfoot +{ +class AssetBase +{ + public: + virtual ~AssetBase() = default; + + protected: + AssetBase() = default; + + AssetBase(const AssetBase& p_asset) = default; + AssetBase(AssetBase&& p_asset) = default; + + AssetBase& operator=(const AssetBase& p_asset) = default; + AssetBase& operator=(AssetBase&& p_asset) = default; +}; + +template +class Asset: public AssetBase +{ + public: + using FLAT_ASSET = typename ASSET::FLAT; + + Asset() + { + m_header.type_id = GetTypeID(); + m_header.type_name = eastl::string {GetTypeName()}; + } + + explicit Asset(const eastl::span p_flatbuffer): + Asset() + { +#ifdef BIGFOOT_NOT_OPTIMIZED + flatbuffers::Verifier verifier {std::bit_cast(p_flatbuffer.data()), p_flatbuffer.size()}; + const bool assetVerified = ::Flat::Bigfoot::VerifyAssetBuffer(verifier); + CRITICAL_ASSERT(EngineAssertHandler, assetVerified, "Given asset could not be verified!"); + + const ::Flat::Bigfoot::Asset* asset = flatbuffers::GetRoot<::Flat::Bigfoot::Asset>(p_flatbuffer.data()); + + flatbuffers::Verifier innerAssetVerifier {asset->inner_asset()->data(), asset->inner_asset()->size()}; + const bool innerAssetVerified = innerAssetVerifier.VerifyBuffer(); + CRITICAL_ASSERT(EngineAssertHandler, innerAssetVerified, "Given asset could not be verified!"); +#else + const ::Flat::Bigfoot::Asset* asset = flatbuffers::GetRoot<::Flat::Bigfoot::Asset>(p_flatbuffer.data()); +#endif + + asset->header()->UnPackTo(&m_header); + flatbuffers::GetRoot(asset->inner_asset()->data())->UnPackTo(&m_asset, nullptr); + } + + Asset(const Asset& p_asset) = default; + Asset(Asset&& p_asset) = default; + + ~Asset() = default; + + [[nodiscard]] + const ::Flat::Bigfoot::AssetHeaderT& GetHeader() const + { + return m_header; + } + + void SetName(const eastl::string_view p_name) + { + m_header.name = p_name; + } + + void SetVersion(const std::uint32_t p_version) + { + m_header.version = p_version; + } + + [[nodiscard]] + const typename FLAT_ASSET::NativeTableType& GetAsset() const + { + return m_asset; + } + + [[nodiscard]] + typename FLAT_ASSET::NativeTableType& GetAsset() + { + return m_asset; + } + + [[nodiscard]] + eastl::vector Save() const + { + flatbuffers::FlatBufferBuilder innerAssetFbb; + innerAssetFbb.Finish(FLAT_ASSET::Pack(innerAssetFbb, &m_asset)); + + ::Flat::Bigfoot::AssetT asset; + asset.header = eastl::make_unique<::Flat::Bigfoot::AssetHeaderT>(m_header); + asset.inner_asset = eastl::vector {innerAssetFbb.GetBufferPointer(), + innerAssetFbb.GetBufferPointer() + innerAssetFbb.GetSize()}; + + flatbuffers::FlatBufferBuilder assetFbb; + assetFbb.Finish(::Flat::Bigfoot::Asset::Pack(assetFbb, &asset)); + + return eastl::vector {std::bit_cast(assetFbb.GetBufferPointer()), + std::bit_cast(assetFbb.GetBufferPointer() + assetFbb.GetSize())}; + } + + [[nodiscard]] + static std::uint64_t GetTypeID() + { + static const std::uint64_t typeID = rapidhash(FLAT_ASSET::GetFullyQualifiedName(), + std::strlen(FLAT_ASSET::GetFullyQualifiedName())); + return typeID; + } + + [[nodiscard]] + static eastl::string_view GetTypeName() + { + return FLAT_ASSET::GetFullyQualifiedName(); + } + + Asset& operator=(const Asset& p_asset) = default; + Asset& operator=(Asset&& p_asset) = default; + + private: + typename FLAT_ASSET::NativeTableType m_asset; + ::Flat::Bigfoot::AssetHeaderT m_header; +}; +} // namespace Bigfoot + +#endif diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp new file mode 100644 index 0000000..592f596 --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetContainer.hpp @@ -0,0 +1,350 @@ +/********************************************************************* + * \file AssetContainer.hpp + * + * \author Romain BOULLARD + * \date May 2026 + *********************************************************************/ +#ifndef BIGFOOT_ENGINE_ASSET_ASSETCONTAINER_HPP +#define BIGFOOT_ENGINE_ASSET_ASSETCONTAINER_HPP +#include +#include + +#include + +#include + +#include + +namespace Bigfoot +{ +class ContainerHandle +{ + public: + ContainerHandle() = default; + + ContainerHandle(const ContainerHandle& p_handle) = default; + ContainerHandle(ContainerHandle&& p_handle) = default; + + ~ContainerHandle() = default; + + /* + * Increment the HardRef count + * + */ + void IncrementHardRefCount() + { + ++m_hardRefCount; + } + + /* + * Decrement the HardRef count + * + */ + void DecrementHardRefCount() + { + --m_hardRefCount; + } + + /* + * Increment the SoftRef count + * + */ + void IncrementSoftRefCount() + { + ++m_softRefCount; + } + + /* + * Decrement the SoftRef count + * + */ + void DecrementSoftRefCount() + { + --m_softRefCount; + } + + /* + * Get the Asset + * + * \return The asset, can be nullptr + */ + [[nodiscard]] + AssetBase* GetAsset() + { + return m_asset; + } + + /* + * Get the Asset + * + * \return The asset + */ + [[nodiscard]] + const AssetBase* GetAsset() const + { + return m_asset; + } + + /* + * Set the asset + * + * \param p_asset The asset + */ + void SetAsset(AssetBase* p_asset) + { + m_asset = p_asset; + } + + ContainerHandle& operator=(const ContainerHandle& p_handle) = default; + ContainerHandle& operator=(ContainerHandle&& p_handle) = default; + + private: + /* + * The HardRef count + */ + std::uint32_t m_hardRefCount = 0; + + /* + * The SoftRef count + */ + std::uint32_t m_softRefCount = 0; + + /* + * The asset + */ + AssetBase* m_asset = nullptr; +}; + +/****************************************************************************************/ + +class AssetContainerBase +{ + public: + virtual ~AssetContainerBase() = default; + + /* + * Check if an Asset is in the AssetContainer or not + * + * \param p_uuid The UUID to check + * \return True if in AssetContainer, false otherwise + */ + [[nodiscard]] + bool Has(const UUID& p_uuid) const + { + const Entry* entry = FindEntry(p_uuid); + return entry != nullptr && entry->m_assetSlotKey.Valid(); + } + + /* + * Acquires a ContainerHandle for a given UUID + * Will create it if it does not exists + * + * \param p_uuid The UUID to get ContainerHandle for + * \return A ContainerHandle for the UUID + */ + [[nodiscard]] + ContainerHandle& AcquireContainerHandle(const UUID& p_uuid) + { + return *m_handles.Get(GetOrCreateEntry(p_uuid).m_handleSlotKey); + } + + /* + * Remove an Asset from the AssetContainer + * + * \param p_uuid The UUID to remove + */ + virtual void Remove(const UUID& p_uuid) + { + if (Entry* entry = FindEntry(p_uuid); entry != nullptr && entry->m_handleSlotKey.Valid()) + { + m_handles.Remove(entry->m_handleSlotKey); + m_uuidToEntry.erase(p_uuid); + } + } + + AssetContainerBase& operator=(const AssetContainerBase& p_container) = delete; + AssetContainerBase& operator=(AssetContainerBase&& p_container) = default; + + protected: + struct Entry + { + /* + * SlotMapKey to the handle + */ + SlotMapKey m_handleSlotKey; + + /* + * SlotMapKey to the asset + */ + SlotMapKey m_assetSlotKey; + }; + + AssetContainerBase() = default; + + AssetContainerBase(const AssetContainerBase& p_container) = delete; + AssetContainerBase(AssetContainerBase&& p_container) = default; + + /* + * Finds an entry matching the Asset + * + * \param p_uuid The UUID to find + * \return Pointer to an Entry, nullptr otherwise + */ + [[nodiscard]] + Entry* FindEntry(const UUID& p_uuid) + { + const auto it = m_uuidToEntry.find(p_uuid); + return it != m_uuidToEntry.end() ? &it->second : nullptr; + } + + /* + * Finds an entry matching the Asset + * + * \param p_uuid The UUID to find + * \return Pointer to an Entry, nullptr otherwise + */ + [[nodiscard]] + const Entry* FindEntry(const UUID& p_uuid) const + { + const auto it = m_uuidToEntry.find(p_uuid); + return it != m_uuidToEntry.end() ? &it->second : nullptr; + } + + /* + * Finds an entry matching the Asset + * Creates it if it does not exist + * + * \param p_uuid The UUID to find + * \return The entry matching the Asset + */ + [[nodiscard]] + Entry& GetOrCreateEntry(const UUID& p_uuid) + { + auto [it, inserted] = m_uuidToEntry.try_emplace(p_uuid); + if (inserted) + { + it->second.m_handleSlotKey = m_handles.Insert(); + } + + return it->second; + } + + /* + * Get a ContainerHandle + * + * \param p_handleSlotKey The key to the container + * \return The container + */ + [[nodiscard]] + ContainerHandle& FindContainerHandle(const SlotMapKey p_handleSlotKey) + { + return *m_handles.Get(p_handleSlotKey); + } + + private: + /* + * HandleContainers + */ + StableSlotMap m_handles; + + /* + * Every Asset added to the map + */ + ankerl::unordered_dense::segmented_map m_uuidToEntry; +}; + +/****************************************************************************************/ + +template +class AssetContainer: public AssetContainerBase +{ + public: + AssetContainer() = default; + + AssetContainer(const AssetContainer& p_container) = delete; + AssetContainer(AssetContainer&& p_container) = default; + + ~AssetContainer() = default; + + /* + * Inserts an Asset to the AssetContainer + * + * \tparam ARGS Arguments to construct the asset + * \param p_args The arguments + * \return The key to the inserted asset. + */ + template + [[nodiscard]] + SlotMapKey Insert(ARGS&&... p_args) + { + SlotMapKey slotKey = m_assets.Insert(std::forward(p_args)...); + ASSET* asset = m_assets.Get(slotKey); + + Entry& entry = GetOrCreateEntry(asset->GetHeader().uuid); + if (entry.m_assetSlotKey.Valid()) + { + m_assets.Remove(slotKey); + slotKey = entry.m_assetSlotKey; + } + else + { + entry.m_assetSlotKey = slotKey; + FindContainerHandle(entry.m_handleSlotKey).SetAsset(asset); + } + + return slotKey; + } + + /* + * Get the Asset + * + * \param p_key The key to the asset + * \return Pointer to the Asset + */ + [[nodiscard]] + ASSET* Get(const SlotMapKey p_key) + { + return m_assets.Get(p_key); + } + + /* + * Get the Asset + * + * \param p_key The key to the asset + * \return Pointer to the Asset + */ + [[nodiscard]] + const ASSET* Get(const SlotMapKey p_key) const + { + return m_assets.Get(p_key); + } + + /* + * Remove an Asset from the AssetContainer + * + * \param p_uuid The UUID to remove + */ + void Remove(const UUID& p_uuid) override + { + if (Entry* entry = FindEntry(p_uuid); entry != nullptr && entry->m_assetSlotKey.Valid()) + { + FindContainerHandle(entry->m_handleSlotKey).SetAsset(nullptr); + m_assets.Remove(entry->m_assetSlotKey); + entry->m_assetSlotKey = SlotMapKey {}; + } + + AssetContainerBase::Remove(p_uuid); + } + + AssetContainer& operator=(const AssetContainer& p_container) = delete; + AssetContainer& operator=(AssetContainer&& p_container) = default; + + private: + /* + * The assets + */ + StableSlotMap m_assets; +}; +} // namespace Bigfoot + +#endif diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetHelper.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetHelper.hpp new file mode 100644 index 0000000..db18acd --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetHelper.hpp @@ -0,0 +1,24 @@ +/********************************************************************* + * \file AssetHelper.hpp + * + * \author Romain BOULLARD + * \date April 2026 + *********************************************************************/ +#ifndef BIGFOOT_ENGINE_ASSET_ASSETHELPER_HPP +#define BIGFOOT_ENGINE_ASSET_ASSETHELPER_HPP +#include +#include +#include + +#define BIGFOOT_ASSET(AssetName, AssetType) \ + namespace Bigfoot \ + { \ + template<> \ + AssetTypeID GetAssetTypeID() \ + { \ + return AssetType::GetTypeID(); \ + } \ + AssetContainer g_containerFor##AssetName; \ + const bool g_insertedContainerFor##AssetName = g_assetLibrary.Insert(&g_containerFor##AssetName); \ + } +#endif diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetLibrary.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetLibrary.hpp new file mode 100644 index 0000000..49c540c --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetLibrary.hpp @@ -0,0 +1,194 @@ +/********************************************************************* + * \file AssetLibrary.hpp + * + * \author Romain BOULLARD + * \date July 2026 + *********************************************************************/ +#ifndef BIGFOOT_ENGINE_ASSET_ASSETLIBRARY_HPP +#define BIGFOOT_ENGINE_ASSET_ASSETLIBRARY_HPP +#include +#include + +#include + +namespace Bigfoot +{ +class AssetLibrary +{ + public: + AssetLibrary() = default; + + AssetLibrary(const AssetLibrary& p_library) = default; + AssetLibrary(AssetLibrary&& p_library) = default; + + ~AssetLibrary() = default; + + /** + * Insert an AssetContainer pointer to the library + * + * \tparam ASSET The Asset type + * \param p_assetContainer The asset container + * \return The AssetContainer for the Asset type. Nullptr if not found + */ + template + [[nodiscard]] + bool Insert(AssetContainer* p_assetContainer) + { + static const AssetTypeID typeID = ASSET::GetTypeID(); + if (m_assetContainers.contains(typeID)) + { + return false; + } + + const auto inserted = m_assetContainers.emplace(typeID, p_assetContainer); + + return inserted.second; + } + + /** + * Get the AssetContainer for a given Asset type + * + * \tparam ASSET The Asset type + * \return The AssetContainer for the Asset type. Nullptr if not found + */ + template + [[nodiscard]] + AssetContainer* GetAssetContainer() + { + static const AssetTypeID typeID = ASSET::GetTypeID(); + return static_cast*>(GetAssetContainer(typeID)); + } + + /** + * Get the AssetContainer for a given Asset type + * + * \tparam ASSET The Asset type + * \return The AssetContainer for the Asset type. Nullptr if not found + */ + template + [[nodiscard]] + const AssetContainer* GetAssetContainer() const + { + static const AssetTypeID typeID = ASSET::GetTypeID(); + return static_cast*>(GetAssetContainer(typeID)); + } + + /** + * Get the AssetContainer for a given AssetType + * + * \param p_typeID The asset type ID + * \return The AssetContainer for the AssetType. Nullptr if not found + */ + [[nodiscard]] + AssetContainerBase* GetAssetContainer(const AssetTypeID p_typeID) + { + if (const auto container = m_assetContainers.find(p_typeID); container != m_assetContainers.end()) + { + return container->second; + } + + return nullptr; + } + + /** + * Get the AssetContainer for a given AssetType + * + * \param p_typeID The asset type ID + * \return The AssetContainer for the AssetType. Nullptr if not found + */ + [[nodiscard]] + const AssetContainerBase* GetAssetContainer(const AssetTypeID p_typeID) const + { + if (const auto container = m_assetContainers.find(p_typeID); container != m_assetContainers.end()) + { + return container->second; + } + + return nullptr; + } + + /** + * Find The associated container for a given UUID identifying an Asset + * + * \param p_uuid The UUID + * \return The AssetContainer containing the asset. Nullptr if not found + */ + [[nodiscard]] + AssetContainerBase* FindAssetContainerContainerForUUID(const UUID& p_uuid) + { + for (const auto& [typeID, container]: m_assetContainers) + { + if (container->Has(p_uuid)) + { + return container; + } + } + + return nullptr; + } + + /** + * Find The associated container for a given UUID identifying an Asset + * + * \param p_uuid The UUID + * \return The AssetContainer containing the asset. Nullptr if not found + */ + [[nodiscard]] + const AssetContainerBase* FindAssetContainerContainerForUUID(const UUID& p_uuid) const + { + for (const auto& [typeID, container]: m_assetContainers) + { + if (container->Has(p_uuid)) + { + return container; + } + } + + return nullptr; + } + + AssetLibrary& operator=(const AssetLibrary& p_library) = default; + AssetLibrary& operator=(AssetLibrary&& p_library) = default; + + private: + // All the asset containers + ankerl::unordered_dense::segmented_map m_assetContainers; +}; + +/****************************************************************************************/ + +// The global asset library for Bigfoot +inline AssetLibrary g_assetLibrary; +inline AssetLibrary* g_activeAssetLibrary = &g_assetLibrary; + +/****************************************************************************************/ + +class ScopedActiveAssetLibrary +{ + public: + ScopedActiveAssetLibrary(AssetLibrary* p_assetLibrary): + m_previous(g_activeAssetLibrary) + { + g_activeAssetLibrary = p_assetLibrary; + } + + ScopedActiveAssetLibrary(const ScopedActiveAssetLibrary& p_scopedActiveAssetLibrary) = default; + ScopedActiveAssetLibrary(ScopedActiveAssetLibrary&& p_scopedActiveAssetLibrary) = default; + + ~ScopedActiveAssetLibrary() + { + g_activeAssetLibrary = m_previous; + } + + ScopedActiveAssetLibrary& operator=(const ScopedActiveAssetLibrary& p_scopedActiveAssetLibrary) = default; + ScopedActiveAssetLibrary& operator=(ScopedActiveAssetLibrary&& p_scopedActiveAssetLibrary) = default; + + private: + /* + * The previously active asset library. + */ + AssetLibrary* m_previous = nullptr; +}; +} // namespace Bigfoot + +#endif diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetTypeID.fbs b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetTypeID.fbs new file mode 100644 index 0000000..6ffe9f6 --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetTypeID.fbs @@ -0,0 +1,8 @@ +native_include "Engine/Asset/AssetTypeID.hpp"; + +namespace Flat.Bigfoot; + +struct AssetTypeID (native_type: "::Bigfoot::AssetTypeID") +{ + value: ulong; +} \ No newline at end of file diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetTypeID.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetTypeID.hpp new file mode 100644 index 0000000..6b82dc6 --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetTypeID.hpp @@ -0,0 +1,34 @@ +/********************************************************************* + * \file AssetTypeID.hpp + * + * \author Romain BOULLARD + * \date February 2026 + *********************************************************************/ +#ifndef BIGFOOT_ENGINE_ASSET_ASSETTYPEID_HPP +#define BIGFOOT_ENGINE_ASSET_ASSETTYPEID_HPP +#include + +namespace Bigfoot +{ +using AssetTypeID = std::uint64_t; +} + +/****************************************************************************************/ + +namespace Flat +{ +namespace Bigfoot +{ +struct AssetTypeID; +} +} // namespace Flat + +/****************************************************************************************/ + +namespace flatbuffers +{ +Flat::Bigfoot::AssetTypeID Pack(const Bigfoot::AssetTypeID& p_assetTypeID); +Bigfoot::AssetTypeID UnPack(const Flat::Bigfoot::AssetTypeID& p_flatAssetTypeID); +} // namespace flatbuffers + +#endif diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetTypeID_generated.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetTypeID_generated.hpp new file mode 100644 index 0000000..d7b9b51 --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/AssetTypeID_generated.hpp @@ -0,0 +1,78 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_ASSETTYPEID_FLAT_BIGFOOT_H_ +#define FLATBUFFERS_GENERATED_ASSETTYPEID_FLAT_BIGFOOT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && + FLATBUFFERS_VERSION_MINOR == 12 && + FLATBUFFERS_VERSION_REVISION == 19, + "Non-compatible flatbuffers version included"); +// Ensure the included flatbuffers.h is Bigfoot's fork - stock +// flatbuffers (or a differently versioned Bigfoot fork) is not compatible. +#ifndef FLATBUFFERS_BIGFOOT_VERSION +#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible" +#endif +static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1, + "Non-compatible Bigfoot flatbuffers fork version included"); + +#include "Engine/Asset/AssetTypeID.hpp" + +#include "EASTL/unique_ptr.h" +#include "EASTL/string.h" +#include "EASTL/vector.h" + +namespace Flat { +namespace Bigfoot { + +struct AssetTypeID; + +inline const ::flatbuffers::TypeTable *AssetTypeIDTypeTable(); + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) AssetTypeID FLATBUFFERS_FINAL_CLASS { + private: + uint64_t value_; + + public: + struct Traits; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return AssetTypeIDTypeTable(); + } + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.AssetTypeID"; + } + AssetTypeID() + : value_(0) { + } + AssetTypeID(uint64_t _value) + : value_(::flatbuffers::EndianScalar(_value)) { + } + uint64_t value() const { + return ::flatbuffers::EndianScalar(value_); + } +}; +FLATBUFFERS_STRUCT_END(AssetTypeID, 8); + +struct AssetTypeID::Traits { + using type = AssetTypeID; +}; + +inline const ::flatbuffers::TypeTable *AssetTypeIDTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_ULONG, 0, -1 } + }; + static const int64_t values[] = { 0, 8 }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_STRUCT, 1, type_codes, nullptr, nullptr, values, nullptr + }; + return &tt; +} + +} // namespace Bigfoot +} // namespace Flat + +#endif // FLATBUFFERS_GENERATED_ASSETTYPEID_FLAT_BIGFOOT_H_ diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset_generated.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset_generated.hpp new file mode 100644 index 0000000..a3269dc --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/Asset_generated.hpp @@ -0,0 +1,413 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_ASSET_FLAT_BIGFOOT_H_ +#define FLATBUFFERS_GENERATED_ASSET_FLAT_BIGFOOT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && + FLATBUFFERS_VERSION_MINOR == 12 && + FLATBUFFERS_VERSION_REVISION == 19, + "Non-compatible flatbuffers version included"); +// Ensure the included flatbuffers.h is Bigfoot's fork - stock +// flatbuffers (or a differently versioned Bigfoot fork) is not compatible. +#ifndef FLATBUFFERS_BIGFOOT_VERSION +#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible" +#endif +static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1, + "Non-compatible Bigfoot flatbuffers fork version included"); + +#include "Engine/Asset/AssetTypeID.hpp" +#include "System/UUID/UUID.hpp" +#include "Engine/Asset/AssetTypeID_generated.hpp" +#include "System/UUID/UUID_generated.hpp" + +#include "EASTL/unique_ptr.h" +#include "EASTL/string.h" +#include "EASTL/vector.h" + +namespace Flat { +namespace Bigfoot { + +struct AssetHeader; +struct AssetHeaderBuilder; +struct AssetHeaderT; + +struct Asset; +struct AssetBuilder; +struct AssetT; + +inline const ::flatbuffers::TypeTable *AssetHeaderTypeTable(); + +inline const ::flatbuffers::TypeTable *AssetTypeTable(); + +struct AssetHeaderT : public ::flatbuffers::NativeTable { + typedef AssetHeader TableType; + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.AssetHeaderT"; + } + ::Bigfoot::UUID uuid{}; + eastl::string name{}; + ::Bigfoot::AssetTypeID type_id{}; + eastl::string type_name{}; + uint32_t version = 0; +}; + +struct AssetHeader FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef AssetHeaderT NativeTableType; + typedef AssetHeaderBuilder Builder; + struct Traits; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return AssetHeaderTypeTable(); + } + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.AssetHeader"; + } + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_UUID = 4, + VT_NAME = 6, + VT_TYPE_ID = 8, + VT_TYPE_NAME = 10, + VT_VERSION = 12 + }; + const Flat::Bigfoot::UUID *uuid() const { + return GetStruct(VT_UUID); + } + const ::flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + const Flat::Bigfoot::AssetTypeID *type_id() const { + return GetStruct(VT_TYPE_ID); + } + const ::flatbuffers::String *type_name() const { + return GetPointer(VT_TYPE_NAME); + } + uint32_t version() const { + return GetField(VT_VERSION, 0); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyFieldRequired(verifier, VT_UUID, 1) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyFieldRequired(verifier, VT_TYPE_ID, 8) && + VerifyOffsetRequired(verifier, VT_TYPE_NAME) && + verifier.VerifyString(type_name()) && + VerifyField(verifier, VT_VERSION, 4) && + verifier.EndTable(); + } + AssetHeaderT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AssetHeaderT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AssetHeaderT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AssetHeaderBuilder { + typedef AssetHeader Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_uuid(const Flat::Bigfoot::UUID *uuid) { + fbb_.AddStruct(AssetHeader::VT_UUID, uuid); + } + void add_name(::flatbuffers::Offset<::flatbuffers::String> name) { + fbb_.AddOffset(AssetHeader::VT_NAME, name); + } + void add_type_id(const Flat::Bigfoot::AssetTypeID *type_id) { + fbb_.AddStruct(AssetHeader::VT_TYPE_ID, type_id); + } + void add_type_name(::flatbuffers::Offset<::flatbuffers::String> type_name) { + fbb_.AddOffset(AssetHeader::VT_TYPE_NAME, type_name); + } + void add_version(uint32_t version) { + fbb_.AddElement(AssetHeader::VT_VERSION, version, 0); + } + explicit AssetHeaderBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + fbb_.Required(o, AssetHeader::VT_UUID); + fbb_.Required(o, AssetHeader::VT_NAME); + fbb_.Required(o, AssetHeader::VT_TYPE_ID); + fbb_.Required(o, AssetHeader::VT_TYPE_NAME); + return o; + } +}; + +inline ::flatbuffers::Offset CreateAssetHeader( + ::flatbuffers::FlatBufferBuilder &_fbb, + const Flat::Bigfoot::UUID *uuid = nullptr, + ::flatbuffers::Offset<::flatbuffers::String> name = 0, + const Flat::Bigfoot::AssetTypeID *type_id = nullptr, + ::flatbuffers::Offset<::flatbuffers::String> type_name = 0, + uint32_t version = 0) { + AssetHeaderBuilder builder_(_fbb); + builder_.add_version(version); + builder_.add_type_name(type_name); + builder_.add_type_id(type_id); + builder_.add_name(name); + builder_.add_uuid(uuid); + return builder_.Finish(); +} + +struct AssetHeader::Traits { + using type = AssetHeader; + static auto constexpr Create = CreateAssetHeader; +}; + +::flatbuffers::Offset CreateAssetHeader(::flatbuffers::FlatBufferBuilder &_fbb, const AssetHeaderT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct AssetT : public ::flatbuffers::NativeTable { + typedef Asset TableType; + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.AssetT"; + } + eastl::unique_ptr header{}; + eastl::vector inner_asset{}; + AssetT() = default; + AssetT(const AssetT &o); + AssetT(AssetT&&) FLATBUFFERS_NOEXCEPT = default; + AssetT &operator=(AssetT o) FLATBUFFERS_NOEXCEPT; +}; + +struct Asset FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef AssetT NativeTableType; + typedef AssetBuilder Builder; + struct Traits; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return AssetTypeTable(); + } + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.Asset"; + } + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_HEADER = 4, + VT_INNER_ASSET = 6 + }; + const Flat::Bigfoot::AssetHeader *header() const { + return GetPointer(VT_HEADER); + } + const ::flatbuffers::Vector *inner_asset() const { + return GetPointer *>(VT_INNER_ASSET); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_HEADER) && + verifier.VerifyTable(header()) && + VerifyOffsetRequired(verifier, VT_INNER_ASSET) && + verifier.VerifyVector(inner_asset()) && + verifier.EndTable(); + } + AssetT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AssetT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AssetT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AssetBuilder { + typedef Asset Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_header(::flatbuffers::Offset header) { + fbb_.AddOffset(Asset::VT_HEADER, header); + } + void add_inner_asset(::flatbuffers::Offset<::flatbuffers::Vector> inner_asset) { + fbb_.AddOffset(Asset::VT_INNER_ASSET, inner_asset); + } + explicit AssetBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + fbb_.Required(o, Asset::VT_HEADER); + fbb_.Required(o, Asset::VT_INNER_ASSET); + return o; + } +}; + +inline ::flatbuffers::Offset CreateAsset( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset header = 0, + ::flatbuffers::Offset<::flatbuffers::Vector> inner_asset = 0) { + AssetBuilder builder_(_fbb); + builder_.add_inner_asset(inner_asset); + builder_.add_header(header); + return builder_.Finish(); +} + +struct Asset::Traits { + using type = Asset; + static auto constexpr Create = CreateAsset; +}; + +::flatbuffers::Offset CreateAsset(::flatbuffers::FlatBufferBuilder &_fbb, const AssetT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + +inline AssetHeaderT *AssetHeader::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::make_unique(); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void AssetHeader::UnPackTo(AssetHeaderT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = uuid(); if (_e) _o->uuid = ::flatbuffers::UnPack(*_e); } + { auto _e = name(); if (_e) _o->name = eastl::string(_e->c_str(), _e->size()); } + { auto _e = type_id(); if (_e) _o->type_id = ::flatbuffers::UnPack(*_e); } + { auto _e = type_name(); if (_e) _o->type_name = eastl::string(_e->c_str(), _e->size()); } + { auto _e = version(); _o->version = _e; } +} + +inline ::flatbuffers::Offset CreateAssetHeader(::flatbuffers::FlatBufferBuilder &_fbb, const AssetHeaderT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return AssetHeader::Pack(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset AssetHeader::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AssetHeaderT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const AssetHeaderT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _uuid = ::flatbuffers::Pack(_o->uuid); + auto _name = _fbb.CreateString(_o->name); + auto _type_id = ::flatbuffers::Pack(_o->type_id); + auto _type_name = _fbb.CreateString(_o->type_name); + auto _version = _o->version; + return Flat::Bigfoot::CreateAssetHeader( + _fbb, + &_uuid, + _name, + &_type_id, + _type_name, + _version); +} + +inline AssetT::AssetT(const AssetT &o) + : header((o.header) ? new Flat::Bigfoot::AssetHeaderT(*o.header) : nullptr), + inner_asset(o.inner_asset) { +} + +inline AssetT &AssetT::operator=(AssetT o) FLATBUFFERS_NOEXCEPT { + std::swap(header, o.header); + std::swap(inner_asset, o.inner_asset); + return *this; +} + +inline AssetT *Asset::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::make_unique(); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Asset::UnPackTo(AssetT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = header(); if (_e) { if(_o->header) { _e->UnPackTo(_o->header.get(), _resolver); } else { _o->header = eastl::unique_ptr(_e->UnPack(_resolver)); } } else if (_o->header) { _o->header.reset(); } } + { auto _e = inner_asset(); if (_e) { _o->inner_asset.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->inner_asset.begin()); } } +} + +inline ::flatbuffers::Offset CreateAsset(::flatbuffers::FlatBufferBuilder &_fbb, const AssetT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return Asset::Pack(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset Asset::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AssetT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const AssetT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _header = _o->header ? CreateAssetHeader(_fbb, _o->header.get(), _rehasher) : 0; + auto _inner_asset = _fbb.CreateVector(_o->inner_asset.data(), _o->inner_asset.size()); + return Flat::Bigfoot::CreateAsset( + _fbb, + _header, + _inner_asset); +} + +inline const ::flatbuffers::TypeTable *AssetHeaderTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_SEQUENCE, 0, 0 }, + { ::flatbuffers::ET_STRING, 0, -1 }, + { ::flatbuffers::ET_SEQUENCE, 0, 1 }, + { ::flatbuffers::ET_STRING, 0, -1 }, + { ::flatbuffers::ET_UINT, 0, -1 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + Flat::Bigfoot::UUIDTypeTable, + Flat::Bigfoot::AssetTypeIDTypeTable + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_TABLE, 5, type_codes, type_refs, nullptr, nullptr, nullptr + }; + return &tt; +} + +inline const ::flatbuffers::TypeTable *AssetTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_SEQUENCE, 0, 0 }, + { ::flatbuffers::ET_UCHAR, 1, -1 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + Flat::Bigfoot::AssetHeaderTypeTable + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_TABLE, 2, type_codes, type_refs, nullptr, nullptr, nullptr + }; + return &tt; +} + +inline const Flat::Bigfoot::Asset *GetAsset(const void *buf) { + return ::flatbuffers::GetRoot(buf); +} + +inline const Flat::Bigfoot::Asset *GetSizePrefixedAsset(const void *buf) { + return ::flatbuffers::GetSizePrefixedRoot(buf); +} + +template +inline bool VerifyAssetBuffer( + ::flatbuffers::VerifierTemplate &verifier) { + return verifier.template VerifyBuffer(nullptr); +} + +template +inline bool VerifySizePrefixedAssetBuffer( + ::flatbuffers::VerifierTemplate &verifier) { + return verifier.template VerifySizePrefixedBuffer(nullptr); +} + +inline const char *AssetExtension() { + return "bfbs"; +} + +inline void FinishAssetBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.Finish(root); +} + +inline void FinishSizePrefixedAssetBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root); +} + +inline eastl::unique_ptr UnPackAsset( + const void *buf, + const ::flatbuffers::resolver_function_t *res = nullptr) { + return eastl::unique_ptr(GetAsset(buf)->UnPack(res)); +} + +inline eastl::unique_ptr UnPackSizePrefixedAsset( + const void *buf, + const ::flatbuffers::resolver_function_t *res = nullptr) { + return eastl::unique_ptr(GetSizePrefixedAsset(buf)->UnPack(res)); +} + +} // namespace Bigfoot +} // namespace Flat + +#endif // FLATBUFFERS_GENERATED_ASSET_FLAT_BIGFOOT_H_ diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/Reference.fbs b/Bigfoot/Sources/Engine/Include/Engine/Asset/Reference.fbs new file mode 100644 index 0000000..1282b64 --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/Reference.fbs @@ -0,0 +1,15 @@ +include "System/UUID/UUID.fbs"; + +native_include "Engine/Asset/Reference.hpp"; + +namespace Flat.Bigfoot; + +struct HardReference (bigfoot_ref_wrapper: "::Bigfoot::HardReference") +{ + uuid: UUID; +} + +struct SoftReference (bigfoot_ref_wrapper: "::Bigfoot::SoftReference") +{ + uuid: UUID; +} \ No newline at end of file diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/Reference.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/Reference.hpp new file mode 100644 index 0000000..79833f9 --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/Reference.hpp @@ -0,0 +1,256 @@ +/********************************************************************* + * \file Reference.hpp + * + * \author Romain BOULLARD + * \date April 2026 + *********************************************************************/ +#ifndef BIGFOOT_ENGINE_ASSET_REFERENCE_HPP +#define BIGFOOT_ENGINE_ASSET_REFERENCE_HPP +#include + +#include + +#include + +namespace Bigfoot +{ +template +AssetTypeID GetAssetTypeID(); + +template +class HardReference +{ + public: + HardReference() = default; + + HardReference(const UUID& p_uuid): + m_uuid(p_uuid) + { + Acquire(); + } + + HardReference(const HardReference& p_ref): + m_uuid(p_ref.m_uuid), + m_handle(p_ref.m_handle) + { + Acquire(); + } + + HardReference(HardReference&& p_ref) noexcept: + m_uuid(std::exchange(p_ref.m_uuid, UUID::NULL_UUID)), + m_handle(std::exchange(p_ref.m_handle, nullptr)) + { + } + + [[nodiscard]] + const UUID& GetUUID() const + { + return m_uuid; + } + + [[nodiscard]] + const ASSET* Get() const + { + return m_handle ? static_cast(m_handle->GetAsset()) : nullptr; + } + + [[nodiscard]] + ASSET* Get() + { + return m_handle ? static_cast(m_handle->GetAsset()) : nullptr; + } + + ~HardReference() + { + Release(); + } + + HardReference& operator=(const HardReference& p_ref) + { + if (this != &p_ref) + { + Release(); + m_uuid = p_ref.m_uuid; + m_handle = p_ref.m_handle; + Acquire(); + } + return *this; + } + + HardReference& operator=(HardReference&& p_ref) noexcept + { + if (this != &p_ref) + { + Release(); + m_uuid = std::exchange(p_ref.m_uuid, UUID::NULL_UUID); + m_handle = std::exchange(p_ref.m_handle, nullptr); + } + return *this; + } + + [[nodiscard]] + bool operator==(const HardReference& p_ref) const + { + return m_uuid == p_ref.m_uuid; + } + + private: + void Acquire() + { + if (!m_uuid) + { + return; + } + + AssetContainerBase* assetContainer = nullptr; + if constexpr (std::is_same_v) + { + assetContainer = g_activeAssetLibrary->FindAssetContainerContainerForUUID(m_uuid); + } + else + { + assetContainer = g_activeAssetLibrary->GetAssetContainer(GetAssetTypeID()); + } + + if (assetContainer) + { + if (!m_handle) + { + m_handle = &assetContainer->AcquireContainerHandle(m_uuid); + } + m_handle->IncrementSoftRefCount(); + } + } + + void Release() + { + if (m_handle) + { + m_handle->DecrementHardRefCount(); + m_handle = nullptr; + } + } + + UUID m_uuid = UUID::NULL_UUID; + ContainerHandle* m_handle = nullptr; +}; + +template +class SoftReference +{ + public: + SoftReference() = default; + + SoftReference(const UUID& p_uuid): + m_uuid(p_uuid) + { + Acquire(); + } + + SoftReference(const SoftReference& p_ref): + m_uuid(p_ref.m_uuid), + m_handle(p_ref.m_handle) + { + Acquire(); + } + + SoftReference(SoftReference&& p_ref) noexcept: + m_uuid(std::exchange(p_ref.m_uuid, UUID::NULL_UUID)), + m_handle(std::exchange(p_ref.m_handle, nullptr)) + { + } + + [[nodiscard]] + const UUID& GetUUID() const + { + return m_uuid; + } + + [[nodiscard]] + const ASSET* Get() const + { + return m_handle ? static_cast(m_handle->GetAsset()) : nullptr; + } + + [[nodiscard]] + ASSET* Get() + { + return m_handle ? static_cast(m_handle->GetAsset()) : nullptr; + } + + ~SoftReference() + { + Release(); + } + + SoftReference& operator=(const SoftReference& p_ref) + { + if (this != &p_ref) + { + Release(); + m_uuid = p_ref.m_uuid; + m_handle = p_ref.m_handle; + Acquire(); + } + return *this; + } + + SoftReference& operator=(SoftReference&& p_ref) noexcept + { + if (this != &p_ref) + { + Release(); + m_uuid = std::exchange(p_ref.m_uuid, UUID::NULL_UUID); + m_handle = std::exchange(p_ref.m_handle, nullptr); + } + return *this; + } + + [[nodiscard]] + bool operator==(const SoftReference& p_ref) const + { + return m_uuid == p_ref.m_uuid; + } + + private: + void Acquire() + { + if (!m_uuid) + { + return; + } + + AssetContainerBase* assetContainer = nullptr; + if constexpr (std::is_same_v) + { + assetContainer = g_activeAssetLibrary->FindAssetContainerContainerForUUID(m_uuid); + } + else + { + assetContainer = g_activeAssetLibrary->GetAssetContainer(GetAssetTypeID()); + } + + if (assetContainer) + { + if (!m_handle) + { + m_handle = &assetContainer->AcquireContainerHandle(m_uuid); + } + m_handle->IncrementSoftRefCount(); + } + } + + void Release() + { + if (m_handle) + { + m_handle->DecrementSoftRefCount(); + m_handle = nullptr; + } + } + + UUID m_uuid = UUID::NULL_UUID; + ContainerHandle* m_handle = nullptr; +}; +} // namespace Bigfoot +#endif diff --git a/Bigfoot/Sources/Engine/Include/Engine/Asset/Reference_generated.hpp b/Bigfoot/Sources/Engine/Include/Engine/Asset/Reference_generated.hpp new file mode 100644 index 0000000..1bc2051 --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/Asset/Reference_generated.hpp @@ -0,0 +1,129 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_REFERENCE_FLAT_BIGFOOT_H_ +#define FLATBUFFERS_GENERATED_REFERENCE_FLAT_BIGFOOT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && + FLATBUFFERS_VERSION_MINOR == 12 && + FLATBUFFERS_VERSION_REVISION == 19, + "Non-compatible flatbuffers version included"); +// Ensure the included flatbuffers.h is Bigfoot's fork - stock +// flatbuffers (or a differently versioned Bigfoot fork) is not compatible. +#ifndef FLATBUFFERS_BIGFOOT_VERSION +#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible" +#endif +static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1, + "Non-compatible Bigfoot flatbuffers fork version included"); + +#include "System/UUID/UUID.hpp" +#include "Engine/Asset/Reference.hpp" +#include "System/UUID/UUID_generated.hpp" + +#include "EASTL/unique_ptr.h" +#include "EASTL/string.h" +#include "EASTL/vector.h" + +namespace Flat { +namespace Bigfoot { + +struct HardReference; + +struct SoftReference; + +inline const ::flatbuffers::TypeTable *HardReferenceTypeTable(); + +inline const ::flatbuffers::TypeTable *SoftReferenceTypeTable(); + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(1) HardReference FLATBUFFERS_FINAL_CLASS { + private: + Flat::Bigfoot::UUID uuid_; + + public: + struct Traits; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return HardReferenceTypeTable(); + } + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.HardReference"; + } + HardReference() + : uuid_() { + } + HardReference(const Flat::Bigfoot::UUID &_uuid) + : uuid_(_uuid) { + } + const Flat::Bigfoot::UUID &uuid() const { + return uuid_; + } +}; +FLATBUFFERS_STRUCT_END(HardReference, 16); + +struct HardReference::Traits { + using type = HardReference; +}; + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(1) SoftReference FLATBUFFERS_FINAL_CLASS { + private: + Flat::Bigfoot::UUID uuid_; + + public: + struct Traits; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return SoftReferenceTypeTable(); + } + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.SoftReference"; + } + SoftReference() + : uuid_() { + } + SoftReference(const Flat::Bigfoot::UUID &_uuid) + : uuid_(_uuid) { + } + const Flat::Bigfoot::UUID &uuid() const { + return uuid_; + } +}; +FLATBUFFERS_STRUCT_END(SoftReference, 16); + +struct SoftReference::Traits { + using type = SoftReference; +}; + +inline const ::flatbuffers::TypeTable *HardReferenceTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_SEQUENCE, 0, 0 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + Flat::Bigfoot::UUIDTypeTable + }; + static const int64_t values[] = { 0, 16 }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_STRUCT, 1, type_codes, type_refs, nullptr, values, nullptr + }; + return &tt; +} + +inline const ::flatbuffers::TypeTable *SoftReferenceTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_SEQUENCE, 0, 0 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + Flat::Bigfoot::UUIDTypeTable + }; + static const int64_t values[] = { 0, 16 }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_STRUCT, 1, type_codes, type_refs, nullptr, values, nullptr + }; + return &tt; +} + +} // namespace Bigfoot +} // namespace Flat + +#endif // FLATBUFFERS_GENERATED_REFERENCE_FLAT_BIGFOOT_H_ diff --git a/Bigfoot/Sources/Engine/Include/Engine/BigFile/BigFile.hpp b/Bigfoot/Sources/Engine/Include/Engine/BigFile/BigFile.hpp new file mode 100644 index 0000000..cb1c562 --- /dev/null +++ b/Bigfoot/Sources/Engine/Include/Engine/BigFile/BigFile.hpp @@ -0,0 +1,276 @@ +/********************************************************************* + * \file BigFile.hpp + * + * \author Romain BOULLARD + * \date October 2025 + *********************************************************************/ +#ifndef BIGFOOT_ENGINE_BIGFILE_BIGFILE_HPP +#define BIGFOOT_ENGINE_BIGFILE_BIGFILE_HPP +#include + +#include + +#include +#include + +namespace Bigfoot +{ +class BigFile +{ + public: + /** + * Constructor + * + * \param p_file The file targetting the BigFile DB + */ + BigFile(const File& p_file); + + BigFile(const BigFile& p_bigFile) = delete; + BigFile(BigFile&& p_bigFile) = delete; + + /** + * Begin a transaction + * + */ + void BeginTransaction(); + + /** + * Commit a transaction + * + */ + void CommitTransaction(); + + /** + * Rollback a transaction + * + */ + void RollbackTransaction(); + + ~BigFile(); + + BigFile& operator=(const BigFile& p_bigFile) = delete; + BigFile& operator=(BigFile&& p_bigFile) = delete; + + class Request + { + public: + /* + * Constructor + * + * \param p_bigFile The bigfile + * \param p_request The SQL request + */ + Request(const BigFile& p_bigFile, const eastl::string_view p_request); + + Request(const Request& p_request) = delete; + Request(Request&& p_request) = delete; + + using CopyValue = TaggedType; + + /* + * Bind a int32 value to the Request at index + * + * \param p_index The index to bind to + * \param p_value The value + */ + void Bind(const std::uint32_t p_index, const std::int32_t p_value); + + /* + * Bind a uint32 value to the Request at index + * + * \param p_index The index to bind to + * \param p_value The value + */ + void Bind(const std::uint32_t p_index, const std::uint32_t p_value); + + /* + * Bind a int64 value to the Request at index + * + * \param p_index The index to bind to + * \param p_value The value + */ + void Bind(const std::uint32_t p_index, const std::int64_t p_value); + + /* + * Bind a uint64 value to the Request at index + * + * \param p_index The index to bind to + * \param p_value The value + */ + void Bind(const std::uint32_t p_index, const std::uint64_t p_value); + + /* + * Bind a float value to the Request at index + * + * \param p_index The index to bind to + * \param p_value The value + */ + void Bind(const std::uint32_t p_index, const float p_value); + + /* + * Bind a double value to the Request at index + * + * \param p_index The index to bind to + * \param p_value The value + */ + void Bind(const std::uint32_t p_index, const double p_value); + + /* + * Bind a string value to the Request at index + * + * \param p_index The index to bind to + * \param p_value The value + * \param p_copy Should the memory be copied so that caller does not have to retain it + */ + void Bind(const std::uint32_t p_index, + const eastl::string_view p_value, + const CopyValue p_copy = CopyValue {false}); + + /* + * Bind a blob value to the Request at index + * + * \param p_index The index to bind to + * \param p_value The value + * \param p_copy Should the memory be copied so that caller does not have to retain it + */ + void Bind(const std::uint32_t p_index, + const eastl::span p_value, + const CopyValue p_copy = CopyValue {false}); + + /* + * Step through the request + * + * \return True if the request can continue (get next row), false otherwise + */ + [[nodiscard]] + bool Step(); + + /* + * Execute the request once + * + * The number of modified rows + */ + [[maybe_unused]] + std::uint32_t Execute(); + + class Column + { + public: + /* + * Constructor + * + * \param p_request The request to get the column of + * \param p_index Column index + */ + Column(const Request& p_request, const std::uint32_t p_index); + + Column(const Column& p_column) = default; + Column(Column&& p_column) = default; + + ~Column() = default; + + Column& operator=(const Column& p_column) = default; + Column& operator=(Column&& p_column) = default; + + /* + * Get value as a int32 + * + * \return The value + */ + operator std::int32_t() const; + + /* + * Get value as a uint32 + * + * \return The value + */ + operator std::uint32_t() const; + + /* + * Get value as a int64 + * + * \return The value + */ + operator std::int64_t() const; + + /* + * Get value as a uint64 + * + * \return The value + */ + operator std::uint64_t() const; + + /* + * Get value as a float + * + * \return The value + */ + operator float() const; + + /* + * Get value as a double + * + * \return The value + */ + operator double() const; + + /* + * Get value as a string + * + * \return The value + */ + operator eastl::string_view() const; + + /* + * Get value as a blob + * + * \return The value + */ + operator eastl::span() const; + + private: + /* + * The statement + */ + sqlite3_stmt* m_statement; + + /* + * The column index + */ + std::uint32_t m_index; + }; + + /* + * Get a column + * + * \param p_index Column index + */ + [[nodiscard]] + Column Get(const std::uint32_t p_index) const; + + ~Request(); + + Request& operator=(const Request& p_request) = delete; + Request& operator=(Request&& p_request) = delete; + + private: + /* + * The database + */ + sqlite3* m_db; + + /* + * The statement + */ + sqlite3_stmt* m_statement; + }; + + private: + /** + * The BigFile DB + */ + sqlite3* m_db; +}; +} // namespace Bigfoot + +#endif diff --git a/Bigfoot/Sources/Engine/Include/Engine/EngineAssertHandler.hpp b/Bigfoot/Sources/Engine/Include/Engine/EngineAssertHandler.hpp index 1c969a7..b47f803 100644 --- a/Bigfoot/Sources/Engine/Include/Engine/EngineAssertHandler.hpp +++ b/Bigfoot/Sources/Engine/Include/Engine/EngineAssertHandler.hpp @@ -6,16 +6,14 @@ *********************************************************************/ #ifndef BIGFOOT_ENGINE_ENGINEASSERTHANDLER_HPP #define BIGFOOT_ENGINE_ENGINEASSERTHANDLER_HPP -#include - #include +#include + #if defined BIGFOOT_NOT_OPTIMIZED -#include #include #include -#include namespace Bigfoot { @@ -33,23 +31,18 @@ class EngineAssertHandler * Handle an assertion. * * \param p_location Location of the assertion. - * \param p_stacktrace The stack trace * \param p_format Format string for the assertion message. * \param p_args Arguments for the format string. */ template - static void Handle(const std::source_location& p_location, - const std::string_view p_stacktrace, - std::format_string p_format, - ARGS&&... p_args) + static void Handle(const std::source_location& p_location, std::format_string p_format, ARGS&&... p_args) { BIGFOOT_LOG_FATAL(ENGINE_LOGGER, - "Assert: {} (File:{}, Line:{}, Function:{}\n{}", - std::format(p_format, eastl::forward(p_args)...), + "Assert: {} (File:{}, Line:{}, Function:{}\n", + std::format(p_format, std::forward(p_args)...), p_location.file_name(), p_location.line(), - p_location.function_name(), - p_stacktrace); + p_location.function_name()); } EngineAssertHandler& operator=(const EngineAssertHandler& p_handler) = delete; diff --git a/Bigfoot/Sources/Engine/Include/Engine/EngineLogger_generated.hpp b/Bigfoot/Sources/Engine/Include/Engine/EngineLogger_generated.hpp index e3e58e9..0067c8c 100644 --- a/Bigfoot/Sources/Engine/Include/Engine/EngineLogger_generated.hpp +++ b/Bigfoot/Sources/Engine/Include/Engine/EngineLogger_generated.hpp @@ -6,7 +6,7 @@ *********************************************************************/ #ifndef BIGFOOT_ENGINELOGGER_GENERATED_HPP #define BIGFOOT_ENGINELOGGER_GENERATED_HPP -#include +#include #if defined BIGFOOT_NOT_OPTIMIZED diff --git a/Bigfoot/Sources/System/CMakeLists.txt b/Bigfoot/Sources/System/CMakeLists.txt index e25e7e0..1688ada 100644 --- a/Bigfoot/Sources/System/CMakeLists.txt +++ b/Bigfoot/Sources/System/CMakeLists.txt @@ -2,8 +2,6 @@ get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME) project(${PackageName}) set(PublicDependencies - $<$:quill::quill> - mimalloc stduuid::stduuid) set(PrivateDependencies) set(BigfootPublicDependencies @@ -18,11 +16,3 @@ bigfoot_create_package_lib( "") bigfoot_create_logger() - -target_compile_definitions(${PROJECT_NAME} - PUBLIC $<$:QUILL_NO_EXCEPTIONS> - PUBLIC $<$:QUILL_DISABLE_NON_PREFIXED_MACROS> - - PUBLIC MI_SHARED_LIB) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/MimallocImpl.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) - diff --git a/Bigfoot/Sources/System/File.cpp b/Bigfoot/Sources/System/File.cpp index ff57db3..e2fe411 100644 --- a/Bigfoot/Sources/System/File.cpp +++ b/Bigfoot/Sources/System/File.cpp @@ -37,21 +37,21 @@ bool File::Exists() const /****************************************************************************************/ -eastl::string_view File::Path() const +eastl::string_view File::GetPath() const { return m_pathString; } /****************************************************************************************/ -File File::Absolute() const +File File::ToAbsolute() const { return File {std::filesystem::absolute(m_path)}; } /****************************************************************************************/ -File File::Relative() const +File File::ToRelative() const { return File {std::filesystem::relative(m_path)}; } diff --git a/Bigfoot/Sources/System/Include/System/File.hpp b/Bigfoot/Sources/System/Include/System/File.hpp index 0c67f62..1beb51c 100644 --- a/Bigfoot/Sources/System/Include/System/File.hpp +++ b/Bigfoot/Sources/System/Include/System/File.hpp @@ -57,7 +57,7 @@ class File * \return The path */ [[nodiscard]] - eastl::string_view Path() const; + eastl::string_view GetPath() const; /** * Get the same file, relative to the current executable @@ -65,7 +65,7 @@ class File * \return The relative file */ [[nodiscard]] - File Relative() const; + File ToRelative() const; /** * Get the same file, with an absolute path @@ -73,7 +73,7 @@ class File * \return The absolute file */ [[nodiscard]] - File Absolute() const; + File ToAbsolute() const; ~File() = default; diff --git a/Bigfoot/Sources/System/Include/System/SystemAssertHandler.hpp b/Bigfoot/Sources/System/Include/System/SystemAssertHandler.hpp index 6e58208..8ee1842 100644 --- a/Bigfoot/Sources/System/Include/System/SystemAssertHandler.hpp +++ b/Bigfoot/Sources/System/Include/System/SystemAssertHandler.hpp @@ -6,16 +6,14 @@ *********************************************************************/ #ifndef BIGFOOT_SYSTEM_SYSTEMASSERTHANDLER_HPP #define BIGFOOT_SYSTEM_SYSTEMASSERTHANDLER_HPP -#include - #include +#include + #if defined BIGFOOT_NOT_OPTIMIZED -#include #include #include -#include namespace Bigfoot { @@ -33,23 +31,18 @@ class SystemAssertHandler * Handle an assertion. * * \param p_location Location of the assertion. - * \param p_stacktrace The stack trace * \param p_format Format string for the assertion message. * \param p_args Arguments for the format string. */ template - static void Handle(const std::source_location& p_location, - const std::string_view p_stacktrace, - std::format_string p_format, - ARGS&&... p_args) + static void Handle(const std::source_location& p_location, std::format_string p_format, ARGS&&... p_args) { BIGFOOT_LOG_FATAL(SYSTEM_LOGGER, - "Assert: {} (File:{}, Line:{}, Function:{}\n{}", - std::format(p_format, eastl::forward(p_args)...), + "Assert: {} (File:{}, Line:{}, Function:{}\n", + std::format(p_format, std::forward(p_args)...), p_location.file_name(), p_location.line(), - p_location.function_name(), - p_stacktrace); + p_location.function_name()); } SystemAssertHandler& operator=(const SystemAssertHandler& p_handler) = delete; diff --git a/Bigfoot/Sources/System/Include/System/SystemLogger_generated.hpp b/Bigfoot/Sources/System/Include/System/SystemLogger_generated.hpp index dcdf934..cbafc52 100644 --- a/Bigfoot/Sources/System/Include/System/SystemLogger_generated.hpp +++ b/Bigfoot/Sources/System/Include/System/SystemLogger_generated.hpp @@ -6,7 +6,7 @@ *********************************************************************/ #ifndef BIGFOOT_SYSTEMLOGGER_GENERATED_HPP #define BIGFOOT_SYSTEMLOGGER_GENERATED_HPP -#include +#include #if defined BIGFOOT_NOT_OPTIMIZED diff --git a/Bigfoot/Sources/System/Include/System/Time/Time.fbs b/Bigfoot/Sources/System/Include/System/Time/Time.fbs new file mode 100644 index 0000000..fc9ae88 --- /dev/null +++ b/Bigfoot/Sources/System/Include/System/Time/Time.fbs @@ -0,0 +1,8 @@ +native_include "System/Time/Time.hpp"; + +namespace Flat.Bigfoot; + +struct Time (native_type: "::Bigfoot::Time") +{ + epoch:ulong; +} \ No newline at end of file diff --git a/Bigfoot/Sources/System/Include/System/Time/Time.hpp b/Bigfoot/Sources/System/Include/System/Time/Time.hpp new file mode 100644 index 0000000..635df54 --- /dev/null +++ b/Bigfoot/Sources/System/Include/System/Time/Time.hpp @@ -0,0 +1,86 @@ +/********************************************************************* + * \file Time.hpp + * + * \author Romain BOULLARD + * \date December 2025 + *********************************************************************/ +#ifndef BIGFOOT_SYSTEM_TIME_TIME_HPP +#define BIGFOOT_SYSTEM_TIME_TIME_HPP +#include +#include +#include + +namespace Bigfoot +{ +class Time +{ + public: + Time(const std::uint64_t p_epoch); + + Time(const Time& p_time) = default; + Time(Time&& p_time) = default; + + [[nodiscard]] + std::uint32_t GetYear() const; + + [[nodiscard]] + std::uint32_t GetMonth() const; + + [[nodiscard]] + std::uint32_t GetDay() const; + + [[nodiscard]] + std::uint32_t GetHour() const; + + [[nodiscard]] + std::uint32_t GetMinute() const; + + [[nodiscard]] + std::uint32_t GetSecond() const; + + [[nodiscard]] + std::uint32_t GetMicrosecond() const; + + [[nodiscard]] + std::uint64_t GetEpoch() const; + + ~Time() = default; + + Time& operator=(const Time& p_time) = default; + Time& operator=(Time&& p_time) = default; + + [[nodiscard]] + auto operator<=>(const Time& p_other) const + { + return m_epoch <=> p_other.m_epoch; + } + + [[nodiscard]] + static Time Now(); + + private: + std::uint64_t m_epoch; + std::tm m_timeInfo; + std::chrono::microseconds m_microseconds; +}; +} // namespace Bigfoot + +/****************************************************************************************/ + +namespace Flat +{ +namespace Bigfoot +{ +struct Time; +} +} // namespace Flat + +/****************************************************************************************/ + +namespace flatbuffers +{ +Flat::Bigfoot::Time Pack(const Bigfoot::Time& p_time); +Bigfoot::Time UnPack(const Flat::Bigfoot::Time& p_flatTime); +} // namespace flatbuffers + +#endif diff --git a/Bigfoot/Sources/System/Include/System/Time/Time_generated.hpp b/Bigfoot/Sources/System/Include/System/Time/Time_generated.hpp new file mode 100644 index 0000000..b71046f --- /dev/null +++ b/Bigfoot/Sources/System/Include/System/Time/Time_generated.hpp @@ -0,0 +1,78 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_TIME_FLAT_BIGFOOT_H_ +#define FLATBUFFERS_GENERATED_TIME_FLAT_BIGFOOT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && + FLATBUFFERS_VERSION_MINOR == 12 && + FLATBUFFERS_VERSION_REVISION == 19, + "Non-compatible flatbuffers version included"); +// Ensure the included flatbuffers.h is Bigfoot's fork - stock +// flatbuffers (or a differently versioned Bigfoot fork) is not compatible. +#ifndef FLATBUFFERS_BIGFOOT_VERSION +#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible" +#endif +static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1, + "Non-compatible Bigfoot flatbuffers fork version included"); + +#include "System/Time/Time.hpp" + +#include "EASTL/unique_ptr.h" +#include "EASTL/string.h" +#include "EASTL/vector.h" + +namespace Flat { +namespace Bigfoot { + +struct Time; + +inline const ::flatbuffers::TypeTable *TimeTypeTable(); + +FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Time FLATBUFFERS_FINAL_CLASS { + private: + uint64_t epoch_; + + public: + struct Traits; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return TimeTypeTable(); + } + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.Time"; + } + Time() + : epoch_(0) { + } + Time(uint64_t _epoch) + : epoch_(::flatbuffers::EndianScalar(_epoch)) { + } + uint64_t epoch() const { + return ::flatbuffers::EndianScalar(epoch_); + } +}; +FLATBUFFERS_STRUCT_END(Time, 8); + +struct Time::Traits { + using type = Time; +}; + +inline const ::flatbuffers::TypeTable *TimeTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_ULONG, 0, -1 } + }; + static const int64_t values[] = { 0, 8 }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_STRUCT, 1, type_codes, nullptr, nullptr, values, nullptr + }; + return &tt; +} + +} // namespace Bigfoot +} // namespace Flat + +#endif // FLATBUFFERS_GENERATED_TIME_FLAT_BIGFOOT_H_ diff --git a/Bigfoot/Sources/System/Include/System/UUID/UUID.fbs b/Bigfoot/Sources/System/Include/System/UUID/UUID.fbs index c622b85..6fab320 100644 --- a/Bigfoot/Sources/System/Include/System/UUID/UUID.fbs +++ b/Bigfoot/Sources/System/Include/System/UUID/UUID.fbs @@ -1,6 +1,6 @@ -native_include "System/UUID/FlatUUID.hpp"; +native_include "System/UUID/UUID.hpp"; -namespace Bigfoot.Flat; +namespace Flat.Bigfoot; struct UUID (native_type: "::Bigfoot::UUID") { diff --git a/Bigfoot/Sources/System/Include/System/UUID/UUID.hpp b/Bigfoot/Sources/System/Include/System/UUID/UUID.hpp index 21ff3b1..9014a2a 100644 --- a/Bigfoot/Sources/System/Include/System/UUID/UUID.hpp +++ b/Bigfoot/Sources/System/Include/System/UUID/UUID.hpp @@ -4,9 +4,8 @@ * \author Romain BOULLARD * \date October 2025 *********************************************************************/ -#ifndef BIGFOOT_SYSTEM_UUID_HPP -#define BIGFOOT_SYSTEM_UUID_HPP - +#ifndef BIGFOOT_SYSTEM_UUID_UUID_HPP +#define BIGFOOT_SYSTEM_UUID_UUID_HPP #include namespace Bigfoot @@ -35,19 +34,31 @@ class UUID UUID(const UUID& p_uuid) = default; UUID(UUID&& p_uuid) noexcept = default; + /** + * Gets the raw bytes of a UUID + * + * \return A view to the raw bytes + */ + [[nodiscard]] + std::span ToBytes() const; + + /** + * Gets the string representation of a UUID + * + * \return A string representing the UUID + */ + [[nodiscard]] + std::string ToString() const; + ~UUID() = default; - operator std::span() const; - operator std::string() const; operator bool() const; UUID& operator=(const UUID& p_uuid) = default; UUID& operator=(UUID&& p_uuid) noexcept = default; [[nodiscard]] - bool operator==(const UUID& p_uuid) const = default; - [[nodiscard]] - bool operator!=(const UUID& p_uuid) const = default; + bool operator==(const UUID& p_uuid) const; [[nodiscard]] bool operator<(const UUID& p_uuid) const; @@ -114,10 +125,12 @@ struct std::formatter template auto format(const Bigfoot::UUID& p_uuid, FormatContext& ctx) const { - return std::format_to(ctx.out(), "{}", static_cast(p_uuid)); + return std::format_to(ctx.out(), "{}", p_uuid.ToString()); } }; +/****************************************************************************************/ + #if defined BIGFOOT_NOT_OPTIMIZED #include @@ -131,7 +144,7 @@ struct fmtquill::formatter auto format(const Bigfoot::UUID& p_uuid, format_context& ctx) const { - return fmtquill::format_to(ctx.out(), "{}", static_cast(p_uuid)); + return fmtquill::format_to(ctx.out(), "{}", p_uuid.ToString()); } }; @@ -141,4 +154,22 @@ struct quill::Codec: quill::DeferredFormatCodec }; #endif +/****************************************************************************************/ + +namespace Flat +{ +namespace Bigfoot +{ +struct UUID; +} +} // namespace Flat + +/****************************************************************************************/ + +namespace flatbuffers +{ +Flat::Bigfoot::UUID Pack(const Bigfoot::UUID& p_uuid); +Bigfoot::UUID UnPack(const Flat::Bigfoot::UUID& p_flatUUID); +} // namespace flatbuffers + #endif diff --git a/Bigfoot/Sources/System/Include/System/UUID/UUID_generated.hpp b/Bigfoot/Sources/System/Include/System/UUID/UUID_generated.hpp index f02e7fa..f6b35a0 100644 --- a/Bigfoot/Sources/System/Include/System/UUID/UUID_generated.hpp +++ b/Bigfoot/Sources/System/Include/System/UUID/UUID_generated.hpp @@ -1,8 +1,8 @@ // automatically generated by the FlatBuffers compiler, do not modify -#ifndef FLATBUFFERS_GENERATED_UUID_BIGFOOT_FLAT_H_ -#define FLATBUFFERS_GENERATED_UUID_BIGFOOT_FLAT_H_ +#ifndef FLATBUFFERS_GENERATED_UUID_FLAT_BIGFOOT_H_ +#define FLATBUFFERS_GENERATED_UUID_FLAT_BIGFOOT_H_ #include "flatbuffers/flatbuffers.h" @@ -12,14 +12,22 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && FLATBUFFERS_VERSION_MINOR == 12 && FLATBUFFERS_VERSION_REVISION == 19, "Non-compatible flatbuffers version included"); +// Ensure the included flatbuffers.h is Bigfoot's fork - stock +// flatbuffers (or a differently versioned Bigfoot fork) is not compatible. +#ifndef FLATBUFFERS_BIGFOOT_VERSION +#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible" +#endif +static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1, + "Non-compatible Bigfoot flatbuffers fork version included"); -#include "System/UUID/FlatUUID.hpp" +#include "System/UUID/UUID.hpp" #include "EASTL/unique_ptr.h" #include "EASTL/string.h" +#include "EASTL/vector.h" -namespace Bigfoot { namespace Flat { +namespace Bigfoot { struct UUID; @@ -35,7 +43,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(1) UUID FLATBUFFERS_FINAL_CLASS { return UUIDTypeTable(); } static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { - return "Bigfoot.Flat.UUID"; + return "Flat.Bigfoot.UUID"; } UUID() : bytes_() { @@ -59,16 +67,13 @@ inline const ::flatbuffers::TypeTable *UUIDTypeTable() { }; static const int16_t array_sizes[] = { 16, }; static const int64_t values[] = { 0, 16 }; - static const char * const names[] = { - "bytes" - }; static const ::flatbuffers::TypeTable tt = { - ::flatbuffers::ST_STRUCT, 1, type_codes, nullptr, array_sizes, values, names + ::flatbuffers::ST_STRUCT, 1, type_codes, nullptr, array_sizes, values, nullptr }; return &tt; } -} // namespace Flat } // namespace Bigfoot +} // namespace Flat -#endif // FLATBUFFERS_GENERATED_UUID_BIGFOOT_FLAT_H_ +#endif // FLATBUFFERS_GENERATED_UUID_FLAT_BIGFOOT_H_ diff --git a/Bigfoot/Sources/System/Time/Time.cpp b/Bigfoot/Sources/System/Time/Time.cpp new file mode 100644 index 0000000..e6e3a21 --- /dev/null +++ b/Bigfoot/Sources/System/Time/Time.cpp @@ -0,0 +1,139 @@ +/********************************************************************* + * \file Time.cpp + * + * \author Romain BOULLARD + * \date December 2025 + *********************************************************************/ +#include + +#include +#include + +namespace +{ +[[nodiscard]] +std::tm GetTimeInfo(const std::time_t& p_time) +{ + std::tm timeInfo {}; +#ifdef BIGFOOT_WINDOWS + [[maybe_unused]] + const errno_t error = gmtime_s(&timeInfo, &p_time); + if (error != 0) + { + char errnoStr[256]; + strerror_s(errnoStr, error); + + CRITICAL_ASSERT(Bigfoot::SystemAssertHandler, + false, + "Failed to convert epoch time to calendar time. {}", + errnoStr); + } +#elif BIGFOOT_LINUX + [[maybe_unused]] + const std::tm* error = gmtime_r(&p_time, &timeInfo); + CRITICAL_ASSERT(Bigfoot::SystemAssertHandler, error, "Failed to convert epoch time to calendar time"); +#else + static_assert(false, "not implemented"); +#endif + + return timeInfo; +} +} // namespace + +namespace Bigfoot +{ +Time::Time(const std::uint64_t p_epoch): + m_epoch(p_epoch), + m_timeInfo(GetTimeInfo(std::chrono::system_clock::to_time_t( + std::chrono::time_point {std::chrono::microseconds {m_epoch}}))), + m_microseconds(std::chrono::duration_cast( + std::chrono::duration_cast(std::chrono::time_point { + std::chrono::microseconds {m_epoch}}.time_since_epoch()) % + std::chrono::seconds(1))) +{ +} + +/****************************************************************************************/ + +std::uint32_t Time::GetYear() const +{ + return m_timeInfo.tm_year + 1900; +} + +/****************************************************************************************/ + +std::uint32_t Time::GetMonth() const +{ + return m_timeInfo.tm_mon + 1; +} + +/****************************************************************************************/ + +std::uint32_t Time::GetDay() const +{ + return m_timeInfo.tm_mday; +} + +/****************************************************************************************/ + +std::uint32_t Time::GetHour() const +{ + return m_timeInfo.tm_hour; +} + +/****************************************************************************************/ + +std::uint32_t Time::GetMinute() const +{ + return m_timeInfo.tm_min; +} + +/****************************************************************************************/ + +std::uint32_t Time::GetSecond() const +{ + return m_timeInfo.tm_sec; +} + +/****************************************************************************************/ + +std::uint32_t Time::GetMicrosecond() const +{ + return static_cast(m_microseconds.count()); +} + +/****************************************************************************************/ + +std::uint64_t Time::GetEpoch() const +{ + return m_epoch; +} + +/****************************************************************************************/ + +Time Time::Now() +{ + const std::chrono::time_point time = std::chrono::system_clock::now(); + const std::uint64_t epochInMicroSeconds = + std::chrono::duration_cast(time.time_since_epoch()).count(); + + return Time {epochInMicroSeconds}; +} +} // namespace Bigfoot + +/****************************************************************************************/ + +namespace flatbuffers +{ +Flat::Bigfoot::Time Pack(const Bigfoot::Time& p_time) +{ + return Flat::Bigfoot::Time {p_time.GetEpoch()}; +} + +/****************************************************************************************/ + +Bigfoot::Time UnPack(const Flat::Bigfoot::Time& p_flatTime) +{ + return Bigfoot::Time {p_flatTime.epoch()}; +} +} // namespace flatbuffers diff --git a/Bigfoot/Sources/System/UUID/UUID.cpp b/Bigfoot/Sources/System/UUID/UUID.cpp index cd87cb6..a69347d 100644 --- a/Bigfoot/Sources/System/UUID/UUID.cpp +++ b/Bigfoot/Sources/System/UUID/UUID.cpp @@ -6,6 +6,8 @@ *********************************************************************/ #include +#include + namespace Bigfoot { UUID UUID::NULL_UUID {"00000000-0000-0000-0000-000000000000"}; @@ -41,14 +43,14 @@ UUID::UUID(const std::span p_raw) /****************************************************************************************/ -UUID::operator std::span() const +std::span UUID::ToBytes() const { return m_uuid.as_bytes(); } /****************************************************************************************/ -UUID::operator std::string() const +std::string UUID::ToString() const { return uuids::to_string(m_uuid); } @@ -60,6 +62,11 @@ UUID::operator bool() const return *this != NULL_UUID; } +bool UUID::operator==(const UUID& p_uuid) const +{ + return m_uuid == p_uuid.m_uuid; +} + /****************************************************************************************/ bool UUID::operator<(const UUID& p_uuid) const @@ -85,3 +92,25 @@ uuids::uuid_random_generator UUID::GetUUIDGenerator() return uuids::uuid_random_generator {ms_randomGenerator}; } } // namespace Bigfoot + +/****************************************************************************************/ + +namespace flatbuffers +{ +Flat::Bigfoot::UUID Pack(const Bigfoot::UUID& p_uuid) +{ + const std::span bytes = p_uuid.ToBytes(); + return Flat::Bigfoot::UUID { + std::span {reinterpret_cast(bytes.data()), + bytes.size()}}; +} + +/****************************************************************************************/ + +Bigfoot::UUID UnPack(const Flat::Bigfoot::UUID& p_flatUUID) +{ + const std::span bytesView {p_flatUUID.bytes()->data(), + p_flatUUID.bytes()->size()}; + return Bigfoot::UUID {std::as_bytes(bytesView)}; +} +} // namespace flatbuffers diff --git a/Bigfoot/Sources/Utils/CMakeLists.txt b/Bigfoot/Sources/Utils/CMakeLists.txt index f12f19a..2250593 100644 --- a/Bigfoot/Sources/Utils/CMakeLists.txt +++ b/Bigfoot/Sources/Utils/CMakeLists.txt @@ -2,7 +2,12 @@ get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME) project(${PackageName}) set(PublicDependencies - $<$:cpptrace::cpptrace>) + $<$:quill::quill> + $,mimalloc-asan,mimalloc-static> + unordered_dense::unordered_dense + EASTL::EASTL + flatbuffers::flatbuffers + rapidhash::rapidhash) set(PrivateDependencies) set(BigfootPublicDependencies) set(BigfootPrivateDependencies) @@ -12,4 +17,12 @@ bigfoot_create_package_lib( "${PrivateLibraries}" "${BigfootPublicDependencies}" "${BigfootPrivateDependencies}" - "") \ No newline at end of file + "") +set_source_files_properties(../Utils/MimallocImpl.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) + +bigfoot_create_logger() + +target_compile_definitions(${PROJECT_NAME} + PUBLIC + $<$:QUILL_NO_EXCEPTIONS> + $<$:QUILL_DISABLE_NON_PREFIXED_MACROS>) \ No newline at end of file diff --git a/Bigfoot/Sources/Utils/Include/Utils/Assert.hpp b/Bigfoot/Sources/Utils/Include/Utils/Assert.hpp index 4bdefc2..708a39c 100644 --- a/Bigfoot/Sources/Utils/Include/Utils/Assert.hpp +++ b/Bigfoot/Sources/Utils/Include/Utils/Assert.hpp @@ -6,11 +6,10 @@ *********************************************************************/ #ifndef BIGFOOT_UTILS_ASSERT_HPP #define BIGFOOT_UTILS_ASSERT_HPP +#include #if defined BIGFOOT_NOT_OPTIMIZED -#include - #include #include @@ -38,13 +37,7 @@ constexpr std::source_location location = std::source_location::current(); \ if (!(p_assert)) [[unlikely]] \ { \ - constexpr auto stacktrace = []() -> std::string \ - { \ - const cpptrace::stacktrace stacktrace = cpptrace::generate_trace(); \ - return stacktrace.to_string(); \ - }; \ - \ - HANDLER::Handle(location, stacktrace(), p_message __VA_OPT__(, ) __VA_ARGS__); \ + HANDLER::Handle(location, p_message __VA_OPT__(, ) __VA_ARGS__); \ BREAK; \ } \ } while (false) @@ -55,13 +48,7 @@ constexpr std::source_location location = std::source_location::current(); \ if (!(p_assert)) [[unlikely]] \ { \ - constexpr auto stacktrace = []() -> std::string \ - { \ - const cpptrace::stacktrace stacktrace = cpptrace::generate_trace(); \ - return stacktrace.to_string(); \ - }; \ - \ - HANDLER::Handle(location, stacktrace(), p_message __VA_OPT__(, ) __VA_ARGS__); \ + HANDLER::Handle(location, p_message __VA_OPT__(, ) __VA_ARGS__); \ BREAK; \ } \ } while (false) @@ -72,13 +59,11 @@ constexpr std::source_location location = std::source_location::current(); \ if (!(p_assert)) [[unlikely]] \ { \ - constexpr auto stacktrace = []() -> std::string \ + HANDLER::Handle(location, p_message __VA_OPT__(, ) __VA_ARGS__); \ + if (Bigfoot::Singleton::HasInstance()) \ { \ - const cpptrace::stacktrace stacktrace = cpptrace::generate_trace(); \ - return stacktrace.to_string(); \ - }; \ - \ - HANDLER::Handle(location, stacktrace(), p_message __VA_OPT__(, ) __VA_ARGS__); \ + Bigfoot::Singleton::GetInstance().Flush(); \ + } \ BREAK; \ std::abort(); \ } \ diff --git a/Bigfoot/Sources/Utils/Include/Utils/Containers/SlotMap.hpp b/Bigfoot/Sources/Utils/Include/Utils/Containers/SlotMap.hpp new file mode 100644 index 0000000..fc14fc7 --- /dev/null +++ b/Bigfoot/Sources/Utils/Include/Utils/Containers/SlotMap.hpp @@ -0,0 +1,343 @@ +/********************************************************************* + * \file SlotMap.hpp + * + * \author Romain BOULLARD + * \date May 2026 + *********************************************************************/ +#ifndef BIGFOOT_UTILS_CONTAINERS_SLOTMAP_HPP +#define BIGFOOT_UTILS_CONTAINERS_SLOTMAP_HPP +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace Bigfoot +{ +template +class SlotMapKey +{ + public: + using IndexType = INDEX_TYPE; + using VersionType = VERSION_TYPE; + + private: + static constexpr std::uint32_t VERSION_BIT_COUNT = sizeof(VersionType) * std::numeric_limits::digits; + static constexpr std::uint32_t INDEX_BIT_COUNT = sizeof(IndexType) * std::numeric_limits::digits; + static_assert(VERSION_BIT_COUNT + INDEX_BIT_COUNT <= 64, + "We cant construct a 64 bit key from the given Version and Index types!"); + + static constexpr std::uint64_t INDEX_MASK = (static_cast(1) << INDEX_BIT_COUNT) - 1; + + public: + static constexpr VersionType INVALID_VERSION = 0; + + static constexpr IndexType MAX_INDEX = std::numeric_limits::max(); + static constexpr VersionType MAX_VERSION = std::numeric_limits::max(); + + constexpr SlotMapKey(const VersionType p_version, const IndexType p_index): + m_key((static_cast(p_version) << INDEX_BIT_COUNT) | + (static_cast(p_index) & INDEX_MASK)) + { + } + + constexpr SlotMapKey(): + SlotMapKey(INVALID_VERSION, 0) + { + } + + constexpr SlotMapKey(const SlotMapKey& p_slotKey) = default; + constexpr SlotMapKey(SlotMapKey&& p_slotKey) = default; + + constexpr ~SlotMapKey() = default; + + [[nodiscard]] + constexpr bool Valid() const + { + return GetVersion() != INVALID_VERSION; + } + + [[nodiscard]] + constexpr VersionType GetVersion() const + { + return static_cast(m_key >> INDEX_BIT_COUNT); + } + + [[nodiscard]] + constexpr IndexType GetIndex() const + { + return static_cast(m_key & INDEX_MASK); + } + + constexpr SlotMapKey& operator=(const SlotMapKey& p_slotKey) = default; + constexpr SlotMapKey& operator=(SlotMapKey&& p_slotKey) = default; + + [[nodiscard]] + constexpr bool operator==(const SlotMapKey& p_other) const = default; + + private: + std::uint64_t m_key; +}; + +template> +class DenseSlotMap +{ + public: + using SlotMapKey = SLOT_MAP_KEY_TYPE; + + using iterator = typename eastl::vector::iterator; + using const_iterator = typename eastl::vector::const_iterator; + using reverse_iterator = typename eastl::vector::reverse_iterator; + using const_reverse_iterator = typename eastl::vector::const_reverse_iterator; + + DenseSlotMap() = default; + + DenseSlotMap(const DenseSlotMap&) = default; + DenseSlotMap(DenseSlotMap&&) = default; + + ~DenseSlotMap() = default; + + [[nodiscard]] + bool Has(const SlotMapKey p_key) const + { + return p_key.Valid() && + (p_key.GetIndex() < m_keys.size() && p_key.GetVersion() == m_keys[p_key.GetIndex()].GetVersion()); + } + + [[nodiscard]] + std::size_t Size() const + { + return m_data.size(); + } + + [[nodiscard]] + std::size_t Capacity() const + { + return m_data.capacity(); + } + + [[nodiscard]] + bool Empty() const + { + return m_data.empty(); + } + + template + [[nodiscard]] + SlotMapKey Insert(ARGS&&... p_args) + { + ASSERT(UtilsAssertHandler, + Size() < SlotMapKey::MAX_INDEX, + "Can't store more than {} elements", + SlotMapKey::MAX_INDEX); + + m_data.emplace_back(std::forward(p_args)...); + const std::size_t indexToInsertedData = m_data.size() - 1; + + if (HasFreeSlots()) + { + const std::size_t indexToRecyclingKey = m_freeListHead; + + m_freeListHead = m_keys[indexToRecyclingKey].GetIndex(); + m_keys[indexToRecyclingKey] = SlotMapKey {m_keys[indexToRecyclingKey].GetVersion(), static_cast(indexToInsertedData)}; + m_dataToKey.emplace_back(indexToRecyclingKey); + + return SlotMapKey {m_keys[indexToRecyclingKey].GetVersion(), + static_cast(indexToRecyclingKey)}; + } + + m_keys.emplace_back(1, static_cast(indexToInsertedData)); + m_dataToKey.push_back(m_keys.size() - 1); + + return SlotMapKey {1, static_cast(m_keys.size() - 1)}; + } + + void Remove(const SlotMapKey p_key) + { + if (!Has(p_key)) + { + return; + } + + const std::size_t dataIndex = GetDataIndex(p_key); + + m_data.erase_unsorted(m_data.begin() + dataIndex); + m_dataToKey.erase_unsorted(m_dataToKey.begin() + dataIndex); + + if (dataIndex < Size()) + { + m_keys[m_dataToKey[dataIndex]] = SlotMapKey {m_keys[m_dataToKey[dataIndex]].GetVersion(), + static_cast(dataIndex)}; + } + + RecycleKey(p_key); + } + + void Reset() + { + m_data.clear(); + m_dataToKey.clear(); + m_keys.clear(); + m_freeListHead = SlotMapKey::MAX_INDEX; + } + + void Clear() + { + for (const std::size_t keyIndex: m_dataToKey) + { + RecycleKey(SlotMapKey {m_keys[keyIndex].GetVersion(), static_cast(keyIndex)}); + } + + m_data.clear(); + m_dataToKey.clear(); + } + + [[nodiscard]] + T* Get(const SlotMapKey p_slotKey) + { + return Has(p_slotKey) ? &m_data[GetDataIndex(p_slotKey)] : nullptr; + } + + [[nodiscard]] + const T* Get(const SlotMapKey p_slotKey) const + { + return Has(p_slotKey) ? &m_data[GetDataIndex(p_slotKey)] : nullptr; + } + + [[nodiscard]] + iterator begin() + { + return m_data.begin(); + } + + [[nodiscard]] + iterator end() + { + return m_data.end(); + } + + [[nodiscard]] + const_iterator begin() const + { + return m_data.begin(); + } + + [[nodiscard]] + const_iterator end() const + { + return m_data.end(); + } + + [[nodiscard]] + reverse_iterator rbegin() + { + return m_data.rbegin(); + } + + [[nodiscard]] + reverse_iterator rend() + { + return m_data.rend(); + } + + [[nodiscard]] + const_reverse_iterator rbegin() const + { + return m_data.rbegin(); + } + + [[nodiscard]] + const_reverse_iterator rend() const + { + return m_data.rend(); + } + + [[nodiscard]] + const_iterator cbegin() const + { + return m_data.cbegin(); + } + + [[nodiscard]] + const_iterator cend() const + { + return m_data.cend(); + } + + [[nodiscard]] + const_reverse_iterator crbegin() const + { + return m_data.crbegin(); + } + + [[nodiscard]] + const_reverse_iterator crend() const + { + return m_data.crend(); + } + + DenseSlotMap& operator=(const DenseSlotMap&) = default; + DenseSlotMap& operator=(DenseSlotMap&&) = default; + + private: + [[nodiscard]] + bool HasFreeSlots() const + { + return m_freeListHead != SlotMapKey::MAX_INDEX; + } + + [[nodiscard]] + std::size_t GetDataIndex(const SlotMapKey p_key) const + { + return m_keys[p_key.GetIndex()].GetIndex(); + } + + void RecycleKey(const SlotMapKey p_key) + { + const SlotMapKey::VersionType nextVersion = static_cast(p_key.GetVersion() + 1); + + if (nextVersion == SlotMapKey::INVALID_VERSION) + { + // Mark it dead, we've exhausted all versions for this key + m_keys[p_key.GetIndex()] = SlotMapKey {SlotMapKey::INVALID_VERSION, 0}; + return; + } + + m_keys[p_key.GetIndex()] = SlotMapKey {nextVersion, static_cast(m_freeListHead)}; + m_freeListHead = p_key.GetIndex(); + } + + private: + eastl::vector m_data; + eastl::vector m_keys; + + /** + * Allows us to match m_data and m_keys. + * dataIndex = m_keys[m_dataToKey[dataIndex]].GetIndex() + */ + eastl::vector m_dataToKey; + + /** + * Index to a key that can be recycled + */ + std::size_t m_freeListHead = SlotMapKey::MAX_INDEX; +}; + +template> +class StableSlotMap +{ + public: + + private: +}; +} // namespace Bigfoot + +#endif diff --git a/Bigfoot/Sources/Utils/Include/Utils/Log/EASTLFormatters.hpp b/Bigfoot/Sources/Utils/Include/Utils/Log/EASTLFormatters.hpp new file mode 100644 index 0000000..48e1236 --- /dev/null +++ b/Bigfoot/Sources/Utils/Include/Utils/Log/EASTLFormatters.hpp @@ -0,0 +1,95 @@ +/********************************************************************* + * \file EASTLFormatters.hpp + * + * \author Romain BOULLARD + * \date December 2025 + *********************************************************************/ +#ifndef BIGFOOT_UTILS_LOG_EASTLFORMATTERS_HPP +#define BIGFOOT_UTILS_LOG_EASTLFORMATTERS_HPP +#include + +#if defined(BIGFOOT_NOT_OPTIMIZED) +#include +#endif + +#include +#include + +#include + +// STRING + +template<> +struct std::formatter +{ + constexpr auto parse(std::format_parse_context& ctx) + { + return ctx.begin(); + } + + template + auto format(const eastl::string& p_string, FormatContext& ctx) const + { + return std::format_to(ctx.out(), "{}", p_string.c_str()); + } +}; + +#if defined BIGFOOT_NOT_OPTIMIZED +template<> +struct fmtquill::formatter +{ + constexpr auto parse(format_parse_context& ctx) + { + return ctx.begin(); + } + + auto format(const eastl::string& p_string, format_context& ctx) const + { + return fmtquill::format_to(ctx.out(), "{}", p_string.c_str()); + } +}; + +template<> +struct quill::Codec: quill::DeferredFormatCodec +{ +}; +#endif + +// STRING_VIEW + +template<> +struct std::formatter +{ + constexpr auto parse(std::format_parse_context& ctx) + { + return ctx.begin(); + } + + template + auto format(const eastl::string_view& p_stringView, FormatContext& ctx) const + { + return std::format_to(ctx.out(), "{}", p_stringView.data()); + } +}; + +#if defined BIGFOOT_NOT_OPTIMIZED +template<> +struct fmtquill::formatter +{ + constexpr auto parse(format_parse_context& ctx) + { + return ctx.begin(); + } + + auto format(const eastl::string_view& p_stringView, format_context& ctx) const + { + return fmtquill::format_to(ctx.out(), "{}", p_stringView.data()); + } +}; + +template<> +struct quill::Codec: quill::DeferredFormatCodec +{ +}; +#endif +#endif diff --git a/Bigfoot/Sources/Utils/Include/Utils/Log/Log.fbs b/Bigfoot/Sources/Utils/Include/Utils/Log/Log.fbs new file mode 100644 index 0000000..727798b --- /dev/null +++ b/Bigfoot/Sources/Utils/Include/Utils/Log/Log.fbs @@ -0,0 +1,16 @@ +namespace Bigfoot.Flat; + +enum LogSinkType: byte +{ + Console +} + +enum LogLevel: byte +{ + Debug, + Trace, + Info, + Warn, + Error, + Critical +} \ No newline at end of file diff --git a/Bigfoot/Sources/Utils/Include/Utils/Log/Log.hpp b/Bigfoot/Sources/Utils/Include/Utils/Log/Log.hpp new file mode 100644 index 0000000..79be60a --- /dev/null +++ b/Bigfoot/Sources/Utils/Include/Utils/Log/Log.hpp @@ -0,0 +1,102 @@ +/********************************************************************* + * \file Log.hpp + * + * \author Romain BOULLARD + * \date October 2025 + *********************************************************************/ +#ifndef BIGFOOT_UTILS_LOG_LOG_HPP +#define BIGFOOT_UTILS_LOG_LOG_HPP +#include + +#if defined BIGFOOT_NOT_OPTIMIZED +#include + +#include + +#ifdef BIGFOOT_WINDOWS +#pragma warning(disable: 4702) +#endif +#include +#include +#include +#include +#include +#if defined BIGFOOT_WINDOWS +#pragma warning(default: 4702) +#endif + +namespace Bigfoot +{ +class Log +{ + public: + struct LoggerInfo + { + std::string m_name; + Flat::LogLevel m_level; + }; + + Log(); + + Log(const Log& p_logger) = delete; + Log(Log&& p_logger) = delete; + + /** + * Register a logger. + * + * \param p_loggerInfo The logger to register + */ + [[nodiscard]] + quill::Logger* RegisterLogger(const LoggerInfo& p_loggerInfo); + + /** + * Unregister a logger. + * + * \param p_loggerInfo The logger to unregister + */ + void UnregisterLogger(const LoggerInfo& p_loggerInfo); + + /** + * Register a logger. + * + * \param p_loggerInfo The logger to get + * \return The logger, nullptr if it does not exist + */ + [[nodiscard]] + quill::Logger* GetLogger(const LoggerInfo& p_loggerInfo); + + /** + * Changes the loglevel of a Logger. + * + * \param p_loggerInfo The logger to change + * \param p_level The new level + */ + void ChangeLoggerLogLevel(LoggerInfo& p_loggerInfo, const Flat::LogLevel p_level); + + /* + * Flush all the loggers + * + */ + void Flush(); + + ~Log(); + + Log& operator=(const Log& p_logger) = delete; + Log& operator=(Log&& p_logger) = delete; + + private: + /** + * Set the LogLevel of a logger + * + * \param p_loggerInfo The logger to set + */ + void SetLoggerLevel(const LoggerInfo& p_loggerInfo); + + /* + * The sinks + */ + eastl::array, 1> m_sinks; +}; +} // namespace Bigfoot +#endif +#endif diff --git a/Bigfoot/Sources/Utils/Include/Utils/Log/LogMacros.hpp b/Bigfoot/Sources/Utils/Include/Utils/Log/LogMacros.hpp new file mode 100644 index 0000000..61e3cd7 --- /dev/null +++ b/Bigfoot/Sources/Utils/Include/Utils/Log/LogMacros.hpp @@ -0,0 +1,104 @@ +/********************************************************************* + * \file LogMacros.hpp + * + * \author Romain BOULLARD + * \date May 2026 + *********************************************************************/ +#ifndef BIGFOOT_UTILS_LOG_LOGMACROS_HPP +#define BIGFOOT_UTILS_LOG_LOGMACROS_HPP +#include +#include + +#if defined BIGFOOT_NOT_OPTIMIZED +#define BIGFOOT_LOG_DEBUG(loggerName, fmt, ...) \ + do \ + { \ + if (::quill::Logger* logger = ::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().GetLogger(loggerName)) \ + { \ + QUILL_LOG_DEBUG(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + else \ + { \ + QUILL_LOG_DEBUG(::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().RegisterLogger(loggerName), \ + fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + } while (0) + +#define BIGFOOT_LOG_TRACE(loggerName, fmt, ...) \ + do \ + { \ + if (::quill::Logger* logger = ::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().GetLogger(loggerName)) \ + { \ + QUILL_LOG_TRACE_L3(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + else \ + { \ + QUILL_LOG_TRACE_L3(::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().RegisterLogger(loggerName), \ + fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + } while (0) + +#define BIGFOOT_LOG_INFO(loggerName, fmt, ...) \ + do \ + { \ + if (::quill::Logger* logger = ::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().GetLogger(loggerName)) \ + { \ + QUILL_LOG_INFO(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + else \ + { \ + QUILL_LOG_INFO(::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().RegisterLogger(loggerName), \ + fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + } while (0) + +#define BIGFOOT_LOG_WARN(loggerName, fmt, ...) \ + do \ + { \ + if (::quill::Logger* logger = ::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().GetLogger(loggerName)) \ + { \ + QUILL_LOG_WARNING(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + else \ + { \ + QUILL_LOG_WARNING(::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().RegisterLogger(loggerName), \ + fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + } while (0) + +#define BIGFOOT_LOG_ERROR(loggerName, fmt, ...) \ + do \ + { \ + if (::quill::Logger* logger = ::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().GetLogger(loggerName)) \ + { \ + QUILL_LOG_ERROR(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + else \ + { \ + QUILL_LOG_ERROR(::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().RegisterLogger(loggerName), \ + fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + } while (0) + +#define BIGFOOT_LOG_FATAL(loggerName, fmt, ...) \ + do \ + { \ + if (::quill::Logger* logger = ::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().GetLogger(loggerName)) \ + { \ + QUILL_LOG_CRITICAL(logger, fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + else \ + { \ + QUILL_LOG_CRITICAL(::Bigfoot::Singleton<::Bigfoot::Log>::GetInstance().RegisterLogger(loggerName), \ + fmt __VA_OPT__(, ) __VA_ARGS__); \ + } \ + } while (0) +#else +#define BIGFOOT_LOG_DEBUG(loggerName, fmt, ...) +#define BIGFOOT_LOG_TRACE(loggerName, fmt, ...) +#define BIGFOOT_LOG_INFO(loggerName, fmt, ...) +#define BIGFOOT_LOG_WARN(loggerName, fmt, ...) +#define BIGFOOT_LOG_ERROR(loggerName, fmt, ...) +#define BIGFOOT_LOG_FATAL(loggerName, fmt, ...) +#endif +#endif diff --git a/Bigfoot/Sources/Utils/Include/Utils/Log/Log_generated.hpp b/Bigfoot/Sources/Utils/Include/Utils/Log/Log_generated.hpp new file mode 100644 index 0000000..887afbe --- /dev/null +++ b/Bigfoot/Sources/Utils/Include/Utils/Log/Log_generated.hpp @@ -0,0 +1,133 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_LOG_BIGFOOT_FLAT_H_ +#define FLATBUFFERS_GENERATED_LOG_BIGFOOT_FLAT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && + FLATBUFFERS_VERSION_MINOR == 12 && + FLATBUFFERS_VERSION_REVISION == 19, + "Non-compatible flatbuffers version included"); +// Ensure the included flatbuffers.h is Bigfoot's fork - stock +// flatbuffers (or a differently versioned Bigfoot fork) is not compatible. +#ifndef FLATBUFFERS_BIGFOOT_VERSION +#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible" +#endif +static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1, + "Non-compatible Bigfoot flatbuffers fork version included"); + +#include "EASTL/unique_ptr.h" +#include "EASTL/string.h" +#include "EASTL/vector.h" + +namespace Bigfoot { +namespace Flat { + +enum class LogSinkType : int8_t { + Console = 0, + MIN = Console, + MAX = Console +}; + +inline const LogSinkType (&EnumValuesLogSinkType())[1] { + static const LogSinkType values[] = { + LogSinkType::Console + }; + return values; +} + +inline const char * const *EnumNamesLogSinkType() { + static const char * const names[2] = { + "Console", + nullptr + }; + return names; +} + +inline const char *EnumNameLogSinkType(LogSinkType e) { + if (::flatbuffers::IsOutRange(e, LogSinkType::Console, LogSinkType::Console)) return ""; + const size_t index = static_cast(e); + return EnumNamesLogSinkType()[index]; +} + +enum class LogLevel : int8_t { + Debug = 0, + Trace = 1, + Info = 2, + Warn = 3, + Error = 4, + Critical = 5, + MIN = Debug, + MAX = Critical +}; + +inline const LogLevel (&EnumValuesLogLevel())[6] { + static const LogLevel values[] = { + LogLevel::Debug, + LogLevel::Trace, + LogLevel::Info, + LogLevel::Warn, + LogLevel::Error, + LogLevel::Critical + }; + return values; +} + +inline const char * const *EnumNamesLogLevel() { + static const char * const names[7] = { + "Debug", + "Trace", + "Info", + "Warn", + "Error", + "Critical", + nullptr + }; + return names; +} + +inline const char *EnumNameLogLevel(LogLevel e) { + if (::flatbuffers::IsOutRange(e, LogLevel::Debug, LogLevel::Critical)) return ""; + const size_t index = static_cast(e); + return EnumNamesLogLevel()[index]; +} + +inline const ::flatbuffers::TypeTable *LogSinkTypeTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_CHAR, 0, 0 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + Bigfoot::Flat::LogSinkTypeTypeTable + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_ENUM, 1, type_codes, type_refs, nullptr, nullptr, nullptr + }; + return &tt; +} + +inline const ::flatbuffers::TypeTable *LogLevelTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_CHAR, 0, 0 }, + { ::flatbuffers::ET_CHAR, 0, 0 }, + { ::flatbuffers::ET_CHAR, 0, 0 }, + { ::flatbuffers::ET_CHAR, 0, 0 }, + { ::flatbuffers::ET_CHAR, 0, 0 }, + { ::flatbuffers::ET_CHAR, 0, 0 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + Bigfoot::Flat::LogLevelTypeTable + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_ENUM, 6, type_codes, type_refs, nullptr, nullptr, nullptr + }; + return &tt; +} + +} // namespace Flat +} // namespace Bigfoot + +#endif // FLATBUFFERS_GENERATED_LOG_BIGFOOT_FLAT_H_ diff --git a/Bigfoot/Sources/Utils/Include/Utils/Log/TargetLogger_generated.hpp.in b/Bigfoot/Sources/Utils/Include/Utils/Log/TargetLogger_generated.hpp.in new file mode 100644 index 0000000..8977a65 --- /dev/null +++ b/Bigfoot/Sources/Utils/Include/Utils/Log/TargetLogger_generated.hpp.in @@ -0,0 +1,21 @@ +@AUTO_GENERATED_COMMENT@ + +/********************************************************************* + * \file @LOGGER_FILENAME@.generated.hpp + * + *********************************************************************/ +#ifndef BIGFOOT_@LOGGER_FILENAME_UPPER@_GENERATED_HPP +#define BIGFOOT_@LOGGER_FILENAME_UPPER@_GENERATED_HPP +#include + +#if defined BIGFOOT_NOT_OPTIMIZED + +namespace Bigfoot +{ +/* + * Logger + */ +inline Log::LoggerInfo @LOGGER_NAME@ {"@LOGGER_NAME@", Flat::LogLevel::Trace}; +} // namespace Bigfoot +#endif +#endif \ No newline at end of file diff --git a/Bigfoot/Sources/Utils/Include/Utils/Profiler.hpp b/Bigfoot/Sources/Utils/Include/Utils/Profiler.hpp new file mode 100644 index 0000000..2553d62 --- /dev/null +++ b/Bigfoot/Sources/Utils/Include/Utils/Profiler.hpp @@ -0,0 +1,64 @@ +/********************************************************************* + * \file Profiler.hpp + * + * \author Romain BOULLARD + * \date October 2025 + *********************************************************************/ +#ifndef BIGFOOT_UTILS_PROFILER_HPP +#define BIGFOOT_UTILS_PROFILER_HPP + +#ifdef TRACY +#include +#define BIGFOOT_PROFILER_THREADNAME(p_name) tracy::SetThreadName(p_name) + +#define BIGFOOT_PROFILER_FRAME() FrameMark +#define BIGFOOT_PROFILER_FRAME_START(p_name) FrameMarkStart(p_name) +#define BIGFOOT_PROFILER_FRAME_STOP(p_name) FrameMarkEnd(p_name) + +#define BIGFOOT_PROFILER_PROFILE_FUNCTION() ZoneScoped +#define BIGFOOT_PROFILER_PROFILE(p_name) ZoneScopedN(p_name) + +#define BIGFOOT_PROFILER_TEXT(p_text, p_size) ZoneText(p_text, p_size) + +#define BIGFOOT_PROFILER_MEMORY_ALLOC(p_ptr, p_size) TracyAlloc(p_ptr, p_size) +#define BIGFOOT_PROFILER_MEMORY_FREE(p_ptr) TracyFree(p_ptr) + +#define BIGFOOT_PROFILER_LOCKABLE(p_type, p_name) TracyLockable(p_type, p_name) +#define BIGFOOT_PROFILER_LOCK(p_name) LockMark(p_name) + +#define BIGFOOT_PROFILER_APPINFO(p_text, p_size) TracyAppInfo(p_text, p_size) + +#define BIGFOOT_PROFILER_ATTACH_FRAME_IMAGE(p_imageData, p_width, p_height, p_offset) \ + FrameImage(p_imageData, p_width, p_height, p_offset, false) + +#define BIGFOOT_PROFILER + +#define BIGFOOT_PROFILER_ONLY(...) __VA_ARGS__ +// TODO: profile GPU +#else +#define BIGFOOT_PROFILER_THREADNAME(p_name) + +#define BIGFOOT_PROFILER_FRAME() +#define BIGFOOT_PROFILER_FRAME_START(p_name) +#define BIGFOOT_PROFILER_FRAME_STOP(p_name) + +#define BIGFOOT_PROFILER_PROFILE_FUNCTION() +#define BIGFOOT_PROFILER_PROFILE(p_name) + +#define BIGFOOT_PROFILER_TEXT_FUNCTION(p_text, p_size) +#define BIGFOOT_PROFILER_TEXT(p_text, p_size) + +#define BIGFOOT_PROFILER_MEMORY_ALLOC(p_ptr, p_size) +#define BIGFOOT_PROFILER_MEMORY_FREE(p_ptr) + +#define BIGFOOT_PROFILER_LOCKABLE(p_type, p_name) p_type p_name +#define BIGFOOT_PROFILER_LOCK(p_name) + +#define BIGFOOT_PROFILER_APPINFO(p_text, p_size) + +#define BIGFOOT_PROFILER_ATTACH_FRAME_IMAGE(p_imageData, p_width, p_height, p_offset) + +#define BIGFOOT_PROFILER_ONLY(...) +// TODO: profile GPU +#endif +#endif diff --git a/Bigfoot/Sources/Utils/Include/Utils/Singleton.hpp b/Bigfoot/Sources/Utils/Include/Utils/Singleton.hpp index 106eb70..abd933a 100644 --- a/Bigfoot/Sources/Utils/Include/Utils/Singleton.hpp +++ b/Bigfoot/Sources/Utils/Include/Utils/Singleton.hpp @@ -6,12 +6,7 @@ *********************************************************************/ #ifndef BIGFOOT_UTILS_SINGLETON_HPP #define BIGFOOT_UTILS_SINGLETON_HPP - -#include -#include #include -#include -#include namespace Bigfoot { @@ -31,11 +26,21 @@ class Singleton * * \return The instance */ - static constexpr TYPE& Instance() + static constexpr TYPE& GetInstance() { return ms_instance.value(); } + /** + * Is the instance initialized + * + * \return True if initialized, false otherwise + */ + static constexpr bool HasInstance() + { + return ms_instance.has_value(); + } + class Lifetime { public: @@ -44,11 +49,10 @@ class Singleton * * \param p_args Arguments for the singleton */ - template> || ...)>> + template explicit Lifetime(ARGS&&... p_args) { - Initialize(eastl::forward(p_args)...); + Initialize(std::forward(p_args)...); } Lifetime(const Lifetime& p_lifetime) = delete; @@ -59,15 +63,11 @@ class Singleton Finalize(); } - [[nodiscard]] Lifetime& operator=(const Lifetime& p_lifetime) = delete; - [[nodiscard]] - Lifetime& operator=(Lifetime&& p_lifetime) = delete; + Lifetime& operator=(Lifetime&& p_lifetime) noexcept = delete; }; - [[nodiscard]] Singleton& operator=(const Singleton& p_singleton) = delete; - [[nodiscard]] Singleton& operator=(Singleton&& p_singleton) = delete; private: @@ -79,7 +79,7 @@ class Singleton template static void Initialize(ARGS&&... p_args) { - ms_instance.emplace(eastl::forward(p_args)...); + ms_instance.emplace(std::forward(p_args)...); } /** diff --git a/Bigfoot/Sources/Utils/Include/Utils/TaggedType.hpp b/Bigfoot/Sources/Utils/Include/Utils/TaggedType.hpp index a020837..dc5a7e0 100644 --- a/Bigfoot/Sources/Utils/Include/Utils/TaggedType.hpp +++ b/Bigfoot/Sources/Utils/Include/Utils/TaggedType.hpp @@ -4,8 +4,8 @@ * \author Romain BOULLARD * \date December 2025 *********************************************************************/ -#ifndef BIGFOOT_UTILS_TAGGEDTYPE_H -#define BIGFOOT_UTILS_TAGGEDTYPE_H +#ifndef BIGFOOT_UTILS_TAGGEDTYPE_HPP +#define BIGFOOT_UTILS_TAGGEDTYPE_HPP #include diff --git a/Bigfoot/Sources/Utils/Include/Utils/TargetMacros.h b/Bigfoot/Sources/Utils/Include/Utils/TargetMacros.h index 3a95305..cfb649e 100644 --- a/Bigfoot/Sources/Utils/Include/Utils/TargetMacros.h +++ b/Bigfoot/Sources/Utils/Include/Utils/TargetMacros.h @@ -7,6 +7,14 @@ #ifndef BIGFOOT_UTILS_TARGETMACROS_H #define BIGFOOT_UTILS_TARGETMACROS_H +#if defined BIGFOOT_WINDOWS +#define BIGFOOT_WINDOWS_OR_LINUX(p_windows, p_linux) p_windows +#endif + +#if defined BIGFOOT_LINUX +#define BIGFOOT_WINDOWS_OR_LINUX(p_windows, p_linux) p_linux +#endif + #if defined BIGFOOT_OPTIMIZED #define BIGFOOT_OPTIMIZED_ONLY(...) __VA_ARGS__ #define BIGFOOT_NOT_OPTIMIZED_ONLY(...) diff --git a/Bigfoot/Sources/Utils/Include/Utils/UtilsAssertHandler.hpp b/Bigfoot/Sources/Utils/Include/Utils/UtilsAssertHandler.hpp new file mode 100644 index 0000000..7777449 --- /dev/null +++ b/Bigfoot/Sources/Utils/Include/Utils/UtilsAssertHandler.hpp @@ -0,0 +1,52 @@ +/********************************************************************* + * \file UtilsAssertHandler.hpp + * + * \author Romain BOULLARD + * \date May 2026 + *********************************************************************/ +#ifndef BIGFOOT_UTILS_UTILSASSERTHANDLER_HPP +#define BIGFOOT_UTILS_UTILSASSERTHANDLER_HPP +#include +#include + +#if defined BIGFOOT_NOT_OPTIMIZED + +#include +#include + +namespace Bigfoot +{ +class UtilsAssertHandler +{ + public: + UtilsAssertHandler() = delete; + + UtilsAssertHandler(const UtilsAssertHandler& p_handler) = delete; + UtilsAssertHandler(UtilsAssertHandler&& p_handler) = delete; + + ~UtilsAssertHandler() = delete; + + /** + * Handle an assertion. + * + * \param p_location Location of the assertion. + * \param p_format Format string for the assertion message. + * \param p_args Arguments for the format string. + */ + template + static void Handle(const std::source_location& p_location, std::format_string p_format, ARGS&&... p_args) + { + BIGFOOT_LOG_FATAL(UTILS_LOGGER, + "Assert: {} (File:{}, Line:{}, Function:{}\n", + std::format(p_format, std::forward(p_args)...), + p_location.file_name(), + p_location.line(), + p_location.function_name()); + } + + UtilsAssertHandler& operator=(const UtilsAssertHandler& p_handler) = delete; + UtilsAssertHandler& operator=(UtilsAssertHandler&& p_handler) = delete; +}; +} // namespace Bigfoot +#endif +#endif diff --git a/Bigfoot/Sources/Utils/Include/Utils/UtilsLogger_generated.hpp b/Bigfoot/Sources/Utils/Include/Utils/UtilsLogger_generated.hpp new file mode 100644 index 0000000..e58a250 --- /dev/null +++ b/Bigfoot/Sources/Utils/Include/Utils/UtilsLogger_generated.hpp @@ -0,0 +1,21 @@ +// AUTO-GENERATED DO NOT TOUCH + +/********************************************************************* + * \file UtilsLogger.generated.hpp + * + *********************************************************************/ +#ifndef BIGFOOT_UTILSLOGGER_GENERATED_HPP +#define BIGFOOT_UTILSLOGGER_GENERATED_HPP +#include + +#if defined BIGFOOT_NOT_OPTIMIZED + +namespace Bigfoot +{ +/* + * Logger + */ +inline Log::LoggerInfo UTILS_LOGGER {"UTILS_LOGGER", Flat::LogLevel::Trace}; +} // namespace Bigfoot +#endif +#endif diff --git a/Bigfoot/Sources/Utils/Include/Utils/Version.hpp b/Bigfoot/Sources/Utils/Include/Utils/Version.hpp index 68e0bfa..40a3481 100644 --- a/Bigfoot/Sources/Utils/Include/Utils/Version.hpp +++ b/Bigfoot/Sources/Utils/Include/Utils/Version.hpp @@ -53,7 +53,7 @@ class Version * \return The major part of the version. */ [[nodiscard]] - constexpr std::uint8_t Major() const + constexpr std::uint8_t GetMajor() const { constexpr std::uint32_t mask = 0b00000000111111110000000000000000; @@ -66,7 +66,7 @@ class Version * \return The minor part of the version. */ [[nodiscard]] - constexpr std::uint8_t Minor() const + constexpr std::uint8_t GetMinor() const { constexpr std::uint32_t mask = 0b00000000000000001111111100000000; @@ -79,54 +79,37 @@ class Version * \return The patch part of the version. */ [[nodiscard]] - constexpr std::uint8_t Patch() const + constexpr std::uint8_t GetPatch() const { constexpr std::uint32_t mask = 0b00000000000000000000000011111111; return static_cast(m_combined & mask); } + /** + * Gets the raw Version + * + * \return the raw version + */ [[nodiscard]] - constexpr operator std::uint32_t() const + constexpr std::uint32_t Raw() const { return m_combined; } - operator std::string() const; + /** + * Gets the string representation of the Version + * + * \return The string + */ + [[nodiscard]] + std::string ToString() const; constexpr Version& operator=(const Version& p_version) = default; - constexpr Version& operator=(Version&& p_version) = default; [[nodiscard]] - constexpr bool operator>(const Version& p_version) const - { - return m_combined > p_version.m_combined; - } - - [[nodiscard]] - constexpr bool operator<(const Version& p_version) const - { - return m_combined < p_version.m_combined; - } - - [[nodiscard]] - constexpr bool operator>=(const Version& p_version) const - { - return m_combined >= p_version.m_combined; - } - - [[nodiscard]] - constexpr bool operator<=(const Version& p_version) const - { - return m_combined <= p_version.m_combined; - } - - [[nodiscard]] - constexpr bool operator==(const Version& p_version) const = default; - - [[nodiscard]] - constexpr bool operator!=(const Version& p_version) const = default; + constexpr auto operator<=>(const Version& p_version) const = default; private: /** @@ -151,7 +134,7 @@ struct std::formatter template auto format(const Bigfoot::Version& p_version, FormatContext& p_context) const { - return std::format_to(p_context.out(), "{}", static_cast(p_version)); + return std::format_to(p_context.out(), "{}", p_version.ToString()); } }; #endif diff --git a/Bigfoot/Sources/Utils/Log/Log.cpp b/Bigfoot/Sources/Utils/Log/Log.cpp new file mode 100644 index 0000000..033594b --- /dev/null +++ b/Bigfoot/Sources/Utils/Log/Log.cpp @@ -0,0 +1,112 @@ +/******************************************************************* + * \file Log.cpp + * + * \author Romain BOULLARD + * \date October 2025 + *********************************************************************/ +#include + +#if defined BIGFOOT_NOT_OPTIMIZED + +namespace Bigfoot +{ +Log::Log() +{ + quill::Backend::start(); + + m_sinks[static_cast(Flat::LogSinkType::Console)] = + quill::Frontend::create_or_get_sink( + std::string {Flat::EnumNameLogSinkType(Flat::LogSinkType::Console)}); +} + +/****************************************************************************************/ + +quill::Logger* Log::RegisterLogger(const LoggerInfo& p_loggerInfo) +{ + quill::Logger* logger = quill::Frontend::create_or_get_logger( + p_loggerInfo.m_name, + m_sinks[static_cast(Flat::LogSinkType::Console)]); + SetLoggerLevel(p_loggerInfo); + + return logger; +} + +/****************************************************************************************/ + +void Log::UnregisterLogger(const LoggerInfo& p_loggerInfo) +{ + if (quill::Logger* logger = quill::Frontend::get_logger(p_loggerInfo.m_name)) + { + quill::Frontend::remove_logger_blocking(logger); + } +} + +/****************************************************************************************/ + +quill::Logger* Log::GetLogger(const LoggerInfo& p_loggerInfo) +{ + return quill::Frontend::get_logger(p_loggerInfo.m_name); +} + +/****************************************************************************************/ + +void Log::ChangeLoggerLogLevel(LoggerInfo& p_loggerInfo, const Flat::LogLevel p_level) +{ + p_loggerInfo.m_level = p_level; + SetLoggerLevel(p_loggerInfo); +} + +/****************************************************************************************/ + +void Log::SetLoggerLevel(const LoggerInfo& p_loggerInfo) +{ + constexpr auto logLevelToQuillLogLevel = [](const Flat::LogLevel p_level) constexpr -> quill::LogLevel + { + switch (p_level) + { + case Flat::LogLevel::Debug: + return quill::LogLevel::Debug; + case Flat::LogLevel::Trace: + return quill::LogLevel::TraceL3; + case Flat::LogLevel::Info: + return quill::LogLevel::Info; + case Flat::LogLevel::Warn: + return quill::LogLevel::Warning; + case Flat::LogLevel::Error: + return quill::LogLevel::Error; + case Flat::LogLevel::Critical: + return quill::LogLevel::Critical; + } + + return quill::LogLevel::TraceL3; + }; + + if (quill::Logger* logger = GetLogger(p_loggerInfo)) + { + logger->set_log_level(logLevelToQuillLogLevel(p_loggerInfo.m_level)); + } +} + +/****************************************************************************************/ + +void Log::Flush() +{ + for (quill::Logger* logger: quill::Frontend::get_all_loggers()) + { + logger->flush_log(); + } +} + +/****************************************************************************************/ + +Log::~Log() +{ + Flush(); + for (quill::Logger* logger: quill::Frontend::get_all_loggers()) + { + quill::Frontend::remove_logger_blocking(logger); + } + quill::Backend::stop(); +} +} // namespace Bigfoot +#endif diff --git a/Bigfoot/Sources/Utils/MimallocImpl.cpp b/Bigfoot/Sources/Utils/MimallocImpl.cpp new file mode 100644 index 0000000..71fda4e --- /dev/null +++ b/Bigfoot/Sources/Utils/MimallocImpl.cpp @@ -0,0 +1,98 @@ +/********************************************************************* + * \file MimallocImpl.cpp + * + * \author Romain BOULLARD + * \date October 2025 + *********************************************************************/ +#include + +#if defined BIGFOOT_WINDOWS +#pragma comment(linker, "/include:mi_version") +#pragma warning(disable: 4100 4559) +#elif defined BIGFOOT_LINUX +#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif +#endif + +// Taken from mimalloc-new-delete.h + +// clang-format off + +// ---------------------------------------------------------------------------- +// This header provides convenient overrides for the new and +// delete operations in C++. +// +// This header should be included in only one source file! +// +// On Windows, or when linking dynamically with mimalloc, these +// can be more performant than the standard new-delete operations. +// See +// --------------------------------------------------------------------------- +#if defined(__cplusplus) + #include + #include + + #if defined(_MSC_VER) && defined(_Ret_notnull_) && defined(_Post_writable_byte_size_) + // stay consistent with VCRT definitions + #define mi_decl_new(n) mi_decl_nodiscard mi_decl_restrict _Ret_notnull_ _Post_writable_byte_size_(n) + #define mi_decl_new_nothrow(n) mi_decl_nodiscard mi_decl_restrict _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(n) + #else + #define mi_decl_new(n) mi_decl_nodiscard mi_decl_restrict + #define mi_decl_new_nothrow(n) mi_decl_nodiscard mi_decl_restrict + #endif + + void operator delete(void* p) noexcept { mi_free(p); BIGFOOT_PROFILER_MEMORY_FREE(p); }; + void operator delete[](void* p) noexcept { mi_free(p); BIGFOOT_PROFILER_MEMORY_FREE(p); }; + + void operator delete (void* p, const std::nothrow_t&) noexcept { mi_free(p); BIGFOOT_PROFILER_MEMORY_FREE(p); } + void operator delete[](void* p, const std::nothrow_t&) noexcept { mi_free(p); BIGFOOT_PROFILER_MEMORY_FREE(p); } + + mi_decl_new(n) void* operator new(std::size_t n) noexcept(false) { void* p = mi_new(n); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; } + mi_decl_new(n) void* operator new[](std::size_t n) noexcept(false) { void* p = mi_new(n); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; } + + mi_decl_new_nothrow(n) void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); void* p = mi_new_nothrow(n); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; } + mi_decl_new_nothrow(n) void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); void* p = mi_new_nothrow(n); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; } + + // Not from mimalloc-new-delete.h, but necessary for EASTL + void* operator new[](size_t size, const char* name, int flags, unsigned debugFlags, const char* file, int line) noexcept(false) { void* p = mi_new(size); BIGFOOT_PROFILER_MEMORY_ALLOC(p, size); return p; } + + #if (__cplusplus >= 201402L || _MSC_VER >= 1916) + void operator delete (void* p, std::size_t n) noexcept { mi_free_size(p,n); BIGFOOT_PROFILER_MEMORY_FREE(p); }; + void operator delete[](void* p, std::size_t n) noexcept { mi_free_size(p,n); BIGFOOT_PROFILER_MEMORY_FREE(p); }; + #endif + + #if (__cplusplus > 201402L || defined(__cpp_aligned_new)) + void operator delete (void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); } + void operator delete[](void* p, std::align_val_t al) noexcept { mi_free_aligned(p, static_cast(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); } + void operator delete (void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); }; + void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); }; + void operator delete (void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); } + void operator delete[](void* p, std::align_val_t al, const std::nothrow_t&) noexcept { mi_free_aligned(p, static_cast(al)); BIGFOOT_PROFILER_MEMORY_FREE(p); } + + void* operator new (std::size_t n, std::align_val_t al) noexcept(false) { void* p = mi_new_aligned(n, static_cast(al)); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; } + void* operator new[](std::size_t n, std::align_val_t al) noexcept(false) { void* p = mi_new_aligned(n, static_cast(al)); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; } + void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { void* p = mi_new_aligned_nothrow(n, static_cast(al)); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; } + void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { void* p = mi_new_aligned_nothrow(n, static_cast(al)); BIGFOOT_PROFILER_MEMORY_ALLOC(p, n); return p; } + + // Not from mimalloc-new-delete.h, but necessary for EASTL + void* operator new[](size_t size, size_t alignment, size_t alignmentOffset, const char* pName, int flags, unsigned debugFlags, const char* file, int line) noexcept(false) { void* p = mi_new_aligned(size, alignment); BIGFOOT_PROFILER_MEMORY_ALLOC(p, size); return p; } + #endif + +#endif + +// clang-format on + +#if defined BIGFOOT_WINDOWS +#pragma warning(default: 4100 4559) +#elif defined BIGFOOT_LINUX +#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) +#pragma GCC diagnostic pop +#else +#pragma clang diagnostic pop +#endif +#endif diff --git a/Bigfoot/Sources/Utils/Version.cpp b/Bigfoot/Sources/Utils/Version.cpp index 678b2fc..6423659 100644 --- a/Bigfoot/Sources/Utils/Version.cpp +++ b/Bigfoot/Sources/Utils/Version.cpp @@ -8,8 +8,8 @@ namespace Bigfoot { -Version::operator std::string() const +std::string Version::ToString() const { - return std::format("{}.{}.{}", Major(), Minor(), Patch()); + return std::format("{}.{}.{}", GetMajor(), GetMinor(), GetPatch()); } } // namespace Bigfoot diff --git a/Bigfoot/Tests/CMakeLists.txt b/Bigfoot/Tests/CMakeLists.txt index bdd68d7..cbbb5ea 100644 --- a/Bigfoot/Tests/CMakeLists.txt +++ b/Bigfoot/Tests/CMakeLists.txt @@ -1,3 +1,5 @@ -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Misc) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine) \ No newline at end of file diff --git a/Bigfoot/Tests/Engine/Asset/Asset.cpp b/Bigfoot/Tests/Engine/Asset/Asset.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Bigfoot/Tests/Engine/Asset/AssetContainer.cpp b/Bigfoot/Tests/Engine/Asset/AssetContainer.cpp new file mode 100644 index 0000000..c5f9ff4 --- /dev/null +++ b/Bigfoot/Tests/Engine/Asset/AssetContainer.cpp @@ -0,0 +1,109 @@ +/********************************************************************* + * \file AssetContainer.cpp + * + * \author Romain BOULLARD + * \date July 2026 + *********************************************************************/ +#include + +#include +#include + +namespace Bigfoot +{ +class AssetContainerFixture: public ::testing::Test +{ + protected: + AssetContainer m_containerA; +}; + +/****************************************************************************************/ + +TEST_F(AssetContainerFixture, Has_ShouldReturnTrueIfTheContainerHasTheAsset) +{ + AssetA asset1; + std::ignore = m_containerA.Insert(asset1); + EXPECT_TRUE(m_containerA.Has(asset1.GetHeader().uuid)); +} + +/****************************************************************************************/ + +TEST_F(AssetContainerFixture, Has_ShouldReturnFalseIfTheContainerDoesNotHaveTheAsset) +{ + AssetA asset1; + EXPECT_FALSE(m_containerA.Has(asset1.GetHeader().uuid)); +} + +/****************************************************************************************/ + +TEST_F(AssetContainerFixture, AcquireHandle_ShouldReturnTheAssociatedContainerHandle) +{ + AssetA asset1; + std::ignore = m_containerA.Insert(asset1); + + const ContainerHandle& handle = m_containerA.AcquireContainerHandle(asset1.GetHeader().uuid); + EXPECT_EQ(static_cast(handle.GetAsset())->GetHeader().uuid, asset1.GetHeader().uuid); +} + +/****************************************************************************************/ + +TEST_F(AssetContainerFixture, AcquireHandle_ShouldCreateTheAssociatedContainerHandleIfItDoesNotExists) +{ + AssetA asset1; + + const ContainerHandle& handle = m_containerA.AcquireContainerHandle(asset1.GetHeader().uuid); + EXPECT_EQ(handle.GetAsset(), nullptr); +} + +/****************************************************************************************/ + +TEST_F(AssetContainerFixture, Insert_ShouldReturnValidAndUniqueSlotKeyOnInsert) +{ + AssetA asset1; + const SlotMapKey slotKey = m_containerA.Insert(asset1); + EXPECT_TRUE(slotKey.Valid()); + EXPECT_NE(slotKey, m_containerA.Insert()); +} + +/****************************************************************************************/ + +TEST_F(AssetContainerFixture, Insert_ShouldReturnTheSameSlotKeyInCaseOfDuplicatedUUID) +{ + AssetA asset; + const SlotMapKey slotKey = m_containerA.Insert(asset); + EXPECT_EQ(slotKey, m_containerA.Insert(asset)); +} + +/****************************************************************************************/ + +TEST_F(AssetContainerFixture, Get_ShouldReturnTheAssetWithTheSlotKey) +{ + AssetA asset; + const SlotMapKey slotKey = m_containerA.Insert(asset); + + EXPECT_EQ(m_containerA.Get(slotKey)->GetHeader().uuid, asset.GetHeader().uuid); + EXPECT_EQ(const_cast&>(m_containerA).Get(slotKey)->GetHeader().uuid, + asset.GetHeader().uuid); +} + +/****************************************************************************************/ + +TEST_F(AssetContainerFixture, Get_ShouldReturnNullptrIfSlotKeyNotInContainer) +{ + EXPECT_EQ(m_containerA.Get(SlotMapKey {1, 0}), nullptr); + EXPECT_EQ(const_cast&>(m_containerA).Get(SlotMapKey {1, 0}), nullptr); +} + +/****************************************************************************************/ + +TEST_F(AssetContainerFixture, Remove_ShouldRemoveTheAsset) +{ + AssetA asset; + const SlotMapKey slotKey = m_containerA.Insert(asset); + + m_containerA.Remove(asset.GetHeader().uuid); + + EXPECT_EQ(m_containerA.Get(slotKey), nullptr); + EXPECT_FALSE(m_containerA.Has(asset.GetHeader().uuid)); +} +} // namespace Bigfoot diff --git a/Bigfoot/Tests/Engine/Asset/AssetLibrary.cpp b/Bigfoot/Tests/Engine/Asset/AssetLibrary.cpp new file mode 100644 index 0000000..068e76b --- /dev/null +++ b/Bigfoot/Tests/Engine/Asset/AssetLibrary.cpp @@ -0,0 +1,135 @@ +/********************************************************************* + * \file AssetLibrary.cpp + * + * \author Romain BOULLARD + * \date July 2026 + *********************************************************************/ +#include + +#include +#include +#include +#include + +namespace Bigfoot +{ +class AssetLibraryFixture: public ::testing::Test +{ + protected: + AssetContainer m_containerA; + AssetContainer m_containerB; + AssetContainer m_containerC; + + AssetLibrary m_library; +}; + +/****************************************************************************************/ + +TEST_F(AssetLibraryFixture, Insert_ShouldReturnTrueOnSuccess) +{ + EXPECT_TRUE(m_library.Insert(&m_containerA)); + EXPECT_TRUE(m_library.Insert(&m_containerB)); + EXPECT_TRUE(m_library.Insert(&m_containerC)); +} + +/****************************************************************************************/ + +TEST_F(AssetLibraryFixture, Insert_ShouldReturnFalseOnDuplicate) +{ + std::ignore = m_library.Insert(&m_containerA); + EXPECT_FALSE(m_library.Insert(&m_containerA)); + + AssetContainer m_containerAA; + EXPECT_FALSE(m_library.Insert(&m_containerAA)); +} + +/****************************************************************************************/ + +TEST_F(AssetLibraryFixture, GetAssetContainer_ShouldReturnTheAssetContainerIfAvailable) +{ + std::ignore = m_library.Insert(&m_containerA); + std::ignore = m_library.Insert(&m_containerB); + std::ignore = m_library.Insert(&m_containerC); + + EXPECT_EQ(m_library.GetAssetContainer(), &m_containerA); + EXPECT_EQ(m_library.GetAssetContainer(GetAssetTypeID()), &m_containerA); + EXPECT_EQ(m_library.GetAssetContainer(), &m_containerB); + EXPECT_EQ(m_library.GetAssetContainer(GetAssetTypeID()), &m_containerB); + EXPECT_EQ(m_library.GetAssetContainer(), &m_containerC); + EXPECT_EQ(m_library.GetAssetContainer(GetAssetTypeID()), &m_containerC); + + EXPECT_EQ(const_cast(m_library).GetAssetContainer(), &m_containerA); + EXPECT_EQ(const_cast(m_library).GetAssetContainer(GetAssetTypeID()), &m_containerA); + EXPECT_EQ(const_cast(m_library).GetAssetContainer(), &m_containerB); + EXPECT_EQ(const_cast(m_library).GetAssetContainer(GetAssetTypeID()), &m_containerB); + EXPECT_EQ(const_cast(m_library).GetAssetContainer(), &m_containerC); + EXPECT_EQ(const_cast(m_library).GetAssetContainer(GetAssetTypeID()), &m_containerC); +} + +/****************************************************************************************/ + +TEST_F(AssetLibraryFixture, GetAssetContainer_ShouldReturnNullptrIfTheContainerDoesNotExist) +{ + std::ignore = m_library.Insert(&m_containerB); + + EXPECT_EQ(m_library.GetAssetContainer(), nullptr); + EXPECT_EQ(m_library.GetAssetContainer(GetAssetTypeID()), nullptr); + + EXPECT_EQ(const_cast(m_library).GetAssetContainer(), nullptr); + EXPECT_EQ(const_cast(m_library).GetAssetContainer(GetAssetTypeID()), nullptr); +} + +/****************************************************************************************/ + +TEST_F(AssetLibraryFixture, FindAssetContainerContainerForUUID_ShouldReturnTheAssetContainerIfAvailable) +{ + std::ignore = m_library.Insert(&m_containerA); + std::ignore = m_library.Insert(&m_containerB); + std::ignore = m_library.Insert(&m_containerC); + + const SlotMapKey keyA = m_containerA.Insert(); + const SlotMapKey keyB = m_containerB.Insert(); + const SlotMapKey keyC = m_containerC.Insert(); + + const UUID uuidA = m_containerA.Get(keyA)->GetHeader().uuid; + const UUID uuidB = m_containerB.Get(keyB)->GetHeader().uuid; + const UUID uuidC = m_containerC.Get(keyC)->GetHeader().uuid; + + EXPECT_EQ(m_library.FindAssetContainerContainerForUUID(uuidA), &m_containerA); + EXPECT_EQ(m_library.FindAssetContainerContainerForUUID(uuidB), &m_containerB); + EXPECT_EQ(m_library.FindAssetContainerContainerForUUID(uuidC), &m_containerC); + + EXPECT_EQ(const_cast(m_library).FindAssetContainerContainerForUUID(uuidA), &m_containerA); + EXPECT_EQ(const_cast(m_library).FindAssetContainerContainerForUUID(uuidB), &m_containerB); + EXPECT_EQ(const_cast(m_library).FindAssetContainerContainerForUUID(uuidC), &m_containerC); +} + +/****************************************************************************************/ + +TEST_F(AssetLibraryFixture, FindAssetContainerContainerForUUID_ShouldReturnNullptrIfTheContainerDoesNotExist) +{ + std::ignore = m_library.Insert(&m_containerA); + std::ignore = m_library.Insert(&m_containerB); + std::ignore = m_library.Insert(&m_containerC); + + std::ignore = m_containerA.Insert(); + std::ignore = m_containerB.Insert(); + std::ignore = m_containerC.Insert(); + + EXPECT_EQ(m_library.FindAssetContainerContainerForUUID(UUID {}), nullptr); + + EXPECT_EQ(const_cast(m_library).FindAssetContainerContainerForUUID(UUID {}), nullptr); +} + +/****************************************************************************************/ + +TEST_F(AssetLibraryFixture, ScopedActiveAssetLibrary_ShouldChangeTheActiveAssetLibraryInAScopedWay) +{ + EXPECT_EQ(g_activeAssetLibrary, &g_assetLibrary); + { + ScopedActiveAssetLibrary activeAssetLibraryScoped {&m_library}; + EXPECT_EQ(g_activeAssetLibrary, &m_library); + } + EXPECT_EQ(g_activeAssetLibrary, &g_assetLibrary); +} +} // namespace Bigfoot diff --git a/Bigfoot/Tests/Engine/Asset/Reference.cpp b/Bigfoot/Tests/Engine/Asset/Reference.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Bigfoot/Tests/Engine/BigFile/BigFile.cpp b/Bigfoot/Tests/Engine/BigFile/BigFile.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Bigfoot/Tests/Engine/CMakeLists.txt b/Bigfoot/Tests/Engine/CMakeLists.txt index 36652b4..89333e5 100644 --- a/Bigfoot/Tests/Engine/CMakeLists.txt +++ b/Bigfoot/Tests/Engine/CMakeLists.txt @@ -1,15 +1,13 @@ get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME) project(${PackageName}Tests) +set(Dependencies) set(BigfootDependencies - Engine - System - Utils) - -bigfoot_create_bigfile("Tests/Bigfoot") + AssetsForTesting) bigfoot_create_package_tests( - "" - "${BigfootDependencies}") + "${Dependencies}" + "${BigfootDependencies}" + "") -bigfoot_setup_dependencies("Tests/Bigfoot") \ No newline at end of file +bigfoot_create_bigfile("Tests/Bigfoot") \ No newline at end of file diff --git a/Bigfoot/Tests/Engine/EngineTests/main.cpp b/Bigfoot/Tests/Engine/EngineTests/main.cpp new file mode 100644 index 0000000..6645ee3 --- /dev/null +++ b/Bigfoot/Tests/Engine/EngineTests/main.cpp @@ -0,0 +1,19 @@ +/********************************************************************* + * \file main.cpp + * + * \author Romain BOULLARD + * \date May 2026 + *********************************************************************/ +#include +#include + +#include + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + + BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime); + + return RUN_ALL_TESTS(); +} diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Asset/AssetA.cpp b/Bigfoot/Tests/Misc/AssetsForTesting/Asset/AssetA.cpp new file mode 100644 index 0000000..6c2a0d1 --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Asset/AssetA.cpp @@ -0,0 +1,11 @@ +/********************************************************************* + * \file AssetA.cpp + * + * \author Romain BOULLARD + * \date July 2026 + *********************************************************************/ +#include + +#include + +BIGFOOT_ASSET(AssetA, ::Bigfoot::AssetA) diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Asset/AssetB.cpp b/Bigfoot/Tests/Misc/AssetsForTesting/Asset/AssetB.cpp new file mode 100644 index 0000000..9d14fa7 --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Asset/AssetB.cpp @@ -0,0 +1,11 @@ +/********************************************************************* + * \file AssetB.cpp + * + * \author Romain BOULLARD + * \date July 2026 + *********************************************************************/ +#include + +#include + +BIGFOOT_ASSET(AssetB, ::Bigfoot::AssetB) diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Asset/AssetC.cpp b/Bigfoot/Tests/Misc/AssetsForTesting/Asset/AssetC.cpp new file mode 100644 index 0000000..bb2d42d --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Asset/AssetC.cpp @@ -0,0 +1,11 @@ +/********************************************************************* + * \file AssetC.cpp + * + * \author Romain BOULLARD + * \date July 2026 + *********************************************************************/ +#include + +#include + +BIGFOOT_ASSET(AssetC, ::Bigfoot::AssetC) diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/CMakeLists.txt b/Bigfoot/Tests/Misc/AssetsForTesting/CMakeLists.txt new file mode 100644 index 0000000..c38a828 --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/CMakeLists.txt @@ -0,0 +1,15 @@ +get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +project(${PackageName}) + +set(PublicDependencies) +set(PrivateDependencies) +set(BigfootPublicDependencies) +set(BigfootPrivateDependencies + Engine) + +bigfoot_create_package_tests_helper_lib( + "${PublicDependencies}" + "${PrivateDependencies}" + "${BigfootPublicDependencies}" + "${BigfootPrivateDependencies}" + "") \ No newline at end of file diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetA.fbs b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetA.fbs new file mode 100644 index 0000000..b778ca5 --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetA.fbs @@ -0,0 +1,13 @@ +include "Engine/Asset/Reference.fbs"; + +namespace Flat.Bigfoot; + +table AssetA +{ + health: uint = 0; + mana: uint = 0; + + ref_a: SoftReference (native_inline, bigfoot_ref: "::Bigfoot::AssetA"); +} + +root_type AssetA; \ No newline at end of file diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetA.hpp b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetA.hpp new file mode 100644 index 0000000..245c486 --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetA.hpp @@ -0,0 +1,40 @@ +/********************************************************************* + * \file AssetA.hpp + * + * \author Romain BOULLARD + * \date April 2026 + *********************************************************************/ +#ifndef BIGFOOT_ASSETSFORTESTING_ASSET_ASSETA_HPP +#define BIGFOOT_ASSETSFORTESTING_ASSET_ASSETA_HPP +#include + +#include + +namespace Bigfoot +{ +struct AssetATraits +{ + using FLAT = ::Flat::Bigfoot::AssetA; +}; + +class AssetA: public Asset +{ + public: + AssetA() = default; + + AssetA(const eastl::span p_flatbuffer): + Asset(p_flatbuffer) + { + } + + AssetA(const AssetA& p_asset) = default; + AssetA(AssetA&& p_asset) = default; + + ~AssetA() = default; + + AssetA& operator=(const AssetA& p_asset) = default; + AssetA& operator=(AssetA&& p_asset) = default; +}; +} // namespace Bigfoot + +#endif diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetA_generated.hpp b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetA_generated.hpp new file mode 100644 index 0000000..b1004e0 --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetA_generated.hpp @@ -0,0 +1,251 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_ASSETA_FLAT_BIGFOOT_H_ +#define FLATBUFFERS_GENERATED_ASSETA_FLAT_BIGFOOT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && + FLATBUFFERS_VERSION_MINOR == 12 && + FLATBUFFERS_VERSION_REVISION == 19, + "Non-compatible flatbuffers version included"); +// Ensure the included flatbuffers.h is Bigfoot's fork - stock +// flatbuffers (or a differently versioned Bigfoot fork) is not compatible. +#ifndef FLATBUFFERS_BIGFOOT_VERSION +#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible" +#endif +static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1, + "Non-compatible Bigfoot flatbuffers fork version included"); + +#include "System/UUID/UUID.hpp" +#include "Engine/Asset/Reference.hpp" +#include "Engine/Asset/Reference_generated.hpp" + +#include "EASTL/unique_ptr.h" +#include "EASTL/string.h" +#include "EASTL/vector.h" + +namespace Flat { +namespace Bigfoot { + +struct AssetA; +struct AssetABuilder; +struct AssetAT; + +} // namespace Bigfoot +} // namespace Flat + +namespace Bigfoot { +class AssetA; +} // namespace Bigfoot + +namespace flatbuffers { +Flat::Bigfoot::SoftReference PackSoftReferenceAssetA(const ::Bigfoot::SoftReference<::Bigfoot::AssetA>& p_asset); +::Bigfoot::SoftReference<::Bigfoot::AssetA> UnPackSoftReferenceAssetA(const Flat::Bigfoot::SoftReference& p_asset); +} // namespace flatbuffers + +namespace Flat { +namespace Bigfoot { + +inline const ::flatbuffers::TypeTable *AssetATypeTable(); + +struct AssetAT : public ::flatbuffers::NativeTable { + typedef AssetA TableType; + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.AssetAT"; + } + uint32_t health = 0; + uint32_t mana = 0; + ::Bigfoot::SoftReference<::Bigfoot::AssetA> ref_a{}; +}; + +struct AssetA FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef AssetAT NativeTableType; + typedef AssetABuilder Builder; + struct Traits; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return AssetATypeTable(); + } + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.AssetA"; + } + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_HEALTH = 4, + VT_MANA = 6, + VT_REF_A = 8 + }; + uint32_t health() const { + return GetField(VT_HEALTH, 0); + } + uint32_t mana() const { + return GetField(VT_MANA, 0); + } + const Flat::Bigfoot::SoftReference *ref_a() const { + return GetStruct(VT_REF_A); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_HEALTH, 4) && + VerifyField(verifier, VT_MANA, 4) && + VerifyField(verifier, VT_REF_A, 1) && + verifier.EndTable(); + } + AssetAT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AssetAT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AssetAT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AssetABuilder { + typedef AssetA Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_health(uint32_t health) { + fbb_.AddElement(AssetA::VT_HEALTH, health, 0); + } + void add_mana(uint32_t mana) { + fbb_.AddElement(AssetA::VT_MANA, mana, 0); + } + void add_ref_a(const Flat::Bigfoot::SoftReference *ref_a) { + fbb_.AddStruct(AssetA::VT_REF_A, ref_a); + } + explicit AssetABuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateAssetA( + ::flatbuffers::FlatBufferBuilder &_fbb, + uint32_t health = 0, + uint32_t mana = 0, + const Flat::Bigfoot::SoftReference *ref_a = nullptr) { + AssetABuilder builder_(_fbb); + builder_.add_ref_a(ref_a); + builder_.add_mana(mana); + builder_.add_health(health); + return builder_.Finish(); +} + +struct AssetA::Traits { + using type = AssetA; + static auto constexpr Create = CreateAssetA; +}; + +::flatbuffers::Offset CreateAssetA(::flatbuffers::FlatBufferBuilder &_fbb, const AssetAT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + +inline AssetAT *AssetA::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::make_unique(); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void AssetA::UnPackTo(AssetAT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = health(); _o->health = _e; } + { auto _e = mana(); _o->mana = _e; } + { auto _e = ref_a(); if (_e) _o->ref_a = ::flatbuffers::UnPackSoftReferenceAssetA(*_e); } +} + +inline ::flatbuffers::Offset CreateAssetA(::flatbuffers::FlatBufferBuilder &_fbb, const AssetAT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return AssetA::Pack(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset AssetA::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AssetAT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const AssetAT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _health = _o->health; + auto _mana = _o->mana; + auto _ref_a = ::flatbuffers::PackSoftReferenceAssetA(_o->ref_a); + return Flat::Bigfoot::CreateAssetA( + _fbb, + _health, + _mana, + &_ref_a); +} + +inline const ::flatbuffers::TypeTable *AssetATypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_UINT, 0, -1 }, + { ::flatbuffers::ET_UINT, 0, -1 }, + { ::flatbuffers::ET_SEQUENCE, 0, 0 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + Flat::Bigfoot::SoftReferenceTypeTable + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_TABLE, 3, type_codes, type_refs, nullptr, nullptr, nullptr + }; + return &tt; +} + +inline const Flat::Bigfoot::AssetA *GetAssetA(const void *buf) { + return ::flatbuffers::GetRoot(buf); +} + +inline const Flat::Bigfoot::AssetA *GetSizePrefixedAssetA(const void *buf) { + return ::flatbuffers::GetSizePrefixedRoot(buf); +} + +template +inline bool VerifyAssetABuffer( + ::flatbuffers::VerifierTemplate &verifier) { + return verifier.template VerifyBuffer(nullptr); +} + +template +inline bool VerifySizePrefixedAssetABuffer( + ::flatbuffers::VerifierTemplate &verifier) { + return verifier.template VerifySizePrefixedBuffer(nullptr); +} + +inline const char *AssetAExtension() { + return "bfbs"; +} + +inline void FinishAssetABuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.Finish(root); +} + +inline void FinishSizePrefixedAssetABuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root); +} + +inline eastl::unique_ptr UnPackAssetA( + const void *buf, + const ::flatbuffers::resolver_function_t *res = nullptr) { + return eastl::unique_ptr(GetAssetA(buf)->UnPack(res)); +} + +inline eastl::unique_ptr UnPackSizePrefixedAssetA( + const void *buf, + const ::flatbuffers::resolver_function_t *res = nullptr) { + return eastl::unique_ptr(GetSizePrefixedAssetA(buf)->UnPack(res)); +} + +} // namespace Bigfoot +} // namespace Flat + +namespace flatbuffers { +#ifndef FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA +#define FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA +inline Flat::Bigfoot::SoftReference PackSoftReferenceAssetA(const ::Bigfoot::SoftReference<::Bigfoot::AssetA>& p_asset) { return {Pack(p_asset.GetUUID())}; } +inline ::Bigfoot::SoftReference<::Bigfoot::AssetA> UnPackSoftReferenceAssetA(const Flat::Bigfoot::SoftReference& p_asset) { return {UnPack(p_asset.uuid())}; } +#endif // FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA +} // namespace flatbuffers + +#endif // FLATBUFFERS_GENERATED_ASSETA_FLAT_BIGFOOT_H_ diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetB.fbs b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetB.fbs new file mode 100644 index 0000000..3cc2362 --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetB.fbs @@ -0,0 +1,11 @@ +include "Engine/Asset/Reference.fbs"; + +namespace Flat.Bigfoot; + +table AssetB +{ + ref_a: HardReference (native_inline, bigfoot_ref: "::Bigfoot::AssetA"); + refs_a: [SoftReference] (native_inline, bigfoot_ref: "::Bigfoot::AssetA"); +} + +root_type AssetB; \ No newline at end of file diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetB.hpp b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetB.hpp new file mode 100644 index 0000000..cc87034 --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetB.hpp @@ -0,0 +1,40 @@ +/********************************************************************* + * \file AssetB.hpp + * + * \author Romain BOULLARD + * \date April 2026 + *********************************************************************/ +#ifndef BIGFOOT_ASSETSFORTESTING_ASSET_ASSETB_HPP +#define BIGFOOT_ASSETSFORTESTING_ASSET_ASSETB_HPP +#include + +#include + +namespace Bigfoot +{ +struct AssetBTraits +{ + using FLAT = ::Flat::Bigfoot::AssetB; +}; + +class AssetB: public Asset +{ + public: + AssetB() = default; + + AssetB(const eastl::span p_flatbuffer): + Asset(p_flatbuffer) + { + } + + AssetB(const AssetB& p_asset) = delete; + AssetB(AssetB&& p_asset) = default; + + ~AssetB() = default; + + AssetB& operator=(const AssetB& p_asset) = delete; + AssetB& operator=(AssetB&& p_asset) = default; +}; +} // namespace Bigfoot + +#endif diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetB_generated.hpp b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetB_generated.hpp new file mode 100644 index 0000000..9a55a7f --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetB_generated.hpp @@ -0,0 +1,245 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_ASSETB_FLAT_BIGFOOT_H_ +#define FLATBUFFERS_GENERATED_ASSETB_FLAT_BIGFOOT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && + FLATBUFFERS_VERSION_MINOR == 12 && + FLATBUFFERS_VERSION_REVISION == 19, + "Non-compatible flatbuffers version included"); +// Ensure the included flatbuffers.h is Bigfoot's fork - stock +// flatbuffers (or a differently versioned Bigfoot fork) is not compatible. +#ifndef FLATBUFFERS_BIGFOOT_VERSION +#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible" +#endif +static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1, + "Non-compatible Bigfoot flatbuffers fork version included"); + +#include "System/UUID/UUID.hpp" +#include "Engine/Asset/Reference.hpp" +#include "Engine/Asset/Reference_generated.hpp" + +#include "EASTL/unique_ptr.h" +#include "EASTL/string.h" +#include "EASTL/vector.h" + +namespace Flat { +namespace Bigfoot { + +struct AssetB; +struct AssetBBuilder; +struct AssetBT; + +} // namespace Bigfoot +} // namespace Flat + +namespace Bigfoot { +class AssetA; +} // namespace Bigfoot + +namespace flatbuffers { +Flat::Bigfoot::HardReference PackHardReferenceAssetA(const ::Bigfoot::HardReference<::Bigfoot::AssetA>& p_asset); +::Bigfoot::HardReference<::Bigfoot::AssetA> UnPackHardReferenceAssetA(const Flat::Bigfoot::HardReference& p_asset); +Flat::Bigfoot::SoftReference PackSoftReferenceAssetA(const ::Bigfoot::SoftReference<::Bigfoot::AssetA>& p_asset); +::Bigfoot::SoftReference<::Bigfoot::AssetA> UnPackSoftReferenceAssetA(const Flat::Bigfoot::SoftReference& p_asset); +} // namespace flatbuffers + +namespace Flat { +namespace Bigfoot { + +inline const ::flatbuffers::TypeTable *AssetBTypeTable(); + +struct AssetBT : public ::flatbuffers::NativeTable { + typedef AssetB TableType; + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.AssetBT"; + } + ::Bigfoot::HardReference<::Bigfoot::AssetA> ref_a{}; + eastl::vector<::Bigfoot::SoftReference<::Bigfoot::AssetA>> refs_a{}; +}; + +struct AssetB FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef AssetBT NativeTableType; + typedef AssetBBuilder Builder; + struct Traits; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return AssetBTypeTable(); + } + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.AssetB"; + } + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_REF_A = 4, + VT_REFS_A = 6 + }; + const Flat::Bigfoot::HardReference *ref_a() const { + return GetStruct(VT_REF_A); + } + const ::flatbuffers::Vector *refs_a() const { + return GetPointer *>(VT_REFS_A); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_REF_A, 1) && + VerifyOffset(verifier, VT_REFS_A) && + verifier.VerifyVector(refs_a()) && + verifier.EndTable(); + } + AssetBT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AssetBT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AssetBT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AssetBBuilder { + typedef AssetB Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_ref_a(const Flat::Bigfoot::HardReference *ref_a) { + fbb_.AddStruct(AssetB::VT_REF_A, ref_a); + } + void add_refs_a(::flatbuffers::Offset<::flatbuffers::Vector> refs_a) { + fbb_.AddOffset(AssetB::VT_REFS_A, refs_a); + } + explicit AssetBBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateAssetB( + ::flatbuffers::FlatBufferBuilder &_fbb, + const Flat::Bigfoot::HardReference *ref_a = nullptr, + ::flatbuffers::Offset<::flatbuffers::Vector> refs_a = 0) { + AssetBBuilder builder_(_fbb); + builder_.add_refs_a(refs_a); + builder_.add_ref_a(ref_a); + return builder_.Finish(); +} + +struct AssetB::Traits { + using type = AssetB; + static auto constexpr Create = CreateAssetB; +}; + +::flatbuffers::Offset CreateAssetB(::flatbuffers::FlatBufferBuilder &_fbb, const AssetBT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + +inline AssetBT *AssetB::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::make_unique(); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void AssetB::UnPackTo(AssetBT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = ref_a(); if (_e) _o->ref_a = ::flatbuffers::UnPackHardReferenceAssetA(*_e); } + { auto _e = refs_a(); if (_e) { _o->refs_a.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->refs_a[_i] = ::flatbuffers::UnPackSoftReferenceAssetA(*_e->Get(_i)); } } else { _o->refs_a.resize(0); } } +} + +inline ::flatbuffers::Offset CreateAssetB(::flatbuffers::FlatBufferBuilder &_fbb, const AssetBT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return AssetB::Pack(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset AssetB::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AssetBT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const AssetBT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _ref_a = ::flatbuffers::PackHardReferenceAssetA(_o->ref_a); + auto _refs_a = _fbb.CreateVectorOfNativeStructs>(_o->refs_a.data(), _o->refs_a.size(), ::flatbuffers::PackSoftReferenceAssetA); + return Flat::Bigfoot::CreateAssetB( + _fbb, + &_ref_a, + _refs_a); +} + +inline const ::flatbuffers::TypeTable *AssetBTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_SEQUENCE, 0, 0 }, + { ::flatbuffers::ET_SEQUENCE, 1, 1 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + Flat::Bigfoot::HardReferenceTypeTable, + Flat::Bigfoot::SoftReferenceTypeTable + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_TABLE, 2, type_codes, type_refs, nullptr, nullptr, nullptr + }; + return &tt; +} + +inline const Flat::Bigfoot::AssetB *GetAssetB(const void *buf) { + return ::flatbuffers::GetRoot(buf); +} + +inline const Flat::Bigfoot::AssetB *GetSizePrefixedAssetB(const void *buf) { + return ::flatbuffers::GetSizePrefixedRoot(buf); +} + +template +inline bool VerifyAssetBBuffer( + ::flatbuffers::VerifierTemplate &verifier) { + return verifier.template VerifyBuffer(nullptr); +} + +template +inline bool VerifySizePrefixedAssetBBuffer( + ::flatbuffers::VerifierTemplate &verifier) { + return verifier.template VerifySizePrefixedBuffer(nullptr); +} + +inline const char *AssetBExtension() { + return "bfbs"; +} + +inline void FinishAssetBBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.Finish(root); +} + +inline void FinishSizePrefixedAssetBBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root); +} + +inline eastl::unique_ptr UnPackAssetB( + const void *buf, + const ::flatbuffers::resolver_function_t *res = nullptr) { + return eastl::unique_ptr(GetAssetB(buf)->UnPack(res)); +} + +inline eastl::unique_ptr UnPackSizePrefixedAssetB( + const void *buf, + const ::flatbuffers::resolver_function_t *res = nullptr) { + return eastl::unique_ptr(GetSizePrefixedAssetB(buf)->UnPack(res)); +} + +} // namespace Bigfoot +} // namespace Flat + +namespace flatbuffers { +#ifndef FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA +#define FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA +inline Flat::Bigfoot::HardReference PackHardReferenceAssetA(const ::Bigfoot::HardReference<::Bigfoot::AssetA>& p_asset) { return {Pack(p_asset.GetUUID())}; } +inline ::Bigfoot::HardReference<::Bigfoot::AssetA> UnPackHardReferenceAssetA(const Flat::Bigfoot::HardReference& p_asset) { return {UnPack(p_asset.uuid())}; } +#endif // FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA +#ifndef FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA +#define FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA +inline Flat::Bigfoot::SoftReference PackSoftReferenceAssetA(const ::Bigfoot::SoftReference<::Bigfoot::AssetA>& p_asset) { return {Pack(p_asset.GetUUID())}; } +inline ::Bigfoot::SoftReference<::Bigfoot::AssetA> UnPackSoftReferenceAssetA(const Flat::Bigfoot::SoftReference& p_asset) { return {UnPack(p_asset.uuid())}; } +#endif // FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETA +} // namespace flatbuffers + +#endif // FLATBUFFERS_GENERATED_ASSETB_FLAT_BIGFOOT_H_ diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetC.fbs b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetC.fbs new file mode 100644 index 0000000..6c537bc --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetC.fbs @@ -0,0 +1,22 @@ +include "Engine/Asset/Reference.fbs"; + +namespace Flat.Bigfoot; + +table InnerTable +{ + asset_a_ref: HardReference (native_inline, bigfoot_ref: "::Bigfoot::AssetA"); + asset_a_refs: [HardReference] (native_inline, bigfoot_ref: "::Bigfoot::AssetA"); + + any_asset: HardReference (native_inline, bigfoot_ref: "::Bigfoot::AssetBase"); + any_assets: [SoftReference] (native_inline, bigfoot_ref: "::Bigfoot::AssetBase"); +} + +table AssetC +{ + inner_table: InnerTable (required); + + asset_b_ref: HardReference (native_inline, bigfoot_ref: "::Bigfoot::AssetB"); + asset_b_refs: [SoftReference] (native_inline, bigfoot_ref: "::Bigfoot::AssetB"); +} + +root_type AssetC; \ No newline at end of file diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetC.hpp b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetC.hpp new file mode 100644 index 0000000..ecf5fae --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetC.hpp @@ -0,0 +1,43 @@ +/********************************************************************* + * \file AssetC.hpp + * + * \author Romain BOULLARD + * \date April 2026 + *********************************************************************/ +#ifndef BIGFOOT_ASSETSFORTESTING_ASSET_ASSETC_HPP +#define BIGFOOT_ASSETSFORTESTING_ASSET_ASSETC_HPP +#include + +#include + +namespace Bigfoot +{ +struct AssetCTraits +{ + using FLAT = ::Flat::Bigfoot::AssetC; +}; + +class AssetC: public Asset +{ + public: + AssetC() + { + GetAsset().inner_table = eastl::make_unique<::Flat::Bigfoot::InnerTableT>(); + } + + AssetC(const eastl::span p_flatbuffer): + Asset(p_flatbuffer) + { + } + + AssetC(const AssetC& p_asset) = delete; + AssetC(AssetC&& p_asset) = default; + + ~AssetC() = default; + + AssetC& operator=(const AssetC& p_asset) = delete; + AssetC& operator=(AssetC&& p_asset) = default; +}; +} // namespace Bigfoot + +#endif diff --git a/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetC_generated.hpp b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetC_generated.hpp new file mode 100644 index 0000000..80ab68b --- /dev/null +++ b/Bigfoot/Tests/Misc/AssetsForTesting/Include/AssetsForTesting/Asset/AssetC_generated.hpp @@ -0,0 +1,470 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_ASSETC_FLAT_BIGFOOT_H_ +#define FLATBUFFERS_GENERATED_ASSETC_FLAT_BIGFOOT_H_ + +#include "flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && + FLATBUFFERS_VERSION_MINOR == 12 && + FLATBUFFERS_VERSION_REVISION == 19, + "Non-compatible flatbuffers version included"); +// Ensure the included flatbuffers.h is Bigfoot's fork - stock +// flatbuffers (or a differently versioned Bigfoot fork) is not compatible. +#ifndef FLATBUFFERS_BIGFOOT_VERSION +#error "This file requires Bigfoot's flatbuffers fork - stock flatbuffers is not compatible" +#endif +static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1, + "Non-compatible Bigfoot flatbuffers fork version included"); + +#include "System/UUID/UUID.hpp" +#include "Engine/Asset/Reference.hpp" +#include "Engine/Asset/Reference_generated.hpp" + +#include "EASTL/unique_ptr.h" +#include "EASTL/string.h" +#include "EASTL/vector.h" + +namespace Flat { +namespace Bigfoot { + +struct InnerTable; +struct InnerTableBuilder; +struct InnerTableT; + +struct AssetC; +struct AssetCBuilder; +struct AssetCT; + +} // namespace Bigfoot +} // namespace Flat + +namespace Bigfoot { +class AssetA; +} // namespace Bigfoot + +namespace Bigfoot { +class AssetBase; +} // namespace Bigfoot + +namespace Bigfoot { +class AssetB; +} // namespace Bigfoot + +namespace flatbuffers { +Flat::Bigfoot::HardReference PackHardReferenceAssetA(const ::Bigfoot::HardReference<::Bigfoot::AssetA>& p_asset); +::Bigfoot::HardReference<::Bigfoot::AssetA> UnPackHardReferenceAssetA(const Flat::Bigfoot::HardReference& p_asset); +Flat::Bigfoot::HardReference PackHardReferenceAssetBase(const ::Bigfoot::HardReference<::Bigfoot::AssetBase>& p_asset); +::Bigfoot::HardReference<::Bigfoot::AssetBase> UnPackHardReferenceAssetBase(const Flat::Bigfoot::HardReference& p_asset); +Flat::Bigfoot::SoftReference PackSoftReferenceAssetBase(const ::Bigfoot::SoftReference<::Bigfoot::AssetBase>& p_asset); +::Bigfoot::SoftReference<::Bigfoot::AssetBase> UnPackSoftReferenceAssetBase(const Flat::Bigfoot::SoftReference& p_asset); +Flat::Bigfoot::HardReference PackHardReferenceAssetB(const ::Bigfoot::HardReference<::Bigfoot::AssetB>& p_asset); +::Bigfoot::HardReference<::Bigfoot::AssetB> UnPackHardReferenceAssetB(const Flat::Bigfoot::HardReference& p_asset); +Flat::Bigfoot::SoftReference PackSoftReferenceAssetB(const ::Bigfoot::SoftReference<::Bigfoot::AssetB>& p_asset); +::Bigfoot::SoftReference<::Bigfoot::AssetB> UnPackSoftReferenceAssetB(const Flat::Bigfoot::SoftReference& p_asset); +} // namespace flatbuffers + +namespace Flat { +namespace Bigfoot { + +inline const ::flatbuffers::TypeTable *InnerTableTypeTable(); + +inline const ::flatbuffers::TypeTable *AssetCTypeTable(); + +struct InnerTableT : public ::flatbuffers::NativeTable { + typedef InnerTable TableType; + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.InnerTableT"; + } + ::Bigfoot::HardReference<::Bigfoot::AssetA> asset_a_ref{}; + eastl::vector<::Bigfoot::HardReference<::Bigfoot::AssetA>> asset_a_refs{}; + ::Bigfoot::HardReference<::Bigfoot::AssetBase> any_asset{}; + eastl::vector<::Bigfoot::SoftReference<::Bigfoot::AssetBase>> any_assets{}; +}; + +struct InnerTable FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef InnerTableT NativeTableType; + typedef InnerTableBuilder Builder; + struct Traits; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return InnerTableTypeTable(); + } + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.InnerTable"; + } + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ASSET_A_REF = 4, + VT_ASSET_A_REFS = 6, + VT_ANY_ASSET = 8, + VT_ANY_ASSETS = 10 + }; + const Flat::Bigfoot::HardReference *asset_a_ref() const { + return GetStruct(VT_ASSET_A_REF); + } + const ::flatbuffers::Vector *asset_a_refs() const { + return GetPointer *>(VT_ASSET_A_REFS); + } + const Flat::Bigfoot::HardReference *any_asset() const { + return GetStruct(VT_ANY_ASSET); + } + const ::flatbuffers::Vector *any_assets() const { + return GetPointer *>(VT_ANY_ASSETS); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ASSET_A_REF, 1) && + VerifyOffset(verifier, VT_ASSET_A_REFS) && + verifier.VerifyVector(asset_a_refs()) && + VerifyField(verifier, VT_ANY_ASSET, 1) && + VerifyOffset(verifier, VT_ANY_ASSETS) && + verifier.VerifyVector(any_assets()) && + verifier.EndTable(); + } + InnerTableT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(InnerTableT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const InnerTableT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct InnerTableBuilder { + typedef InnerTable Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_asset_a_ref(const Flat::Bigfoot::HardReference *asset_a_ref) { + fbb_.AddStruct(InnerTable::VT_ASSET_A_REF, asset_a_ref); + } + void add_asset_a_refs(::flatbuffers::Offset<::flatbuffers::Vector> asset_a_refs) { + fbb_.AddOffset(InnerTable::VT_ASSET_A_REFS, asset_a_refs); + } + void add_any_asset(const Flat::Bigfoot::HardReference *any_asset) { + fbb_.AddStruct(InnerTable::VT_ANY_ASSET, any_asset); + } + void add_any_assets(::flatbuffers::Offset<::flatbuffers::Vector> any_assets) { + fbb_.AddOffset(InnerTable::VT_ANY_ASSETS, any_assets); + } + explicit InnerTableBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + return o; + } +}; + +inline ::flatbuffers::Offset CreateInnerTable( + ::flatbuffers::FlatBufferBuilder &_fbb, + const Flat::Bigfoot::HardReference *asset_a_ref = nullptr, + ::flatbuffers::Offset<::flatbuffers::Vector> asset_a_refs = 0, + const Flat::Bigfoot::HardReference *any_asset = nullptr, + ::flatbuffers::Offset<::flatbuffers::Vector> any_assets = 0) { + InnerTableBuilder builder_(_fbb); + builder_.add_any_assets(any_assets); + builder_.add_any_asset(any_asset); + builder_.add_asset_a_refs(asset_a_refs); + builder_.add_asset_a_ref(asset_a_ref); + return builder_.Finish(); +} + +struct InnerTable::Traits { + using type = InnerTable; + static auto constexpr Create = CreateInnerTable; +}; + +::flatbuffers::Offset CreateInnerTable(::flatbuffers::FlatBufferBuilder &_fbb, const InnerTableT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct AssetCT : public ::flatbuffers::NativeTable { + typedef AssetC TableType; + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.AssetCT"; + } + eastl::unique_ptr inner_table{}; + ::Bigfoot::HardReference<::Bigfoot::AssetB> asset_b_ref{}; + eastl::vector<::Bigfoot::SoftReference<::Bigfoot::AssetB>> asset_b_refs{}; + AssetCT() = default; + AssetCT(const AssetCT &o); + AssetCT(AssetCT&&) FLATBUFFERS_NOEXCEPT = default; + AssetCT &operator=(AssetCT o) FLATBUFFERS_NOEXCEPT; +}; + +struct AssetC FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { + typedef AssetCT NativeTableType; + typedef AssetCBuilder Builder; + struct Traits; + static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { + return AssetCTypeTable(); + } + static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() { + return "Flat.Bigfoot.AssetC"; + } + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_INNER_TABLE = 4, + VT_ASSET_B_REF = 6, + VT_ASSET_B_REFS = 8 + }; + const Flat::Bigfoot::InnerTable *inner_table() const { + return GetPointer(VT_INNER_TABLE); + } + const Flat::Bigfoot::HardReference *asset_b_ref() const { + return GetStruct(VT_ASSET_B_REF); + } + const ::flatbuffers::Vector *asset_b_refs() const { + return GetPointer *>(VT_ASSET_B_REFS); + } + template + bool Verify(::flatbuffers::VerifierTemplate &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_INNER_TABLE) && + verifier.VerifyTable(inner_table()) && + VerifyField(verifier, VT_ASSET_B_REF, 1) && + VerifyOffset(verifier, VT_ASSET_B_REFS) && + verifier.VerifyVector(asset_b_refs()) && + verifier.EndTable(); + } + AssetCT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AssetCT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; + static ::flatbuffers::Offset Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AssetCT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AssetCBuilder { + typedef AssetC Table; + ::flatbuffers::FlatBufferBuilder &fbb_; + ::flatbuffers::uoffset_t start_; + void add_inner_table(::flatbuffers::Offset inner_table) { + fbb_.AddOffset(AssetC::VT_INNER_TABLE, inner_table); + } + void add_asset_b_ref(const Flat::Bigfoot::HardReference *asset_b_ref) { + fbb_.AddStruct(AssetC::VT_ASSET_B_REF, asset_b_ref); + } + void add_asset_b_refs(::flatbuffers::Offset<::flatbuffers::Vector> asset_b_refs) { + fbb_.AddOffset(AssetC::VT_ASSET_B_REFS, asset_b_refs); + } + explicit AssetCBuilder(::flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + ::flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = ::flatbuffers::Offset(end); + fbb_.Required(o, AssetC::VT_INNER_TABLE); + return o; + } +}; + +inline ::flatbuffers::Offset CreateAssetC( + ::flatbuffers::FlatBufferBuilder &_fbb, + ::flatbuffers::Offset inner_table = 0, + const Flat::Bigfoot::HardReference *asset_b_ref = nullptr, + ::flatbuffers::Offset<::flatbuffers::Vector> asset_b_refs = 0) { + AssetCBuilder builder_(_fbb); + builder_.add_asset_b_refs(asset_b_refs); + builder_.add_asset_b_ref(asset_b_ref); + builder_.add_inner_table(inner_table); + return builder_.Finish(); +} + +struct AssetC::Traits { + using type = AssetC; + static auto constexpr Create = CreateAssetC; +}; + +::flatbuffers::Offset CreateAssetC(::flatbuffers::FlatBufferBuilder &_fbb, const AssetCT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); + +inline InnerTableT *InnerTable::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::make_unique(); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void InnerTable::UnPackTo(InnerTableT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = asset_a_ref(); if (_e) _o->asset_a_ref = ::flatbuffers::UnPackHardReferenceAssetA(*_e); } + { auto _e = asset_a_refs(); if (_e) { _o->asset_a_refs.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->asset_a_refs[_i] = ::flatbuffers::UnPackHardReferenceAssetA(*_e->Get(_i)); } } else { _o->asset_a_refs.resize(0); } } + { auto _e = any_asset(); if (_e) _o->any_asset = ::flatbuffers::UnPackHardReferenceAssetBase(*_e); } + { auto _e = any_assets(); if (_e) { _o->any_assets.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->any_assets[_i] = ::flatbuffers::UnPackSoftReferenceAssetBase(*_e->Get(_i)); } } else { _o->any_assets.resize(0); } } +} + +inline ::flatbuffers::Offset CreateInnerTable(::flatbuffers::FlatBufferBuilder &_fbb, const InnerTableT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return InnerTable::Pack(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset InnerTable::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const InnerTableT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const InnerTableT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _asset_a_ref = ::flatbuffers::PackHardReferenceAssetA(_o->asset_a_ref); + auto _asset_a_refs = _fbb.CreateVectorOfNativeStructs>(_o->asset_a_refs.data(), _o->asset_a_refs.size(), ::flatbuffers::PackHardReferenceAssetA); + auto _any_asset = ::flatbuffers::PackHardReferenceAssetBase(_o->any_asset); + auto _any_assets = _fbb.CreateVectorOfNativeStructs>(_o->any_assets.data(), _o->any_assets.size(), ::flatbuffers::PackSoftReferenceAssetBase); + return Flat::Bigfoot::CreateInnerTable( + _fbb, + &_asset_a_ref, + _asset_a_refs, + &_any_asset, + _any_assets); +} + +inline AssetCT::AssetCT(const AssetCT &o) + : inner_table((o.inner_table) ? new Flat::Bigfoot::InnerTableT(*o.inner_table) : nullptr), + asset_b_ref(o.asset_b_ref), + asset_b_refs(o.asset_b_refs) { +} + +inline AssetCT &AssetCT::operator=(AssetCT o) FLATBUFFERS_NOEXCEPT { + std::swap(inner_table, o.inner_table); + std::swap(asset_b_ref, o.asset_b_ref); + std::swap(asset_b_refs, o.asset_b_refs); + return *this; +} + +inline AssetCT *AssetC::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::make_unique(); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void AssetC::UnPackTo(AssetCT *_o, const ::flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = inner_table(); if (_e) { if(_o->inner_table) { _e->UnPackTo(_o->inner_table.get(), _resolver); } else { _o->inner_table = eastl::unique_ptr(_e->UnPack(_resolver)); } } else if (_o->inner_table) { _o->inner_table.reset(); } } + { auto _e = asset_b_ref(); if (_e) _o->asset_b_ref = ::flatbuffers::UnPackHardReferenceAssetB(*_e); } + { auto _e = asset_b_refs(); if (_e) { _o->asset_b_refs.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->asset_b_refs[_i] = ::flatbuffers::UnPackSoftReferenceAssetB(*_e->Get(_i)); } } else { _o->asset_b_refs.resize(0); } } +} + +inline ::flatbuffers::Offset CreateAssetC(::flatbuffers::FlatBufferBuilder &_fbb, const AssetCT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { + return AssetC::Pack(_fbb, _o, _rehasher); +} + +inline ::flatbuffers::Offset AssetC::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const AssetCT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const AssetCT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _inner_table = _o->inner_table ? CreateInnerTable(_fbb, _o->inner_table.get(), _rehasher) : 0; + auto _asset_b_ref = ::flatbuffers::PackHardReferenceAssetB(_o->asset_b_ref); + auto _asset_b_refs = _fbb.CreateVectorOfNativeStructs>(_o->asset_b_refs.data(), _o->asset_b_refs.size(), ::flatbuffers::PackSoftReferenceAssetB); + return Flat::Bigfoot::CreateAssetC( + _fbb, + _inner_table, + &_asset_b_ref, + _asset_b_refs); +} + +inline const ::flatbuffers::TypeTable *InnerTableTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_SEQUENCE, 0, 0 }, + { ::flatbuffers::ET_SEQUENCE, 1, 0 }, + { ::flatbuffers::ET_SEQUENCE, 0, 0 }, + { ::flatbuffers::ET_SEQUENCE, 1, 1 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + Flat::Bigfoot::HardReferenceTypeTable, + Flat::Bigfoot::SoftReferenceTypeTable + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_TABLE, 4, type_codes, type_refs, nullptr, nullptr, nullptr + }; + return &tt; +} + +inline const ::flatbuffers::TypeTable *AssetCTypeTable() { + static const ::flatbuffers::TypeCode type_codes[] = { + { ::flatbuffers::ET_SEQUENCE, 0, 0 }, + { ::flatbuffers::ET_SEQUENCE, 0, 1 }, + { ::flatbuffers::ET_SEQUENCE, 1, 2 } + }; + static const ::flatbuffers::TypeFunction type_refs[] = { + Flat::Bigfoot::InnerTableTypeTable, + Flat::Bigfoot::HardReferenceTypeTable, + Flat::Bigfoot::SoftReferenceTypeTable + }; + static const ::flatbuffers::TypeTable tt = { + ::flatbuffers::ST_TABLE, 3, type_codes, type_refs, nullptr, nullptr, nullptr + }; + return &tt; +} + +inline const Flat::Bigfoot::AssetC *GetAssetC(const void *buf) { + return ::flatbuffers::GetRoot(buf); +} + +inline const Flat::Bigfoot::AssetC *GetSizePrefixedAssetC(const void *buf) { + return ::flatbuffers::GetSizePrefixedRoot(buf); +} + +template +inline bool VerifyAssetCBuffer( + ::flatbuffers::VerifierTemplate &verifier) { + return verifier.template VerifyBuffer(nullptr); +} + +template +inline bool VerifySizePrefixedAssetCBuffer( + ::flatbuffers::VerifierTemplate &verifier) { + return verifier.template VerifySizePrefixedBuffer(nullptr); +} + +inline const char *AssetCExtension() { + return "bfbs"; +} + +inline void FinishAssetCBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.Finish(root); +} + +inline void FinishSizePrefixedAssetCBuffer( + ::flatbuffers::FlatBufferBuilder &fbb, + ::flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root); +} + +inline eastl::unique_ptr UnPackAssetC( + const void *buf, + const ::flatbuffers::resolver_function_t *res = nullptr) { + return eastl::unique_ptr(GetAssetC(buf)->UnPack(res)); +} + +inline eastl::unique_ptr UnPackSizePrefixedAssetC( + const void *buf, + const ::flatbuffers::resolver_function_t *res = nullptr) { + return eastl::unique_ptr(GetSizePrefixedAssetC(buf)->UnPack(res)); +} + +} // namespace Bigfoot +} // namespace Flat + +namespace flatbuffers { +#ifndef FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA +#define FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA +inline Flat::Bigfoot::HardReference PackHardReferenceAssetA(const ::Bigfoot::HardReference<::Bigfoot::AssetA>& p_asset) { return {Pack(p_asset.GetUUID())}; } +inline ::Bigfoot::HardReference<::Bigfoot::AssetA> UnPackHardReferenceAssetA(const Flat::Bigfoot::HardReference& p_asset) { return {UnPack(p_asset.uuid())}; } +#endif // FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETA +#ifndef FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETBASE +#define FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETBASE +inline Flat::Bigfoot::HardReference PackHardReferenceAssetBase(const ::Bigfoot::HardReference<::Bigfoot::AssetBase>& p_asset) { return {Pack(p_asset.GetUUID())}; } +inline ::Bigfoot::HardReference<::Bigfoot::AssetBase> UnPackHardReferenceAssetBase(const Flat::Bigfoot::HardReference& p_asset) { return {UnPack(p_asset.uuid())}; } +#endif // FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETBASE +#ifndef FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETBASE +#define FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETBASE +inline Flat::Bigfoot::SoftReference PackSoftReferenceAssetBase(const ::Bigfoot::SoftReference<::Bigfoot::AssetBase>& p_asset) { return {Pack(p_asset.GetUUID())}; } +inline ::Bigfoot::SoftReference<::Bigfoot::AssetBase> UnPackSoftReferenceAssetBase(const Flat::Bigfoot::SoftReference& p_asset) { return {UnPack(p_asset.uuid())}; } +#endif // FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETBASE +#ifndef FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETB +#define FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETB +inline Flat::Bigfoot::HardReference PackHardReferenceAssetB(const ::Bigfoot::HardReference<::Bigfoot::AssetB>& p_asset) { return {Pack(p_asset.GetUUID())}; } +inline ::Bigfoot::HardReference<::Bigfoot::AssetB> UnPackHardReferenceAssetB(const Flat::Bigfoot::HardReference& p_asset) { return {UnPack(p_asset.uuid())}; } +#endif // FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEASSETB +#ifndef FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETB +#define FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETB +inline Flat::Bigfoot::SoftReference PackSoftReferenceAssetB(const ::Bigfoot::SoftReference<::Bigfoot::AssetB>& p_asset) { return {Pack(p_asset.GetUUID())}; } +inline ::Bigfoot::SoftReference<::Bigfoot::AssetB> UnPackSoftReferenceAssetB(const Flat::Bigfoot::SoftReference& p_asset) { return {UnPack(p_asset.uuid())}; } +#endif // FLATBUFFERS_BIGFOOT_REF_SOFTREFERENCEASSETB +} // namespace flatbuffers + +#endif // FLATBUFFERS_GENERATED_ASSETC_FLAT_BIGFOOT_H_ diff --git a/Bigfoot/Tests/Misc/CMakeLists.txt b/Bigfoot/Tests/Misc/CMakeLists.txt new file mode 100644 index 0000000..66cec06 --- /dev/null +++ b/Bigfoot/Tests/Misc/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/AssetsForTesting) \ No newline at end of file diff --git a/Bigfoot/Tests/System/CMakeLists.txt b/Bigfoot/Tests/System/CMakeLists.txt index 7b130e0..07d7c3d 100644 --- a/Bigfoot/Tests/System/CMakeLists.txt +++ b/Bigfoot/Tests/System/CMakeLists.txt @@ -1,14 +1,10 @@ get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME) project(${PackageName}Tests) -set(BigfootDependencies - System - Utils) +set(Dependencies) +set(BigfootDependencies) bigfoot_create_package_tests( - "" - "${BigfootDependencies}") - -bigfoot_create_logger() - -bigfoot_setup_dependencies("Tests/Bigfoot") \ No newline at end of file + "${Dependencies}" + "${BigfootDependencies}" + "") \ No newline at end of file diff --git a/Bigfoot/Tests/System/File.cpp b/Bigfoot/Tests/System/File.cpp index 850afe6..a0c8983 100644 --- a/Bigfoot/Tests/System/File.cpp +++ b/Bigfoot/Tests/System/File.cpp @@ -28,14 +28,14 @@ TEST_F(FileFixture, IsRelative_ShouldReturnTrueOnRelativeFile) TEST_F(FileFixture, IsRelative_ShouldReturnFalseOnAbsoluteFile) { - EXPECT_FALSE(m_file.Absolute().IsRelative()); + EXPECT_FALSE(m_file.ToAbsolute().IsRelative()); } /****************************************************************************************/ TEST_F(FileFixture, IsAbsolute_ShouldReturnTrueOnAbsoluteFile) { - EXPECT_TRUE(m_file.Absolute().IsAbsolute()); + EXPECT_TRUE(m_file.ToAbsolute().IsAbsolute()); } TEST_F(FileFixture, IsAbsolute_ShouldReturnFalseOnRelativeFile) @@ -59,22 +59,22 @@ TEST_F(FileFixture, Exists_ShouldReturnFalseOnNonExistingFile) /****************************************************************************************/ -TEST_F(FileFixture, Path_ShouldReturnThePath) +TEST_F(FileFixture, GetPath_ShouldReturnThePath) { - EXPECT_STREQ(m_file.Path().data(), "Fixture/file"); + EXPECT_STREQ(m_file.GetPath().data(), "Fixture/file"); } /****************************************************************************************/ -TEST_F(FileFixture, Absolute_ShouldReturnTheAbsolutePath) +TEST_F(FileFixture, ToAbsolute_ShouldReturnTheAbsolutePath) { - EXPECT_STREQ(std::filesystem::absolute("Fixture/file").string().c_str(), m_file.Absolute().Path().data()); + EXPECT_STREQ(std::filesystem::absolute("Fixture/file").string().c_str(), m_file.ToAbsolute().GetPath().data()); } /****************************************************************************************/ -TEST_F(FileFixture, Relative_ShouldReturnTheRelativePath) +TEST_F(FileFixture, ToRelative_ShouldReturnTheRelativePath) { - EXPECT_STREQ(std::filesystem::relative("Fixture/file").string().c_str(), m_file.Relative().Path().data()); + EXPECT_STREQ(std::filesystem::relative("Fixture/file").string().c_str(), m_file.ToRelative().GetPath().data()); } } // namespace Bigfoot diff --git a/Bigfoot/Tests/System/SystemTests/main.cpp b/Bigfoot/Tests/System/SystemTests/main.cpp new file mode 100644 index 0000000..6645ee3 --- /dev/null +++ b/Bigfoot/Tests/System/SystemTests/main.cpp @@ -0,0 +1,19 @@ +/********************************************************************* + * \file main.cpp + * + * \author Romain BOULLARD + * \date May 2026 + *********************************************************************/ +#include +#include + +#include + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + + BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime); + + return RUN_ALL_TESTS(); +} diff --git a/Bigfoot/Tests/System/Time/Time.cpp b/Bigfoot/Tests/System/Time/Time.cpp new file mode 100644 index 0000000..ce300d2 --- /dev/null +++ b/Bigfoot/Tests/System/Time/Time.cpp @@ -0,0 +1,67 @@ +/********************************************************************* + * \file Time.cpp + * + * \author Romain BOULLARD + * \date December 2025 + *********************************************************************/ +#include + +#include + +namespace Bigfoot +{ +class TimeFixture: public ::testing::Test +{ + public: + Time m_time {1'767'643'746'680'609}; +}; + +/****************************************************************************************/ + +TEST_F(TimeFixture, GetYear_ShouldReturnTheYear) +{ + EXPECT_EQ(m_time.GetYear(), 2026); +} + +/****************************************************************************************/ + +TEST_F(TimeFixture, GetMonth_ShouldReturnTheMonth) +{ + EXPECT_EQ(m_time.GetMonth(), 1); +} + +/****************************************************************************************/ + +TEST_F(TimeFixture, GetDay_ShouldReturnTheDay) +{ + EXPECT_EQ(m_time.GetDay(), 5); +} + +/****************************************************************************************/ + +TEST_F(TimeFixture, GetHour_ShouldReturnTheHour) +{ + EXPECT_EQ(m_time.GetHour(), 20); +} + +/****************************************************************************************/ + +TEST_F(TimeFixture, GetMinute_ShouldReturnTheMinute) +{ + EXPECT_EQ(m_time.GetMinute(), 9); +} + +/****************************************************************************************/ + +TEST_F(TimeFixture, GetSecond_ShouldReturnTheSecond) +{ + EXPECT_EQ(m_time.GetSecond(), 6); +} + +/****************************************************************************************/ + +TEST_F(TimeFixture, GetMicrosecond_ShouldReturnTheMicrosecond) +{ + EXPECT_EQ(m_time.GetMicrosecond(), 680'609); +} +} // namespace Bigfoot diff --git a/Bigfoot/Tests/System/UUID/UUID.cpp b/Bigfoot/Tests/System/UUID/UUID.cpp index 8f978d9..debfccf 100644 --- a/Bigfoot/Tests/System/UUID/UUID.cpp +++ b/Bigfoot/Tests/System/UUID/UUID.cpp @@ -7,7 +7,6 @@ #include #include - #include namespace Bigfoot @@ -44,13 +43,13 @@ class UUIDFixture: public ::testing::Test TEST_F(UUIDFixture, DumpingRawAndConstructAnUUIDWithItShouldGiveTheSameUUID) { - std::span raw = m_a; + std::span raw = m_a.ToBytes(); EXPECT_EQ(m_a, UUID {raw}); - raw = m_b; + raw = m_b.ToBytes(); EXPECT_EQ(m_b, UUID {raw}); - raw = m_d; + raw = m_d.ToBytes(); EXPECT_EQ(m_d, UUID {raw}); } @@ -58,21 +57,21 @@ TEST_F(UUIDFixture, DumpingRawAndConstructAnUUIDWithItShouldGiveTheSameUUID) TEST_F(UUIDFixture, ValidIDFromStringShouldBeEqualToString) { - EXPECT_EQ(static_cast(m_b), "47183823-2574-4bfd-b411-99ed177d3e43"); + EXPECT_EQ(m_b.ToString(), "47183823-2574-4bfd-b411-99ed177d3e43"); } /****************************************************************************************/ TEST_F(UUIDFixture, InvalidIDFromStringShouldNotBeEqualToString) { - EXPECT_NE(static_cast(m_c), "4bfd-b411-99ed177d3e43"); + EXPECT_NE(m_c.ToString(), "4bfd-b411-99ed177d3e43"); } /****************************************************************************************/ TEST_F(UUIDFixture, NullIDStringShouldBeEqualToNullIDString) { - EXPECT_EQ(static_cast(UUID::NULL_UUID), "00000000-0000-0000-0000-000000000000"); + EXPECT_EQ(UUID::NULL_UUID.ToString(), "00000000-0000-0000-0000-000000000000"); } /****************************************************************************************/ @@ -169,9 +168,9 @@ TEST_F(UUIDFixture, GeneratingFiveMillionUniqueID) /****************************************************************************************/ -TEST_F(UUIDFixture, Raw_ShouldGiveBackTheRawDataOfTheID) +TEST_F(UUIDFixture, ToBytes_ShouldGiveBackTheRawDataOfTheID) { - std::span d = m_d; + std::span d = m_d.ToBytes(); std::span raw = m_raw; for (std::uint32_t i = 0; i < UUID::UUID_BYTE_SIZE; ++i) diff --git a/Bigfoot/Tests/Utils/CMakeLists.txt b/Bigfoot/Tests/Utils/CMakeLists.txt index 47c3d4b..d6c67dd 100644 --- a/Bigfoot/Tests/Utils/CMakeLists.txt +++ b/Bigfoot/Tests/Utils/CMakeLists.txt @@ -1,11 +1,12 @@ get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME) project(${PackageName}Tests) -set(BigfootDependencies - Utils) +set(Dependencies) +set(BigfootDependencies) bigfoot_create_package_tests( - "" - "${BigfootDependencies}") + "${Dependencies}" + "${BigfootDependencies}" + "") -bigfoot_setup_dependencies("Tests/Bigfoot") \ No newline at end of file +bigfoot_create_logger() \ No newline at end of file diff --git a/Bigfoot/Tests/Utils/Containers/SlotMap.cpp b/Bigfoot/Tests/Utils/Containers/SlotMap.cpp new file mode 100644 index 0000000..c6a3649 --- /dev/null +++ b/Bigfoot/Tests/Utils/Containers/SlotMap.cpp @@ -0,0 +1,1162 @@ +/********************************************************************* + * \file SlotMap.cpp + * + * \author Romain BOULLARD + * \date August 2026 + *********************************************************************/ +#include + +#include +#include + +namespace Bigfoot +{ +class SlotMapKeyFixture: public ::testing::Test +{ + protected: + using SlotMapKey = SlotMapKey<>; +}; + +/****************************************************************************************/ + +TEST_F(SlotMapKeyFixture, INVALID_VERSION_IsZero) +{ + EXPECT_EQ(SlotMapKey::INVALID_VERSION, 0); +} + +/****************************************************************************************/ + +TEST_F(SlotMapKeyFixture, MAX_INDEX_IsMaxU32) +{ + EXPECT_EQ(SlotMapKey::MAX_INDEX, std::numeric_limits::max()); +} + +/****************************************************************************************/ + +TEST_F(SlotMapKeyFixture, Valid_ShouldReturnFalseIfVersionIsInvalid) +{ + EXPECT_FALSE(SlotMapKey().Valid()); + EXPECT_FALSE(SlotMapKey(0, 0).Valid()); + EXPECT_FALSE(SlotMapKey(SlotMapKey::INVALID_VERSION, 0).Valid()); + EXPECT_FALSE(SlotMapKey(0, 42).Valid()); + EXPECT_FALSE(SlotMapKey(SlotMapKey::INVALID_VERSION, 42).Valid()); +} + +/****************************************************************************************/ + +TEST_F(SlotMapKeyFixture, Valid_ShouldReturnTrueIfVersionisNotInvalid) +{ + EXPECT_TRUE(SlotMapKey(1, 0).Valid()); + EXPECT_TRUE(SlotMapKey(1, 42).Valid()); +} + +/****************************************************************************************/ + +TEST_F(SlotMapKeyFixture, GetVersion_ShouldReturnTheVersion) +{ + EXPECT_EQ(SlotMapKey(0, 0).GetVersion(), 0); + EXPECT_EQ(SlotMapKey(42, 69).GetVersion(), 42); +} + +/****************************************************************************************/ + +TEST_F(SlotMapKeyFixture, GetIndex_ShouldReturnTheIndex) +{ + EXPECT_EQ(SlotMapKey(0, 0).GetIndex(), 0); + EXPECT_EQ(SlotMapKey(42, 69).GetIndex(), 69); +} + +/****************************************************************************************/ + +class SlotMapValueMock +{ + public: + virtual ~SlotMapValueMock() = default; + virtual void Destruct() = 0; +}; + +class SlotMapValue +{ + public: + inline static SlotMapValueMock* ms_mock = nullptr; + + SlotMapValue() = default; + + SlotMapValue(const std::uint32_t p_value): + m_value(p_value) + { + } + + SlotMapValue(const SlotMapValue& p_value) = default; + SlotMapValue(SlotMapValue&& p_value) = default; + + ~SlotMapValue() + { + if (ms_mock) + { + ms_mock->Destruct(); + } + } + + SlotMapValue& operator=(const SlotMapValue& p_value) = default; + SlotMapValue& operator=(SlotMapValue&& p_value) = default; + + operator std::uint32_t() const + { + return m_value; + } + + private: + std::uint32_t m_value = 0; +}; + +template +class SlotMapFixture: public ::testing::Test +{ + protected: + class SlotMapValueMockImpl: public SlotMapValueMock + { + public: + MOCK_METHOD(void, Destruct, (), (override)); + }; + + using SlotMapKey = typename SLOTMAP::SlotMapKey; + + std::unique_ptr m_mock; + SLOTMAP m_slotMap; + + void SetUp() override + { + m_mock = std::make_unique<::testing::NiceMock>(); + SlotMapValue::ms_mock = m_mock.get(); + } + + void TearDown() override + { + SlotMapValue::ms_mock = nullptr; + m_mock.reset(); + } +}; + +class SlotMapNameGenerator +{ + public: + template + static std::string GetName(int) + { + if constexpr (std::is_same_v>>) + { + return "DenseSlotMap"; + } + // if constexpr (std::is_same_v>) + // { + // return "StableSlotMap"; + // } + } +}; + +using SlotMapTypes = ::testing::Types>>; +TYPED_TEST_SUITE(SlotMapFixture, SlotMapTypes, SlotMapNameGenerator); + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Has_ReturnTrueIfSlotMapHasTheKey) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey key = this->m_slotMap.Insert(42); + EXPECT_TRUE(this->m_slotMap.Has(key)); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Has_ReturnFalseIfSlotMapDoesNotHaveTheKey) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + std::ignore = this->m_slotMap.Insert(42); + EXPECT_FALSE(this->m_slotMap.Has(SlotMapKey {1, 23})); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Has_ReturnFalseForStaleKey) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey staleKey = this->m_slotMap.Insert(42); + this->m_slotMap.Remove(staleKey); + std::ignore = this->m_slotMap.Insert(69); + + EXPECT_FALSE(this->m_slotMap.Has(staleKey)); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Size_ShouldReturnTheSizeOfTheSlotMap) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + EXPECT_EQ(this->m_slotMap.Size(), 0); + const SlotMapKey key1 = this->m_slotMap.Insert(42); + const SlotMapKey key2 = this->m_slotMap.Insert(69); + EXPECT_EQ(this->m_slotMap.Size(), 2); + this->m_slotMap.Remove(key1); + EXPECT_EQ(this->m_slotMap.Size(), 1); + this->m_slotMap.Remove(key2); + EXPECT_EQ(this->m_slotMap.Size(), 0); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Empty_ShouldReturnTrueIfTheSlotMapIsEmpty) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + EXPECT_TRUE(this->m_slotMap.Empty()); + const SlotMapKey key1 = this->m_slotMap.Insert(42); + const SlotMapKey key2 = this->m_slotMap.Insert(69); + this->m_slotMap.Remove(key1); + this->m_slotMap.Remove(key2); + EXPECT_TRUE(this->m_slotMap.Empty()); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Empty_ShouldReturnFalseIfTheSlotMapIsNotEmpty) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey key1 = this->m_slotMap.Insert(42); + EXPECT_FALSE(this->m_slotMap.Empty()); + const SlotMapKey key2 = this->m_slotMap.Insert(69); + EXPECT_FALSE(this->m_slotMap.Empty()); + this->m_slotMap.Remove(key1); + EXPECT_FALSE(this->m_slotMap.Empty()); + this->m_slotMap.Remove(key2); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Insert_ShouldReturnAValidSlotKey) +{ + EXPECT_TRUE(this->m_slotMap.Insert(42).Valid()); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Insert_ShouldRecycleIndicesWhenPossible) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey key1 = this->m_slotMap.Insert(42); + const SlotMapKey key2 = this->m_slotMap.Insert(69); + + this->m_slotMap.Remove(key1); + this->m_slotMap.Remove(key2); + + const SlotMapKey key11 = this->m_slotMap.Insert(42); + const SlotMapKey key21 = this->m_slotMap.Insert(69); + + EXPECT_EQ(key1.GetVersion() + 1, key11.GetVersion()); + EXPECT_EQ(key1.GetIndex(), key21.GetIndex()); // LIFO + + EXPECT_EQ(key2.GetVersion() + 1, key21.GetVersion()); + EXPECT_EQ(key2.GetIndex(), key11.GetIndex()); // LIFO +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Get_ShouldReturnTheValue) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey key = this->m_slotMap.Insert(42); + EXPECT_EQ(*this->m_slotMap.Get(key), 42); + EXPECT_EQ(*const_cast(this->m_slotMap).Get(key), 42); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Get_ShouldNullptrIfTheValueIsNotInMap) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey key {1, 0}; + EXPECT_EQ(this->m_slotMap.Get(key), nullptr); + EXPECT_EQ(const_cast(this->m_slotMap).Get(key), nullptr); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Get_ShouldReturnNullptrForStaleKey) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey staleKey = this->m_slotMap.Insert(42); + this->m_slotMap.Remove(staleKey); + std::ignore = this->m_slotMap.Insert(69); + + EXPECT_EQ(this->m_slotMap.Get(staleKey), nullptr); + EXPECT_EQ(const_cast(this->m_slotMap).Get(staleKey), nullptr); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Remove_ShouldRemoveTheValue) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey key = this->m_slotMap.Insert(42); + EXPECT_TRUE(this->m_slotMap.Has(key)); + + EXPECT_CALL(*this->m_mock, Destruct()).Times(1); + this->m_slotMap.Remove(key); + EXPECT_FALSE(this->m_slotMap.Has(key)); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Remove_ShouldBeANoOpForStaleKey) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey staleKey = this->m_slotMap.Insert(42); + this->m_slotMap.Remove(staleKey); + const SlotMapKey freshKey = this->m_slotMap.Insert(69); + + this->m_slotMap.Remove(staleKey); + + EXPECT_TRUE(this->m_slotMap.Has(freshKey)); + EXPECT_EQ(*this->m_slotMap.Get(freshKey), 69); + EXPECT_EQ(this->m_slotMap.Size(), 1); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Remove_ExhaustingAllVersionsOfKeyMarksItDeadForGood) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + for (typename SlotMapKey::VersionType version = 0; version < SlotMapKey::MAX_VERSION; ++version) + { + const SlotMapKey key = this->m_slotMap.Insert(42); + EXPECT_EQ(key.GetIndex(), 0); + EXPECT_EQ(key.GetVersion(), version + 1); + this->m_slotMap.Remove(key); + } + EXPECT_TRUE(this->m_slotMap.Empty()); + const SlotMapKey key = this->m_slotMap.Insert(42); + EXPECT_EQ(key.GetIndex(), 1); + EXPECT_EQ(key.GetVersion(), 1); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Reset_ShouldClearTheMapAndOldKeysAreValid) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey key1 = this->m_slotMap.Insert(42); + const SlotMapKey key2 = this->m_slotMap.Insert(69); + + EXPECT_CALL(*this->m_mock, Destruct()).Times(2); + this->m_slotMap.Reset(); + + EXPECT_EQ(this->m_slotMap.Size(), 0); + EXPECT_TRUE(this->m_slotMap.Empty()); + + EXPECT_FALSE(this->m_slotMap.Has(key1)); + EXPECT_FALSE(this->m_slotMap.Has(key2)); + + EXPECT_EQ(this->m_slotMap.Insert(42), key1); + EXPECT_EQ(this->m_slotMap.Insert(69), key2); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Clear_ShouldClearTheMapAndOldKeysAreInvalid) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const SlotMapKey key1 = this->m_slotMap.Insert(42); + const SlotMapKey key2 = this->m_slotMap.Insert(69); + + EXPECT_CALL(*this->m_mock, Destruct()).Times(2); + this->m_slotMap.Clear(); + + EXPECT_EQ(this->m_slotMap.Size(), 0); + EXPECT_TRUE(this->m_slotMap.Empty()); + + EXPECT_FALSE(this->m_slotMap.Has(key1)); + EXPECT_FALSE(this->m_slotMap.Has(key2)); + + EXPECT_NE(this->m_slotMap.Insert(42), key1); + EXPECT_NE(this->m_slotMap.Insert(69), key2); +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, Iterator) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + EXPECT_EQ(this->m_slotMap.begin(), this->m_slotMap.end()); + + std::ignore = this->m_slotMap.Insert(1); + const SlotMapKey key2 = this->m_slotMap.Insert(2); + std::ignore = this->m_slotMap.Insert(3); + + // Forward traversal follows insertion order + std::uint32_t expected = 1; + for (auto it = this->m_slotMap.begin(); it != this->m_slotMap.end(); ++it) + { + EXPECT_EQ(*it, expected); + ++expected; + } + + // Pre-increment advances and returns *this + auto preIt = this->m_slotMap.begin(); + auto& preIncrementResult = ++preIt; + EXPECT_EQ(&preIncrementResult, &preIt); + EXPECT_EQ(*preIt, 2); + + // Post-increment advances but returns the old value + auto postIt = this->m_slotMap.begin(); + const auto postIncrementResult = postIt++; + EXPECT_EQ(*postIncrementResult, 1); + EXPECT_EQ(*postIt, 2); + + // Pre-decrement retreats and returns *this + auto preDecIt = this->m_slotMap.end(); + --preDecIt; // now at 3 + auto& preDecrementResult = --preDecIt; // now at 2 + EXPECT_EQ(&preDecrementResult, &preDecIt); + EXPECT_EQ(*preDecIt, 2); + + // Post-decrement retreats but returns the old value + auto postDecIt = this->m_slotMap.end(); + --postDecIt; // now at 3 + const auto postDecrementResult = postDecIt--; + EXPECT_EQ(*postDecrementResult, 3); + EXPECT_EQ(*postDecIt, 2); + + // Removed slots are skipped during traversal + this->m_slotMap.Remove(key2); + + std::size_t count = 0; + std::uint32_t sum = 0; + for (const std::uint32_t value: this->m_slotMap) + { + ++count; + sum += value; + } + EXPECT_EQ(count, 2); + EXPECT_EQ(sum, 4); + + // Multi-page traversal: StableSlotMap's PAGE_SIZE is 64, so 100 elements force it to span pages + this->m_slotMap.Reset(); + + constexpr std::uint32_t elementCount = 100; + eastl::array keys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + keys[value] = this->m_slotMap.Insert(value); + } + + expected = 0; + for (const std::uint32_t value: this->m_slotMap) + { + EXPECT_EQ(value, expected); + ++expected; + } + EXPECT_EQ(expected, elementCount); + + // Explicitly cross the page boundary (index 63 -> 64) forward and backward + auto boundaryIt = this->m_slotMap.begin(); + for (std::uint32_t step = 0; step < 63; ++step) + { + ++boundaryIt; + } + EXPECT_EQ(*boundaryIt, 63); + ++boundaryIt; + EXPECT_EQ(*boundaryIt, 64); + --boundaryIt; + EXPECT_EQ(*boundaryIt, 63); + + // Pre/post-increment/decrement across the boundary + auto preBoundaryIt = this->m_slotMap.begin(); + auto& preBoundaryIncrementResult = ++preBoundaryIt; + EXPECT_EQ(&preBoundaryIncrementResult, &preBoundaryIt); + EXPECT_EQ(*preBoundaryIt, 1); + + auto postBoundaryIt = this->m_slotMap.begin(); + const auto postBoundaryIncrementResult = postBoundaryIt++; + EXPECT_EQ(*postBoundaryIncrementResult, 0); + EXPECT_EQ(*postBoundaryIt, 1); + + auto preBoundaryDecIt = this->m_slotMap.end(); + --preBoundaryDecIt; // now at 99 + auto& preBoundaryDecrementResult = --preBoundaryDecIt; // now at 98 + EXPECT_EQ(&preBoundaryDecrementResult, &preBoundaryDecIt); + EXPECT_EQ(*preBoundaryDecIt, 98); + + auto postBoundaryDecIt = this->m_slotMap.end(); + --postBoundaryDecIt; // now at 99 + const auto postBoundaryDecrementResult = postBoundaryDecIt--; + EXPECT_EQ(*postBoundaryDecrementResult, 99); + EXPECT_EQ(*postBoundaryDecIt, 98); + + // Remove elements straddling the boundary and check the holes are skipped + this->m_slotMap.Remove(keys[63]); + this->m_slotMap.Remove(keys[64]); + + count = 0; + for (const std::uint32_t value: this->m_slotMap) + { + EXPECT_NE(value, 63); + EXPECT_NE(value, 64); + ++count; + } + EXPECT_EQ(count, elementCount - 2); + + // A fully empty leading page must be skipped by begin()/SeekFirstFrom + this->m_slotMap.Reset(); + eastl::array leadingKeys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + leadingKeys[value] = this->m_slotMap.Insert(value); + } + for (std::uint32_t value = 0; value < 64; ++value) + { + this->m_slotMap.Remove(leadingKeys[value]); + } + + count = 0; + sum = 0; + for (const std::uint32_t value: this->m_slotMap) + { + ++count; + sum += value; + } + EXPECT_EQ(count, elementCount - 64); + EXPECT_EQ(sum, 2934u); // 64 + 65 + ... + 99 + + // A fully empty trailing page must be skipped when retreating past it + this->m_slotMap.Reset(); + eastl::array trailingKeys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + trailingKeys[value] = this->m_slotMap.Insert(value); + } + for (std::uint32_t value = 64; value < elementCount; ++value) + { + this->m_slotMap.Remove(trailingKeys[value]); + } + + count = 0; + sum = 0; + for (const std::uint32_t value: this->m_slotMap) + { + ++count; + sum += value; + } + EXPECT_EQ(count, 64u); + EXPECT_EQ(sum, 2016u); // 0 + 1 + ... + 63 +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, ConstIterator) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const TypeParam& constMap = this->m_slotMap; + + // const_iterator is reachable two ways: cbegin()/cend(), or begin()/end() on a const object + EXPECT_EQ(this->m_slotMap.cbegin(), this->m_slotMap.cend()); + EXPECT_EQ(constMap.begin(), constMap.end()); + + std::ignore = this->m_slotMap.Insert(1); + const SlotMapKey key2 = this->m_slotMap.Insert(2); + std::ignore = this->m_slotMap.Insert(3); + + std::uint32_t expected = 1; + for (auto it = this->m_slotMap.cbegin(); it != this->m_slotMap.cend(); ++it) + { + EXPECT_EQ(*it, expected); + ++expected; + } + + expected = 1; + for (auto it = constMap.begin(); it != constMap.end(); ++it) + { + EXPECT_EQ(*it, expected); + ++expected; + } + + // Pre-increment advances and returns *this + auto preIt = this->m_slotMap.cbegin(); + auto& preIncrementResult = ++preIt; + EXPECT_EQ(&preIncrementResult, &preIt); + EXPECT_EQ(*preIt, 2); + + // Post-increment advances but returns the old value + auto postIt = this->m_slotMap.cbegin(); + const auto postIncrementResult = postIt++; + EXPECT_EQ(*postIncrementResult, 1); + EXPECT_EQ(*postIt, 2); + + // Pre-decrement retreats and returns *this + auto preDecIt = this->m_slotMap.cend(); + --preDecIt; // now at 3 + auto& preDecrementResult = --preDecIt; // now at 2 + EXPECT_EQ(&preDecrementResult, &preDecIt); + EXPECT_EQ(*preDecIt, 2); + + // Post-decrement retreats but returns the old value + auto postDecIt = this->m_slotMap.cend(); + --postDecIt; // now at 3 + const auto postDecrementResult = postDecIt--; + EXPECT_EQ(*postDecrementResult, 3); + EXPECT_EQ(*postDecIt, 2); + + // Removed slots are skipped identically through cbegin()/cend() and the const-object overloads + this->m_slotMap.Remove(key2); + + std::size_t count = 0; + std::uint32_t sum = 0; + for (auto it = this->m_slotMap.cbegin(); it != this->m_slotMap.cend(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, 2); + EXPECT_EQ(sum, 4); + + count = 0; + sum = 0; + for (auto it = constMap.begin(); it != constMap.end(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, 2); + EXPECT_EQ(sum, 4); + + // Multi-page traversal: StableSlotMap's PAGE_SIZE is 64, so 100 elements force it to span pages + this->m_slotMap.Reset(); + + constexpr std::uint32_t elementCount = 100; + eastl::array keys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + keys[value] = this->m_slotMap.Insert(value); + } + + expected = 0; + for (auto it = this->m_slotMap.cbegin(); it != this->m_slotMap.cend(); ++it) + { + EXPECT_EQ(*it, expected); + ++expected; + } + EXPECT_EQ(expected, elementCount); + + // Explicitly cross the page boundary (index 63 -> 64) forward and backward + auto boundaryIt = this->m_slotMap.cbegin(); + for (std::uint32_t step = 0; step < 63; ++step) + { + ++boundaryIt; + } + EXPECT_EQ(*boundaryIt, 63); + ++boundaryIt; + EXPECT_EQ(*boundaryIt, 64); + --boundaryIt; + EXPECT_EQ(*boundaryIt, 63); + + // Pre/post-increment/decrement across the boundary + auto preBoundaryIt = this->m_slotMap.cbegin(); + auto& preBoundaryIncrementResult = ++preBoundaryIt; + EXPECT_EQ(&preBoundaryIncrementResult, &preBoundaryIt); + EXPECT_EQ(*preBoundaryIt, 1); + + auto postBoundaryIt = this->m_slotMap.cbegin(); + const auto postBoundaryIncrementResult = postBoundaryIt++; + EXPECT_EQ(*postBoundaryIncrementResult, 0); + EXPECT_EQ(*postBoundaryIt, 1); + + auto preBoundaryDecIt = this->m_slotMap.cend(); + --preBoundaryDecIt; // now at 99 + auto& preBoundaryDecrementResult = --preBoundaryDecIt; // now at 98 + EXPECT_EQ(&preBoundaryDecrementResult, &preBoundaryDecIt); + EXPECT_EQ(*preBoundaryDecIt, 98); + + auto postBoundaryDecIt = this->m_slotMap.cend(); + --postBoundaryDecIt; // now at 99 + const auto postBoundaryDecrementResult = postBoundaryDecIt--; + EXPECT_EQ(*postBoundaryDecrementResult, 99); + EXPECT_EQ(*postBoundaryDecIt, 98); + + // Remove elements straddling the boundary and check the holes are skipped + this->m_slotMap.Remove(keys[63]); + this->m_slotMap.Remove(keys[64]); + + count = 0; + for (auto it = this->m_slotMap.cbegin(); it != this->m_slotMap.cend(); ++it) + { + EXPECT_NE(*it, 63); + EXPECT_NE(*it, 64); + ++count; + } + EXPECT_EQ(count, elementCount - 2); + + // A fully empty leading page must be skipped by cbegin()/SeekFirstFrom + this->m_slotMap.Reset(); + eastl::array leadingKeys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + leadingKeys[value] = this->m_slotMap.Insert(value); + } + for (std::uint32_t value = 0; value < 64; ++value) + { + this->m_slotMap.Remove(leadingKeys[value]); + } + + count = 0; + sum = 0; + for (auto it = this->m_slotMap.cbegin(); it != this->m_slotMap.cend(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, elementCount - 64); + EXPECT_EQ(sum, 2934u); // 64 + 65 + ... + 99 + + // A fully empty trailing page must be skipped when retreating past it + this->m_slotMap.Reset(); + eastl::array trailingKeys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + trailingKeys[value] = this->m_slotMap.Insert(value); + } + for (std::uint32_t value = 64; value < elementCount; ++value) + { + this->m_slotMap.Remove(trailingKeys[value]); + } + + count = 0; + sum = 0; + for (auto it = this->m_slotMap.cbegin(); it != this->m_slotMap.cend(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, 64u); + EXPECT_EQ(sum, 2016u); // 0 + 1 + ... + 63 +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, ReverseIterator) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + EXPECT_EQ(this->m_slotMap.rbegin(), this->m_slotMap.rend()); + + std::ignore = this->m_slotMap.Insert(1); + const SlotMapKey key2 = this->m_slotMap.Insert(2); + std::ignore = this->m_slotMap.Insert(3); + + // Reverse traversal mirrors insertion order + std::uint32_t expected = 3; + for (auto it = this->m_slotMap.rbegin(); it != this->m_slotMap.rend(); ++it) + { + EXPECT_EQ(*it, expected); + --expected; + } + + // Pre-increment advances and returns *this + auto preIt = this->m_slotMap.rbegin(); + auto& preIncrementResult = ++preIt; + EXPECT_EQ(&preIncrementResult, &preIt); + EXPECT_EQ(*preIt, 2); + + // Post-increment advances but returns the old value + auto postIt = this->m_slotMap.rbegin(); + const auto postIncrementResult = postIt++; + EXPECT_EQ(*postIncrementResult, 3); + EXPECT_EQ(*postIt, 2); + + // Pre-decrement retreats and returns *this + auto preDecIt = this->m_slotMap.rend(); + --preDecIt; // now at 1 + auto& preDecrementResult = --preDecIt; // now at 2 + EXPECT_EQ(&preDecrementResult, &preDecIt); + EXPECT_EQ(*preDecIt, 2); + + // Post-decrement retreats but returns the old value + auto postDecIt = this->m_slotMap.rend(); + --postDecIt; // now at 1 + const auto postDecrementResult = postDecIt--; + EXPECT_EQ(*postDecrementResult, 1); + EXPECT_EQ(*postDecIt, 2); + + // Removed slots are skipped during traversal + this->m_slotMap.Remove(key2); + + std::size_t count = 0; + std::uint32_t sum = 0; + for (auto it = this->m_slotMap.rbegin(); it != this->m_slotMap.rend(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, 2); + EXPECT_EQ(sum, 4); + + // Multi-page traversal: StableSlotMap's PAGE_SIZE is 64, so 100 elements force it to span pages + this->m_slotMap.Reset(); + + constexpr std::uint32_t elementCount = 100; + eastl::array keys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + keys[value] = this->m_slotMap.Insert(value); + } + + expected = elementCount - 1; + for (auto it = this->m_slotMap.rbegin(); it != this->m_slotMap.rend(); ++it) + { + EXPECT_EQ(*it, expected); + --expected; + } + + // Explicitly cross the page boundary (value 64 -> 63) forward and backward + auto boundaryIt = this->m_slotMap.rbegin(); + while (*boundaryIt != 64) + { + ++boundaryIt; + } + ++boundaryIt; + EXPECT_EQ(*boundaryIt, 63); + --boundaryIt; + EXPECT_EQ(*boundaryIt, 64); + + // Pre/post-increment/decrement across the boundary + auto preBoundaryIt = this->m_slotMap.rbegin(); + auto& preBoundaryIncrementResult = ++preBoundaryIt; + EXPECT_EQ(&preBoundaryIncrementResult, &preBoundaryIt); + EXPECT_EQ(*preBoundaryIt, 98); + + auto postBoundaryIt = this->m_slotMap.rbegin(); + const auto postBoundaryIncrementResult = postBoundaryIt++; + EXPECT_EQ(*postBoundaryIncrementResult, 99); + EXPECT_EQ(*postBoundaryIt, 98); + + auto preBoundaryDecIt = this->m_slotMap.rend(); + --preBoundaryDecIt; // now at 0 + auto& preBoundaryDecrementResult = --preBoundaryDecIt; // now at 1 + EXPECT_EQ(&preBoundaryDecrementResult, &preBoundaryDecIt); + EXPECT_EQ(*preBoundaryDecIt, 1); + + auto postBoundaryDecIt = this->m_slotMap.rend(); + --postBoundaryDecIt; // now at 0 + const auto postBoundaryDecrementResult = postBoundaryDecIt--; + EXPECT_EQ(*postBoundaryDecrementResult, 0); + EXPECT_EQ(*postBoundaryDecIt, 1); + + // Remove elements straddling the boundary and check the holes are skipped + this->m_slotMap.Remove(keys[63]); + this->m_slotMap.Remove(keys[64]); + + count = 0; + for (auto it = this->m_slotMap.rbegin(); it != this->m_slotMap.rend(); ++it) + { + EXPECT_NE(*it, 63); + EXPECT_NE(*it, 64); + ++count; + } + EXPECT_EQ(count, elementCount - 2); + + // A fully empty leading page must be skipped when retreating past it (rend() side) + this->m_slotMap.Reset(); + eastl::array leadingKeys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + leadingKeys[value] = this->m_slotMap.Insert(value); + } + for (std::uint32_t value = 0; value < 64; ++value) + { + this->m_slotMap.Remove(leadingKeys[value]); + } + + count = 0; + sum = 0; + for (auto it = this->m_slotMap.rbegin(); it != this->m_slotMap.rend(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, elementCount - 64); + EXPECT_EQ(sum, 2934u); // 64 + 65 + ... + 99 + + // A fully empty trailing page must be skipped by rbegin()/SeekLastFrom + this->m_slotMap.Reset(); + eastl::array trailingKeys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + trailingKeys[value] = this->m_slotMap.Insert(value); + } + for (std::uint32_t value = 64; value < elementCount; ++value) + { + this->m_slotMap.Remove(trailingKeys[value]); + } + + count = 0; + sum = 0; + for (auto it = this->m_slotMap.rbegin(); it != this->m_slotMap.rend(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, 64u); + EXPECT_EQ(sum, 2016u); // 0 + 1 + ... + 63 +} + +/****************************************************************************************/ + +TYPED_TEST(SlotMapFixture, ConstReverseIterator) +{ + using SlotMapKey = typename TestFixture::SlotMapKey; + + const TypeParam& constMap = this->m_slotMap; + + // const_reverse_iterator is reachable two ways: crbegin()/crend(), or rbegin()/rend() on a + // const object + EXPECT_EQ(this->m_slotMap.crbegin(), this->m_slotMap.crend()); + EXPECT_EQ(constMap.rbegin(), constMap.rend()); + + std::ignore = this->m_slotMap.Insert(1); + const SlotMapKey key2 = this->m_slotMap.Insert(2); + std::ignore = this->m_slotMap.Insert(3); + + std::uint32_t expected = 3; + for (auto it = this->m_slotMap.crbegin(); it != this->m_slotMap.crend(); ++it) + { + EXPECT_EQ(*it, expected); + --expected; + } + + expected = 3; + for (auto it = constMap.rbegin(); it != constMap.rend(); ++it) + { + EXPECT_EQ(*it, expected); + --expected; + } + + // Pre-increment advances and returns *this + auto preIt = this->m_slotMap.crbegin(); + auto& preIncrementResult = ++preIt; + EXPECT_EQ(&preIncrementResult, &preIt); + EXPECT_EQ(*preIt, 2); + + // Post-increment advances but returns the old value + auto postIt = this->m_slotMap.crbegin(); + const auto postIncrementResult = postIt++; + EXPECT_EQ(*postIncrementResult, 3); + EXPECT_EQ(*postIt, 2); + + // Pre-decrement retreats and returns *this + auto preDecIt = this->m_slotMap.crend(); + --preDecIt; // now at 1 + auto& preDecrementResult = --preDecIt; // now at 2 + EXPECT_EQ(&preDecrementResult, &preDecIt); + EXPECT_EQ(*preDecIt, 2); + + // Post-decrement retreats but returns the old value + auto postDecIt = this->m_slotMap.crend(); + --postDecIt; // now at 1 + const auto postDecrementResult = postDecIt--; + EXPECT_EQ(*postDecrementResult, 1); + EXPECT_EQ(*postDecIt, 2); + + // Removed slots are skipped identically through crbegin()/crend() and the const-object overloads + this->m_slotMap.Remove(key2); + + std::size_t count = 0; + std::uint32_t sum = 0; + for (auto it = this->m_slotMap.crbegin(); it != this->m_slotMap.crend(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, 2); + EXPECT_EQ(sum, 4); + + count = 0; + sum = 0; + for (auto it = constMap.rbegin(); it != constMap.rend(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, 2); + EXPECT_EQ(sum, 4); + + // Multi-page traversal: StableSlotMap's PAGE_SIZE is 64, so 100 elements force it to span pages + this->m_slotMap.Reset(); + + constexpr std::uint32_t elementCount = 100; + eastl::array keys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + keys[value] = this->m_slotMap.Insert(value); + } + + expected = elementCount - 1; + for (auto it = this->m_slotMap.crbegin(); it != this->m_slotMap.crend(); ++it) + { + EXPECT_EQ(*it, expected); + --expected; + } + + // Explicitly cross the page boundary (value 64 -> 63) forward and backward + auto boundaryIt = this->m_slotMap.crbegin(); + while (*boundaryIt != 64) + { + ++boundaryIt; + } + ++boundaryIt; + EXPECT_EQ(*boundaryIt, 63); + --boundaryIt; + EXPECT_EQ(*boundaryIt, 64); + + // Pre/post-increment/decrement across the boundary + auto preBoundaryIt = this->m_slotMap.crbegin(); + auto& preBoundaryIncrementResult = ++preBoundaryIt; + EXPECT_EQ(&preBoundaryIncrementResult, &preBoundaryIt); + EXPECT_EQ(*preBoundaryIt, 98); + + auto postBoundaryIt = this->m_slotMap.crbegin(); + const auto postBoundaryIncrementResult = postBoundaryIt++; + EXPECT_EQ(*postBoundaryIncrementResult, 99); + EXPECT_EQ(*postBoundaryIt, 98); + + auto preBoundaryDecIt = this->m_slotMap.crend(); + --preBoundaryDecIt; // now at 0 + auto& preBoundaryDecrementResult = --preBoundaryDecIt; // now at 1 + EXPECT_EQ(&preBoundaryDecrementResult, &preBoundaryDecIt); + EXPECT_EQ(*preBoundaryDecIt, 1); + + auto postBoundaryDecIt = this->m_slotMap.crend(); + --postBoundaryDecIt; // now at 0 + const auto postBoundaryDecrementResult = postBoundaryDecIt--; + EXPECT_EQ(*postBoundaryDecrementResult, 0); + EXPECT_EQ(*postBoundaryDecIt, 1); + + // Remove elements straddling the boundary and check the holes are skipped + this->m_slotMap.Remove(keys[63]); + this->m_slotMap.Remove(keys[64]); + + count = 0; + for (auto it = this->m_slotMap.crbegin(); it != this->m_slotMap.crend(); ++it) + { + EXPECT_NE(*it, 63); + EXPECT_NE(*it, 64); + ++count; + } + EXPECT_EQ(count, elementCount - 2); + + // A fully empty leading page must be skipped when retreating past it (crend() side) + this->m_slotMap.Reset(); + eastl::array leadingKeys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + leadingKeys[value] = this->m_slotMap.Insert(value); + } + for (std::uint32_t value = 0; value < 64; ++value) + { + this->m_slotMap.Remove(leadingKeys[value]); + } + + count = 0; + sum = 0; + for (auto it = this->m_slotMap.crbegin(); it != this->m_slotMap.crend(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, elementCount - 64); + EXPECT_EQ(sum, 2934u); // 64 + 65 + ... + 99 + + // A fully empty trailing page must be skipped by crbegin()/SeekLastFrom + this->m_slotMap.Reset(); + eastl::array trailingKeys; + for (std::uint32_t value = 0; value < elementCount; ++value) + { + trailingKeys[value] = this->m_slotMap.Insert(value); + } + for (std::uint32_t value = 64; value < elementCount; ++value) + { + this->m_slotMap.Remove(trailingKeys[value]); + } + + count = 0; + sum = 0; + for (auto it = this->m_slotMap.crbegin(); it != this->m_slotMap.crend(); ++it) + { + ++count; + sum += *it; + } + EXPECT_EQ(count, 64u); + EXPECT_EQ(sum, 2016u); // 0 + 1 + ... + 63 +} + +/****************************************************************************************/ + +// class StableSlotMapFixture: public ::testing::Test +// { +// protected: +// StableSlotMap m_slotMap; +// }; +// +// /****************************************************************************************/ +// +// TEST_F(StableSlotMapFixture, PointersAreStable) +// { +// const SlotMapKey key = m_slotMap.Insert(42); +// const std::uint32_t* const pointer = m_slotMap.Get(key); +// +// // Inserting enough elements to span multiple pages (PAGE_SIZE is 64) must not move already +// // -inserted data: unlike DenseSlotMap's contiguous eastl::vector, growth only appends new +// // Page objects (each individually heap-allocated), it never reallocates existing ones. +// constexpr std::uint32_t elementCount = 200; +// eastl::array keys; +// for (std::uint32_t value = 0; value < elementCount; ++value) +// { +// keys[value] = m_slotMap.Insert(value); +// } +// +// EXPECT_EQ(m_slotMap.Get(key), pointer); +// EXPECT_EQ(*pointer, 42); +// +// // Removing unrelated elements, including ones sharing the same page as key, must not move it +// // either: Remove() only destroys that slot in place, it never compacts the page's array. +// for (std::uint32_t value = 0; value < elementCount; value += 2) +// { +// m_slotMap.Remove(keys[value]); +// } +// +// EXPECT_EQ(m_slotMap.Get(key), pointer); +// EXPECT_EQ(*pointer, 42); +// +// // Re-inserting into the freed slots must not move it either +// for (std::uint32_t value = 0; value < elementCount / 2; ++value) +// { +// std::ignore = m_slotMap.Insert(value); +// } +// +// EXPECT_EQ(m_slotMap.Get(key), pointer); +// EXPECT_EQ(*pointer, 42); +// } +} // namespace Bigfoot diff --git a/Bigfoot/Tests/Utils/Include/UtilsTests/UtilsTestsLogger_generated.hpp b/Bigfoot/Tests/Utils/Include/UtilsTests/UtilsTestsLogger_generated.hpp new file mode 100644 index 0000000..956be17 --- /dev/null +++ b/Bigfoot/Tests/Utils/Include/UtilsTests/UtilsTestsLogger_generated.hpp @@ -0,0 +1,21 @@ +// AUTO-GENERATED DO NOT TOUCH + +/********************************************************************* + * \file UtilsTestsLogger.generated.hpp + * + *********************************************************************/ +#ifndef BIGFOOT_UTILSTESTSLOGGER_GENERATED_HPP +#define BIGFOOT_UTILSTESTSLOGGER_GENERATED_HPP +#include + +#if defined BIGFOOT_NOT_OPTIMIZED + +namespace Bigfoot +{ +/* + * Logger + */ +inline Log::LoggerInfo UTILSTESTS_LOGGER {"UTILSTESTS_LOGGER", Flat::LogLevel::Trace}; +} // namespace Bigfoot +#endif +#endif diff --git a/Bigfoot/Tests/Utils/Log/Log.cpp b/Bigfoot/Tests/Utils/Log/Log.cpp new file mode 100644 index 0000000..afd1a92 --- /dev/null +++ b/Bigfoot/Tests/Utils/Log/Log.cpp @@ -0,0 +1,97 @@ +/********************************************************************* + * \file Log.cpp + * + * \author Romain BOULLARD + * \date December 2022 + *********************************************************************/ +#include + +#include + +#include + +#if defined BIGFOOT_NOT_OPTIMIZED + +#include + +namespace Bigfoot +{ +class LogFixture: public ::testing::Test +{ + protected: + static constexpr Flat::LogLevel QuillLogLevelToLogLevel(const quill::LogLevel p_level) + { + switch (p_level) + { + case quill::LogLevel::Debug: + return Flat::LogLevel::Debug; + case quill::LogLevel::TraceL3: + return Flat::LogLevel::Trace; + case quill::LogLevel::Info: + return Flat::LogLevel::Info; + case quill::LogLevel::Warning: + return Flat::LogLevel::Warn; + case quill::LogLevel::Error: + return Flat::LogLevel::Error; + case quill::LogLevel::Critical: + return Flat::LogLevel::Critical; + default: + break; + } + + return Flat::LogLevel::Trace; + } +}; + +/****************************************************************************************/ + +TEST_F(LogFixture, RegisterLogger_ShouldRegisterTheLogger) +{ + const quill::Logger* logger = Singleton::GetInstance().RegisterLogger(UTILSTESTS_LOGGER); + EXPECT_TRUE(logger); + EXPECT_EQ(logger, Singleton::GetInstance().GetLogger(UTILSTESTS_LOGGER)); + EXPECT_EQ(logger->get_logger_name(), UTILSTESTS_LOGGER.m_name); + EXPECT_EQ(QuillLogLevelToLogLevel(logger->get_log_level()), UTILSTESTS_LOGGER.m_level); +} + +/****************************************************************************************/ + +TEST_F(LogFixture, UnregisterLogger_ShouldUnregisterTheLogger) +{ + std::ignore = Singleton::GetInstance().RegisterLogger(UTILSTESTS_LOGGER); + Singleton::GetInstance().UnregisterLogger(UTILSTESTS_LOGGER); + + EXPECT_EQ(Singleton::GetInstance().GetLogger(UTILSTESTS_LOGGER), nullptr); +} + +/****************************************************************************************/ + +TEST_F(LogFixture, GetLogger_ShouldReturnNullptrIfTheLoggerDoesNotExist) +{ + EXPECT_FALSE(Singleton::GetInstance().GetLogger(UTILSTESTS_LOGGER)); +} + +/****************************************************************************************/ + +TEST_F(LogFixture, GetLoger_ShouldReturnTheLoggerIfItExists) +{ + [[maybe_unused]] + const quill::Logger* logger = Singleton::GetInstance().RegisterLogger(UTILSTESTS_LOGGER); + EXPECT_TRUE(Singleton::GetInstance().GetLogger(UTILSTESTS_LOGGER)); +} + +/****************************************************************************************/ + +TEST_F(LogFixture, ChangeLoggerLogLevel_ShouldChangeTheLoggerLogLevel) +{ + const Flat::LogLevel previous = UTILSTESTS_LOGGER.m_level; + + const quill::Logger* logger = Singleton::GetInstance().RegisterLogger(UTILSTESTS_LOGGER); + + Singleton::GetInstance().ChangeLoggerLogLevel(UTILSTESTS_LOGGER, Flat::LogLevel::Critical); + EXPECT_EQ(QuillLogLevelToLogLevel(logger->get_log_level()), Flat::LogLevel::Critical); + Singleton::GetInstance().ChangeLoggerLogLevel(UTILSTESTS_LOGGER, previous); + EXPECT_EQ(QuillLogLevelToLogLevel(logger->get_log_level()), previous); +} +} // namespace Bigfoot +#endif diff --git a/Bigfoot/Tests/Utils/Log/LogMacros.cpp b/Bigfoot/Tests/Utils/Log/LogMacros.cpp new file mode 100644 index 0000000..aa6e328 --- /dev/null +++ b/Bigfoot/Tests/Utils/Log/LogMacros.cpp @@ -0,0 +1,64 @@ +/********************************************************************* + * \file LogMacros.cpp + * + * \author Romain BOULLARD + * \date May 2026 + *********************************************************************/ +#include + +#include + +#if defined BIGFOOT_NOT_OPTIMIZED + +#include + +namespace Bigfoot +{ +class LogMacrosFixture: public ::testing::Test +{ + protected: +}; + +/****************************************************************************************/ + +TEST_F(LogMacrosFixture, LogDebug) +{ + BIGFOOT_LOG_DEBUG(UTILSTESTS_LOGGER, "Hello"); +} + +/****************************************************************************************/ + +TEST_F(LogMacrosFixture, LogTrace) +{ + BIGFOOT_LOG_TRACE(UTILSTESTS_LOGGER, "Hello"); +} + +/****************************************************************************************/ + +TEST_F(LogMacrosFixture, LogInfo) +{ + BIGFOOT_LOG_INFO(UTILSTESTS_LOGGER, "Hello"); +} + +/****************************************************************************************/ + +TEST_F(LogMacrosFixture, LogWarn) +{ + BIGFOOT_LOG_WARN(UTILSTESTS_LOGGER, "Hello"); +} + +/****************************************************************************************/ + +TEST_F(LogMacrosFixture, LogError) +{ + BIGFOOT_LOG_ERROR(UTILSTESTS_LOGGER, "Hello"); +} + +/****************************************************************************************/ + +TEST_F(LogMacrosFixture, LogFatal) +{ + BIGFOOT_LOG_FATAL(UTILSTESTS_LOGGER, "Hello"); +} +} // namespace Bigfoot +#endif diff --git a/Bigfoot/Tests/Utils/Singleton.cpp b/Bigfoot/Tests/Utils/Singleton.cpp index 4f089b3..98e4839 100644 --- a/Bigfoot/Tests/Utils/Singleton.cpp +++ b/Bigfoot/Tests/Utils/Singleton.cpp @@ -42,7 +42,7 @@ class SingletonTest } [[nodiscard]] - std::uint32_t Data() const + std::uint32_t GetData() const { return m_data; } @@ -84,19 +84,19 @@ TEST_F(SingletonFixture, ConstructorAndDestructorShouldBeCalled) { ::testing::InSequence seq; - EXPECT_CALL(*m_mock, Construct()); - EXPECT_CALL(*m_mock, Destruct()); + EXPECT_CALL(*m_mock, Construct()).Times(1); + EXPECT_CALL(*m_mock, Destruct()).Times(1); Singleton::Lifetime singleton {42}; } /****************************************************************************************/ -TEST_F(SingletonFixture, Instance_ShouldReturnTheInstance) +TEST_F(SingletonFixture, GetInstance_ShouldReturnTheInstance) { Singleton::Lifetime singleton {42}; - EXPECT_EQ(Singleton::Instance().Data(), 42); + EXPECT_EQ(Singleton::GetInstance().GetData(), 42); } } // namespace Bigfoot diff --git a/Bigfoot/Tests/Utils/UtilsTests/main.cpp b/Bigfoot/Tests/Utils/UtilsTests/main.cpp new file mode 100644 index 0000000..6645ee3 --- /dev/null +++ b/Bigfoot/Tests/Utils/UtilsTests/main.cpp @@ -0,0 +1,19 @@ +/********************************************************************* + * \file main.cpp + * + * \author Romain BOULLARD + * \date May 2026 + *********************************************************************/ +#include +#include + +#include + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + + BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime); + + return RUN_ALL_TESTS(); +} diff --git a/Bigfoot/Tests/Utils/Version.cpp b/Bigfoot/Tests/Utils/Version.cpp index d2e6912..bba4a02 100644 --- a/Bigfoot/Tests/Utils/Version.cpp +++ b/Bigfoot/Tests/Utils/Version.cpp @@ -19,42 +19,42 @@ class VersionFixture: public ::testing::Test /****************************************************************************************/ -TEST_F(VersionFixture, string) +TEST_F(VersionFixture, ToString) { - EXPECT_STREQ(static_cast(m_detailed).data(), "1.2.3"); - EXPECT_STREQ(static_cast(m_combined).data(), "1.2.3"); + EXPECT_STREQ(m_detailed.ToString().data(), "1.2.3"); + EXPECT_STREQ(m_combined.ToString().data(), "1.2.3"); } /****************************************************************************************/ -TEST_F(VersionFixture, uint32_t) +TEST_F(VersionFixture, Raw) { - EXPECT_EQ(static_cast(m_detailed), (1 << 16) | (2 << 8) | 3); - EXPECT_EQ(static_cast(m_combined), (1 << 16) | (2 << 8) | 3); + EXPECT_EQ(m_detailed.Raw(), (1 << 16) | (2 << 8) | 3); + EXPECT_EQ(m_combined.Raw(), (1 << 16) | (2 << 8) | 3); } /****************************************************************************************/ -TEST_F(VersionFixture, Major_ShouldBeEqualToTheMajorPartOfTheVersion) +TEST_F(VersionFixture, GetMajor_ShouldBeEqualToTheMajorPartOfTheVersion) { - EXPECT_EQ(m_detailed.Major(), 1); - EXPECT_EQ(m_combined.Major(), 1); + EXPECT_EQ(m_detailed.GetMajor(), 1); + EXPECT_EQ(m_combined.GetMajor(), 1); } /****************************************************************************************/ -TEST_F(VersionFixture, Minor_ShouldBeEqualToTheMinorPartOfTheVersion) +TEST_F(VersionFixture, GetMinor_ShouldBeEqualToTheMinorPartOfTheVersion) { - EXPECT_EQ(m_detailed.Minor(), 2); - EXPECT_EQ(m_combined.Minor(), 2); + EXPECT_EQ(m_detailed.GetMinor(), 2); + EXPECT_EQ(m_combined.GetMinor(), 2); } /****************************************************************************************/ -TEST_F(VersionFixture, Patch_ShouldBeEqualToThePatchPartOfTheVersion) +TEST_F(VersionFixture, GetPatch_ShouldBeEqualToThePatchPartOfTheVersion) { - EXPECT_EQ(m_detailed.Patch(), 3); - EXPECT_EQ(m_combined.Patch(), 3); + EXPECT_EQ(m_detailed.GetPatch(), 3); + EXPECT_EQ(m_combined.GetPatch(), 3); } /****************************************************************************************/ diff --git a/CMake/CustomTargets.cmake b/CMake/CustomTargets.cmake new file mode 100644 index 0000000..5008561 --- /dev/null +++ b/CMake/CustomTargets.cmake @@ -0,0 +1,19 @@ +add_library(BigfootCompileAndLinkFlags INTERFACE) + +target_compile_options(BigfootCompileAndLinkFlags INTERFACE + $<$:/W4 /WX> + $<$:-Wall -Wextra -Wpedantic -Werror> + $<$,$>:-fprofile-instr-generate -fcoverage-mapping> +) + +target_link_options(BigfootCompileAndLinkFlags INTERFACE + $<$,$>:-fprofile-instr-generate> +) + +target_compile_definitions(BigfootCompileAndLinkFlags INTERFACE + $<$:NOMINMAX> + $<$:WIN32_LEAN_AND_MEAN> + $<$:BIGFOOT_WINDOWS> + $<$:BIGFOOT_LINUX> + $<$:BIGFOOT_OPTIMIZED> + $<$:BIGFOOT_NOT_OPTIMIZED>) \ No newline at end of file diff --git a/CMake/FindDependencies.cmake b/CMake/FindDependencies.cmake index b56d7f0..a344941 100644 --- a/CMake/FindDependencies.cmake +++ b/CMake/FindDependencies.cmake @@ -7,10 +7,13 @@ endif() find_package(EASTL REQUIRED) find_package(unordered_dense REQUIRED) -find_package(mimalloc REQUIRED) +if(${ASAN}) + find_package(mimalloc-asan REQUIRED) +else() + find_package(mimalloc REQUIRED) +endif() find_package(stduuid REQUIRED) find_package(SQLite3 REQUIRED) -find_package(CLI11 REQUIRED) find_package(rapidhash REQUIRED) find_package(effolkronium_random REQUIRED) find_package(flatbuffers CONFIG REQUIRED) @@ -21,44 +24,24 @@ endif() if(${IS_MULTI_CONFIG}) find_package(quill REQUIRED) - find_package(cpptrace REQUIRED) elseif(${CMAKE_BUILD_TYPE} STREQUAL "Debug" OR ${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo") find_package(quill REQUIRED) - find_package(cpptrace REQUIRED) endif() - find_package(glm REQUIRED) find_package(lodepng REQUIRED) find_package(imgui REQUIRED) if(VULKAN) find_package(VulkanHeaders REQUIRED) - if(${IS_MULTI_CONFIG}) - find_package(vulkan-validationlayers REQUIRED) - elseif(${CMAKE_BUILD_TYPE} STREQUAL "Debug" OR ${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo") - find_package(vulkan-validationlayers REQUIRED) - endif() find_package(vulkan-memory-allocator REQUIRED) endif() -if(BUILD_BENCHMARKS OR BUILD_TESTS OR SAMPLE_APP) - find_package(glfw3 REQUIRED) -endif() - if(BUILD_TESTS) find_package(GTest REQUIRED) find_package(pixelmatch-cpp17 REQUIRED) endif() -if(BUILD_TOOLS) - find_package(spirv-cross REQUIRED) - find_package(shaderc REQUIRED) - find_package(assimp REQUIRED) - find_package(meshoptimizer REQUIRED) - find_package(libsquish REQUIRED) -endif() - if(BUILD_BENCHMARKS) find_package(benchmark REQUIRED) endif() \ No newline at end of file diff --git a/CMake/Package.cmake b/CMake/Package.cmake index ed86db9..566875a 100644 --- a/CMake/Package.cmake +++ b/CMake/Package.cmake @@ -1,97 +1,308 @@ function(bigfoot_create_package_lib PackagePublicDependencies PackagePrivateDependencies PackageBigfootPublicDependencies PackageBigfootPrivateDependencies ParentFolder) add_library(${PROJECT_NAME} STATIC) - set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) - target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Include) + target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) - bigfoot_compile_flatbuffers("${PackageBigfootPublicDependencies}") + target_link_libraries(${PROJECT_NAME} + PRIVATE + BigfootCompileAndLinkFlags + PUBLIC + ${PackagePublicDependencies} + $ - # collect sources (reconfigure when files are added/removed) - file(GLOB_RECURSE _BF_SOURCES - CONFIGURE_DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/*.h - ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp.in - ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/*.fbs - ${CMAKE_CURRENT_SOURCE_DIR}/*.sql + PRIVATE + ${PackagePrivateDependencies} + $) + + bigfoot_compile_flatbuffers() + + file(GLOB_RECURSE _SOURCES + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp + ) + + file(GLOB_RECURSE _HEADERS + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp + ) + + file(GLOB_RECURSE _OTHERS + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/*.fbs + ${CMAKE_CURRENT_SOURCE_DIR}/*.sql ) target_sources(${PROJECT_NAME} PRIVATE - ${_BF_SOURCES} + ${_SOURCES} + ${_OTHERS} + PUBLIC + FILE_SET HEADERS + BASE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/Include + FILES + ${_HEADERS} ) - target_compile_options(${PROJECT_NAME} PRIVATE ${BIGFOOT_CXX_FLAGS}) - - target_link_libraries(${PROJECT_NAME} PUBLIC unordered_dense::unordered_dense EASTL::EASTL flatbuffers::flatbuffers rapidhash::rapidhash) - target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_DL_LIBS}) - - target_link_libraries(${PROJECT_NAME} PUBLIC ${PackagePublicDependencies}) - target_link_libraries(${PROJECT_NAME} PRIVATE ${PackagePrivateDependencies}) - target_link_libraries(${PROJECT_NAME} PUBLIC $) - target_link_libraries(${PROJECT_NAME} PRIVATE $) - - source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src FILES ${_BF_SOURCES}) + source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src FILES ${_SOURCES} ${_HEADERS} ${_OTHERS}) set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Bigfoot/${ParentFolder}) endfunction() -function(bigfoot_create_package_tests ParentFolder BigfootDependencies) +function(bigfoot_create_package_tests PackageDependencies PackageBigfootDependencies ParentFolder) add_executable(${PROJECT_NAME}) - set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) - bigfoot_compile_flatbuffers("${BigfootDependencies}") + target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) - file(GLOB_RECURSE _BF_TEST_SOURCES - CONFIGURE_DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/*.h - ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp.in - ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/*.fbs + target_link_libraries(${PROJECT_NAME} + PRIVATE + BigfootCompileAndLinkFlags + ${PackageDependencies} + $ + $ + gtest::gtest) + + bigfoot_compile_flatbuffers() + + file(GLOB_RECURSE _SOURCES + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp + ) + + file(GLOB_RECURSE _HEADERS + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp + ) + + file(GLOB_RECURSE _OTHERS + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/*.fbs + ${CMAKE_CURRENT_SOURCE_DIR}/*.sql ) target_sources(${PROJECT_NAME} PRIVATE - ${_BF_TEST_SOURCES} + ${_SOURCES} + ${_OTHERS} + PUBLIC + FILE_SET HEADERS + BASE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/Include + FILES + ${_HEADERS} ) - target_compile_options(${PROJECT_NAME} PRIVATE ${BIGFOOT_CXX_FLAGS}) - target_link_options(${PROJECT_NAME} PRIVATE ${BIGFOOT_EXE_LINK_FLAGS}) - - target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Include) - - target_link_libraries(${PROJECT_NAME} PRIVATE $) - target_link_libraries(${PROJECT_NAME} PRIVATE gtest::gtest) - include(GoogleTest) gtest_discover_tests(${PROJECT_NAME} XML_OUTPUT_DIR ${CMAKE_BINARY_DIR}/TestResults/) - source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src/ FILES ${_BF_TEST_SOURCES}) + source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src/ FILES ${_SOURCES} ${_HEADERS} ${_OTHERS}) set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Tests/Bigfoot/${ParentFolder}) + set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$") + + ##################ASAN SETUP################### + + if(${ASAN}) + if(MSVC) + get_filename_component(MSVC_BIN_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY) + set(ASAN_DLL "${MSVC_BIN_DIR}/clang_rt.asan_dynamic-x86_64.dll") + + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-asan.timestamp" + DEPENDS "${ASAN_DLL}" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${ASAN_DLL}" "$" + COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-asan.timestamp" + COMMENT "Copying ASan DLL for ${PROJECT_NAME}" + ) + + add_custom_target(${PROJECT_NAME}Asan + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-asan.timestamp" + ) + + add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}Asan) + set_target_properties(${PROJECT_NAME}Asan PROPERTIES FOLDER UtilityTargets/Tests/Bigfoot/${ParentFolder}) + endif() + endif() ##################COPY FIXTURE FOLDER################### - if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Fixture) file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Fixture) endif() - # Track all fixture files file(GLOB_RECURSE FIXTURE_FILES - CONFIGURE_DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/Fixture/* + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/Fixture/* + ) + + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-fixture.timestamp" + DEPENDS ${FIXTURE_FILES} + COMMAND ${CMAKE_COMMAND} -E remove_directory $/Fixture + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/Fixture $/Fixture + COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-fixture.timestamp" + COMMENT "Copying Fixture folder for ${PROJECT_NAME}" ) add_custom_target(${PROJECT_NAME}Fixture - COMMAND ${CMAKE_COMMAND} -E remove_directory $/Fixture - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/Fixture $/Fixture - DEPENDS ${FIXTURE_FILES} - COMMENT "Copying Fixture folder for ${PROJECT_NAME}" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-fixture.timestamp" ) add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}Fixture) - set_target_properties(${PROJECT_NAME}Fixture PROPERTIES FOLDER UtilityTargets/Tests/Bigfoot/${ParentFolder}) +endfunction() + +function(bigfoot_create_package_tests_helper_lib PackagePublicDependencies PackagePrivateDependencies PackageBigfootPublicDependencies PackageBigfootPrivateDependencies ParentFolder) + add_library(${PROJECT_NAME} STATIC) + + target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) + + target_link_libraries(${PROJECT_NAME} + PRIVATE + BigfootCompileAndLinkFlags + PUBLIC + ${PackagePublicDependencies} + $ + + PRIVATE + ${PackagePrivateDependencies} + $) + + bigfoot_compile_flatbuffers() + + file(GLOB_RECURSE _SOURCES + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp + ) + + file(GLOB_RECURSE _HEADERS + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp + ) + + file(GLOB_RECURSE _OTHERS + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/*.fbs + ${CMAKE_CURRENT_SOURCE_DIR}/*.sql + ) + + target_sources(${PROJECT_NAME} + PRIVATE + ${_SOURCES} + ${_OTHERS} + PUBLIC + FILE_SET HEADERS + BASE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/Include + FILES + ${_HEADERS} + ) + + source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src FILES ${_SOURCES} ${_HEADERS} ${_OTHERS}) + + set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Tests/Bigfoot/${ParentFolder}) +endfunction() + +function(bigfoot_create_package_benchmarks ParentFolder) + add_executable(${PROJECT_NAME}) + + target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) + + target_link_libraries(${PROJECT_NAME} + PRIVATE + BigfootCompileAndLinkFlags + $ + benchmark::benchmark_main) + + bigfoot_compile_flatbuffers() + + file(GLOB_RECURSE _SOURCES + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp + ) + + file(GLOB_RECURSE _HEADERS + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp + ) + + file(GLOB_RECURSE _OTHERS + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/*.fbs + ${CMAKE_CURRENT_SOURCE_DIR}/*.sql + ) + + target_sources(${PROJECT_NAME} + PRIVATE + ${_SOURCES} + ${_OTHERS} + PUBLIC + FILE_SET HEADERS + BASE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/Include + FILES + ${_HEADERS} + ) + + source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src/ FILES ${_SOURCES} ${_HEADERS} ${_OTHERS}) + + set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Benchmarks/Bigfoot/${ParentFolder}) + set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$") + + ##################ASAN SETUP################### + + if(${ASAN}) + if(MSVC) + get_filename_component(MSVC_BIN_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY) + set(ASAN_DLL "${MSVC_BIN_DIR}/clang_rt.asan_dynamic-x86_64.dll") + + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-asan.timestamp" + DEPENDS "${ASAN_DLL}" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${ASAN_DLL}" "$" + COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-asan.timestamp" + COMMENT "Copying ASan DLL for ${PROJECT_NAME}" + ) + + add_custom_target(${PROJECT_NAME}Asan + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-asan.timestamp" + ) + + add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}Asan) + set_target_properties(${PROJECT_NAME}Asan PROPERTIES FOLDER UtilityTargets/Benchmarks/Bigfoot/${ParentFolder}) + endif() + endif() + + ##################COPY FIXTURE FOLDER################### + if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Fixture) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Fixture) + endif() + + file(GLOB_RECURSE FIXTURE_FILES + CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/Fixture/* + ) + + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-fixture.timestamp" + DEPENDS ${FIXTURE_FILES} + COMMAND ${CMAKE_COMMAND} -E remove_directory $/Fixture + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/Fixture $/Fixture + COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-fixture.timestamp" + COMMENT "Copying Fixture folder for ${PROJECT_NAME}" + ) + + add_custom_target(${PROJECT_NAME}Fixture + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-fixture.timestamp" + ) + + add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}Fixture) + set_target_properties(${PROJECT_NAME}Fixture PROPERTIES FOLDER UtilityTargets/Benchmarks/Bigfoot/${ParentFolder}) endfunction() \ No newline at end of file diff --git a/CMake/Utils.cmake b/CMake/Utils.cmake index 9841ed8..ca0166f 100644 --- a/CMake/Utils.cmake +++ b/CMake/Utils.cmake @@ -2,7 +2,7 @@ function(bigfoot_create_logger) set(LOGGER_FILENAME ${PROJECT_NAME}Logger) string(TOUPPER ${PROJECT_NAME}_Logger LOGGER_NAME) string(TOUPPER ${LOGGER_FILENAME} LOGGER_FILENAME_UPPER) - configure_file( ${CMAKE_SOURCE_DIR}/Bigfoot/Sources/System/Include/System/Log/TargetLogger_generated.hpp.in + configure_file( ${CMAKE_SOURCE_DIR}/Bigfoot/Sources/Utils/Include/Utils/Log/TargetLogger_generated.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/Include/${PROJECT_NAME}/${LOGGER_FILENAME}_generated.hpp @ONLY) endfunction() @@ -20,35 +20,71 @@ function(bigfoot_create_bigfile ParentFolder) COMMAND ${CMAKE_COMMAND} -E touch ${OUTPUT_PATH_BIGFILE_ABSOLUTE}.bftimestamp COMMENT "Creating Bigfile ${OUTPUT_PATH_BIGFILE_ABSOLUTE}" ) - list(APPEND BIGFILE_SOURCES ${OUTPUT_PATH_BIGFILE_ABSOLUTE}.bftimestamp) - add_custom_target(${PROJECT_NAME}BigFile ALL DEPENDS ${BIGFILE_SOURCES}) + add_custom_target(${PROJECT_NAME}BigFile ALL + DEPENDS ${OUTPUT_PATH_BIGFILE_ABSOLUTE}.bftimestamp + ) + set_target_properties(${PROJECT_NAME}BigFile PROPERTIES FOLDER UtilityTargets/${ParentFolder}) - add_dependencies(${PROJECT_NAME}BigFile ${PROJECT_NAME}) - - target_sources(${PROJECT_NAME}BigFile PRIVATE ${BIGFILE_SOURCES}) + + add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}BigFile) string(TOUPPER ${PROJECT_NAME} BIGFILE_NAME) set(BIGFILE_LOCATION "./${PROJECT_NAME}-bigfile.db") - configure_file( ${CMAKE_SOURCE_DIR}/Bigfoot/Sources/Engine/Include/Engine/BigFile/BigFileInfo_generated.hpp.in - ${CMAKE_CURRENT_SOURCE_DIR}/Include/${PROJECT_NAME}/BigFileInfo_generated.hpp - @ONLY) + configure_file( + ${CMAKE_SOURCE_DIR}/Bigfoot/Sources/Engine/Include/Engine/BigFile/BigFileInfo_generated.hpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/Include/${PROJECT_NAME}/BigFileInfo_generated.hpp + @ONLY + ) endfunction() -function(bigfoot_compile_flatbuffers BigfootDependencies) - set(IncludeFolders "") - - get_target_property(CurrentTargetDependencyInclude ${PROJECT_NAME} INCLUDE_DIRECTORIES) - if(CurrentTargetDependencyInclude) - list(APPEND IncludeFolders ${CurrentTargetDependencyInclude}) +function(_bigfoot_collect_includes_recursive Target UseAllLinks) + get_property(_Visited GLOBAL PROPERTY _BIGFOOT_VISITED_TARGETS) + if("${Target}" IN_LIST _Visited) + return() endif() - - foreach(Dependency IN LISTS BigfootDependencies) - get_target_property(DependencyInclude ${Dependency} INCLUDE_DIRECTORIES) - if(DependencyInclude) - list(APPEND IncludeFolders ${DependencyInclude}) + set_property(GLOBAL APPEND PROPERTY _BIGFOOT_VISITED_TARGETS "${Target}") + + get_target_property(_IncDirs "${Target}" INTERFACE_INCLUDE_DIRECTORIES) + if(_IncDirs) + foreach(_Dir IN LISTS _IncDirs) + if(_Dir MATCHES "^\\$$") + set_property(GLOBAL APPEND PROPERTY _BIGFOOT_INCLUDE_DIRS "${CMAKE_MATCH_1}") + elseif(NOT _Dir MATCHES "^\\$<") + set_property(GLOBAL APPEND PROPERTY _BIGFOOT_INCLUDE_DIRS "${_Dir}") + endif() + endforeach() + endif() + + if(UseAllLinks) + get_target_property(_Libs "${Target}" LINK_LIBRARIES) + else() + get_target_property(_Libs "${Target}" INTERFACE_LINK_LIBRARIES) + endif() + if(NOT _Libs) + return() + endif() + foreach(_Lib IN LISTS _Libs) + if(_Lib MATCHES "^\\$$") + foreach(_Inner IN LISTS CMAKE_MATCH_1) + if(TARGET "${_Inner}") + _bigfoot_collect_includes_recursive("${_Inner}" FALSE) + endif() + endforeach() + elseif(NOT _Lib MATCHES "^\\$<" AND TARGET "${_Lib}") + _bigfoot_collect_includes_recursive("${_Lib}" FALSE) endif() endforeach() +endfunction() + +function(bigfoot_compile_flatbuffers) + set_property(GLOBAL PROPERTY _BIGFOOT_VISITED_TARGETS "") + set_property(GLOBAL PROPERTY _BIGFOOT_INCLUDE_DIRS "") + _bigfoot_collect_includes_recursive(${PROJECT_NAME} TRUE) + + get_property(_CollectedDirs GLOBAL PROPERTY _BIGFOOT_INCLUDE_DIRS) + set(IncludeFolders "${CMAKE_CURRENT_SOURCE_DIR}/Include" ${_CollectedDirs}) + list(REMOVE_DUPLICATES IncludeFolders) set(IncludeFlags "") foreach(folder IN LISTS IncludeFolders) @@ -58,7 +94,6 @@ function(bigfoot_compile_flatbuffers BigfootDependencies) file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/Include/*.fbs") foreach(SOURCE_FILE IN LISTS SOURCES) get_filename_component(SOURCE_DIRECTORY ${SOURCE_FILE} DIRECTORY) - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${SOURCE_FILE}) execute_process( @@ -67,9 +102,9 @@ function(bigfoot_compile_flatbuffers BigfootDependencies) ${IncludeFlags} --keep-prefix --filename-ext "hpp" - --reflect-types --cpp-std c++17 --reflect-names + --reflect-types --gen-name-strings --gen-object-api --cpp-str-flex-ctor @@ -77,69 +112,19 @@ function(bigfoot_compile_flatbuffers BigfootDependencies) --force-empty --cpp-ptr-type "eastl::unique_ptr" --cpp-str-type "eastl::string" + --cpp-vector-type "eastl::vector" --cpp-include "EASTL/unique_ptr.h" --cpp-include "EASTL/string.h" + --cpp-include "EASTL/vector.h" -o "${SOURCE_DIRECTORY}" - "${SOURCE_FILE}" + --schema "${SOURCE_FILE}" ) endforeach() endfunction() -function(bigfoot_setup_dependencies ParentFolder) - set(CONAN_DEPLOYER_DIR "${CMAKE_SOURCE_DIR}/build/full_deploy/host") - - if(EXISTS ${CONAN_DEPLOYER_DIR}) - if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - file(GLOB_RECURSE SHARED_BINARIES ${CONAN_DEPLOYER_DIR}/*mimalloc*.dll) - elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") - file(GLOB_RECURSE SHARED_BINARIES ${CONAN_DEPLOYER_DIR}/*mimalloc*.so*) - endif() - - if(${IS_MULTI_CONFIG}) - foreach(CONFIG ${CMAKE_CONFIGURATION_TYPES}) - foreach(file ${SHARED_BINARIES}) - if(file MATCHES "/${CONFIG}/") - list(APPEND SHARED_BINARIES_${CONFIG} ${file}) - endif() - endforeach() - endforeach() - - add_custom_target(${PROJECT_NAME}CopySharedBinaries - ALL DEPENDS SHARED_BINARIES - COMMAND ${CMAKE_COMMAND} -E make_directory $ - COMMAND ${CMAKE_COMMAND} -E $,copy_if_different,true> ${SHARED_BINARIES_Debug} $ - COMMAND ${CMAKE_COMMAND} -E $,copy_if_different,true> ${SHARED_BINARIES_Release} $ - COMMAND ${CMAKE_COMMAND} -E $,copy_if_different,true> ${SHARED_BINARIES_RelWithDebInfo} $ - COMMENT "Copy shared binaries for ${PROJECT_NAME}" - ) - add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}CopySharedBinaries) - set_target_properties(${PROJECT_NAME}CopySharedBinaries PROPERTIES FOLDER UtilityTargets/${ParentFolder}) - - else() - foreach(file ${SHARED_BINARIES}) - if(file MATCHES "/${CMAKE_BUILD_TYPE}/") - list(APPEND SHARED_BINARIES_${CMAKE_BUILD_TYPE} ${file}) - endif() - endforeach() - - add_custom_target(${PROJECT_NAME}CopySharedBinaries ALL - DEPENDS ${SHARED_BINARIES_${CMAKE_BUILD_TYPE}} - COMMAND ${CMAKE_COMMAND} -E make_directory $ - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SHARED_BINARIES_${CMAKE_BUILD_TYPE}} $ - COMMENT "Copy shared binaries for ${PROJECT_NAME}" - ) - add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}CopySharedBinaries) - set_target_properties(${PROJECT_NAME}CopySharedBinaries PROPERTIES FOLDER UtilityTargets/${ParentFolder}) - endif() +macro(bigfoot_remove_default_exception_flags) + if(MSVC) + string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "/EHs" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") endif() - - if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - add_custom_target(${PROJECT_NAME}PatchMinject ALL - COMMAND ${MINJECT_EXECUTABLE} -i -f $ - COMMENT "Patching ${PROJECT_NAME} to ensure mimalloc dynamic override" - ) - add_dependencies(${PROJECT_NAME}PatchMinject ${PROJECT_NAME}) - set_target_properties(${PROJECT_NAME}PatchMinject PROPERTIES FOLDER "UtilityTargets/${ParentFolder}") - endif() - -endfunction() \ No newline at end of file +endmacro() \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 665a2ff..34673e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,28 +1,24 @@ -cmake_minimum_required(VERSION 3.24) - -# CMake sets this flag by default, we don't use exception in bigfoot, we can remove it -string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +cmake_minimum_required(VERSION 3.26) project(Bigfoot VERSION 0.1.0 DESCRIPTION "The Bigfoot engine" LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED True) - set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) set(CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo;Debug" CACHE STRING "" FORCE) option(BUILD_TESTS OFF) -option(TRACY ON) -option(BUILD_TOOLS ON) -option(VULKAN ON) option(BUILD_BENCHMARKS OFF) +option(ASAN OFF) +option(COVERAGE OFF) +option(TRACY ON) +option(VULKAN ON) set(AUTO_GENERATED_COMMENT "// AUTO-GENERATED DO NOT TOUCH") +include(${CMAKE_SOURCE_DIR}/CMake/CustomTargets.cmake) include(${CMAKE_SOURCE_DIR}/CMake/FindDependencies.cmake) include(${CMAKE_SOURCE_DIR}/CMake/Utils.cmake) include(${CMAKE_SOURCE_DIR}/CMake/Package.cmake) @@ -30,18 +26,13 @@ include(${CMAKE_SOURCE_DIR}/CMake/Package.cmake) find_program(FLATBUFFERS_FLATC_EXECUTABLE NAMES flatc) find_program(SQLITE3_EXECUTABLE NAMES sqlite3) find_program(MINJECT_EXECUTABLE NAMES minject) +find_program(BIN2CPP_EXECUTABLE NAMES Bin2CPP) + +bigfoot_remove_default_exception_flags() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_OPTIMIZE_DEPENDENCIES 1) -add_compile_definitions( - $<$:NOMINMAX> - $<$:WIN32_LEAN_AND_MEAN> - $<$:BIGFOOT_WINDOWS> - $<$:BIGFOOT_LINUX> - $<$:BIGFOOT_OPTIMIZED> - $<$:BIGFOOT_NOT_OPTIMIZED>) - if(BUILD_TESTS) enable_testing() endif() @@ -56,6 +47,9 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Bigfoot/Sources) if(${BUILD_TESTS}) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Bigfoot/Tests) endif() +if(${BUILD_BENCHMARKS}) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Bigfoot/Benchmarks) +endif() add_custom_target(NatVis SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Vendor/NatVis/EASTL/EASTL.natvis diff --git a/ConanProfiles/Toolchains/ipo.cmake b/ConanProfiles/Toolchains/ipo.cmake new file mode 100644 index 0000000..7e83475 --- /dev/null +++ b/ConanProfiles/Toolchains/ipo.cmake @@ -0,0 +1,5 @@ +include_guard() + +set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) + +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE) \ No newline at end of file diff --git a/ConanProfiles/Toolchains/ipo.ini b/ConanProfiles/Toolchains/ipo.ini new file mode 100644 index 0000000..bf155da --- /dev/null +++ b/ConanProfiles/Toolchains/ipo.ini @@ -0,0 +1,2 @@ +[built-in options] +b_lto = true \ No newline at end of file diff --git a/ConanProfiles/Toolchains/mold.cmake b/ConanProfiles/Toolchains/mold.cmake new file mode 100644 index 0000000..8d48ddf --- /dev/null +++ b/ConanProfiles/Toolchains/mold.cmake @@ -0,0 +1,9 @@ +include_guard() + +find_program(MOLD_PROGRAM mold) +if (MOLD_PROGRAM) + set(CMAKE_LINKER_TYPE MOLD) + message(STATUS "mold linker found: ${MOLD_PROGRAM}") +else () + message(WARNING "mold linker not found") +endif () \ No newline at end of file diff --git a/ConanProfiles/Tools/clang b/ConanProfiles/Tools/clang new file mode 100644 index 0000000..5a2af6e --- /dev/null +++ b/ConanProfiles/Tools/clang @@ -0,0 +1,22 @@ +[settings] +os=Linux +arch=x86_64 +compiler=clang +compiler.version=20 +compiler.libcxx=libstdc++11 +compiler.cppstd=20 +compiler.cstd=17 +compiler.runtime=static +build_type=Release + +[conf] +tools.cmake.cmaketoolchain:user_toolchain+={{profile_dir}}/../Toolchains/ipo.cmake +tools.meson.mesontoolchain:extra_machine_files+={{profile_dir}}/../Toolchains/ipo.ini + +tools.system.package_manager:mode=install +tools.system.package_manager:sudo=True + +tools.build:compiler_executables={"c": "clang", "cpp": "clang++"} + +[tool_requires] +!cmake/*: cmake/4.3.2 \ No newline at end of file diff --git a/ConanProfiles/Tools/msvc b/ConanProfiles/Tools/msvc new file mode 100644 index 0000000..fff6508 --- /dev/null +++ b/ConanProfiles/Tools/msvc @@ -0,0 +1,21 @@ +[settings] +os=Windows +arch=x86_64 +compiler=msvc +compiler.version=195 +compiler.cppstd=20 +compiler.cstd=17 +compiler.runtime=static +build_type=Release + +[conf] +tools.cmake.cmaketoolchain:user_toolchain+={{profile_dir}}/../Toolchains/ipo.cmake +tools.meson.mesontoolchain:extra_machine_files+={{profile_dir}}/../Toolchains/ipo.ini + +tools.build:cflags=["/Zc:preprocessor", "/Zc:__STDC__", "/D_CRT_DECLARE_NONSTDC_NAMES=1"] +tools.build:cxxflags=["/Zc:preprocessor", "/permissive-", "/Zc:__cplusplus", "/Zc:enumTypes", "/Zc:templateScope"] + +tools.env.virtualenv:powershell=powershell.exe + +[tool_requires] +!cmake/*: cmake/4.3.2 \ No newline at end of file diff --git a/ConanProfiles/clang b/ConanProfiles/clang new file mode 100644 index 0000000..99256b0 --- /dev/null +++ b/ConanProfiles/clang @@ -0,0 +1,32 @@ +[settings] +os=Linux +arch=x86_64 +compiler=clang +compiler.version=20 +compiler.libcxx=libstdc++11 +compiler.cppstd=20 +compiler.cstd=17 +compiler.runtime=static +build_type=Release + +[conf] +tools.cmake.cmaketoolchain:user_toolchain+={{profile_dir}}/Toolchains/mold.cmake +tools.cmake.cmaketoolchain:user_toolchain+={{profile_dir}}/Toolchains/ipo.cmake +tools.meson.mesontoolchain:extra_machine_files+={{profile_dir}}/Toolchains/ipo.ini + +tools.system.package_manager:mode=install +tools.system.package_manager:sudo=True + +tools.build:cxxflags=["-fno-exceptions", "-fno-rtti"] + +tools.build:compiler_executables={"c": "clang", "cpp": "clang++"} + +tools.cmake.cmaketoolchain:generator=Ninja + +[tool_requires] +!cmake/*:cmake/4.3.2 +!mold/*:mold/2.41.0@bigfootdev/main +!ninja/*:ninja/1.13.2 + +[options] +bigfoot/*:build_tests=True \ No newline at end of file diff --git a/ConanProfiles/clang_asan b/ConanProfiles/clang_asan new file mode 100644 index 0000000..266cc86 --- /dev/null +++ b/ConanProfiles/clang_asan @@ -0,0 +1,35 @@ +[settings] +os=Linux +arch=x86_64 +compiler=clang +compiler.version=20 +compiler.libcxx=libstdc++11 +compiler.cppstd=20 +compiler.cstd=17 +compiler.runtime=static +build_type=Debug + +[conf] +tools.cmake.cmaketoolchain:user_toolchain+={{profile_dir}}/Toolchains/mold.cmake + +tools.system.package_manager:mode=install +tools.system.package_manager:sudo=True + +tools.build:exelinkflags=["-fsanitize=address,undefined,leak"] +tools.build:sharedlinkflags=["-fsanitize=address,undefined,leak"] + +tools.build:cflags=["-fsanitize=address,undefined,leak", "-fno-sanitize-recover=all"] +tools.build:cxxflags=["-fno-exceptions", "-fno-rtti", "-fsanitize=address,undefined,leak", "-fno-sanitize-recover=all"] + +tools.cmake.cmaketoolchain:generator=Ninja + +tools.build:compiler_executables={"c": "clang", "cpp": "clang++"} + +[tool_requires] +!cmake/*: cmake/4.3.2 +!mold/*: mold/2.41.0@bigfootdev/main +!ninja/*: ninja/1.13.2 + +[options] +bigfoot/*:asan=True +bigfoot/*:build_tests=True \ No newline at end of file diff --git a/ConanProfiles/clang_coverage b/ConanProfiles/clang_coverage new file mode 100644 index 0000000..0ee4944 --- /dev/null +++ b/ConanProfiles/clang_coverage @@ -0,0 +1,31 @@ +[settings] +os=Linux +arch=x86_64 +compiler=clang +compiler.version=20 +compiler.libcxx=libstdc++11 +compiler.cppstd=20 +compiler.cstd=17 +compiler.runtime=static +build_type=Debug + +[conf] +tools.cmake.cmaketoolchain:user_toolchain+={{profile_dir}}/Toolchains/mold.cmake + +tools.system.package_manager:mode=install +tools.system.package_manager:sudo=True + +tools.build:cxxflags=["-fno-exceptions", "-fno-rtti"] + +tools.cmake.cmaketoolchain:generator=Ninja + +tools.build:compiler_executables={"c": "clang", "cpp": "clang++"} + +[tool_requires] +!cmake/*: cmake/4.3.2 +!mold/*: mold/2.41.0@bigfootdev/main +!ninja/*: ninja/1.13.2 + +[options] +bigfoot/*:build_tests=True +bigfoot/*:coverage=True \ No newline at end of file diff --git a/ConanProfiles/msvc b/ConanProfiles/msvc new file mode 100644 index 0000000..1a1111c --- /dev/null +++ b/ConanProfiles/msvc @@ -0,0 +1,26 @@ +[settings] +os=Windows +arch=x86_64 +compiler=msvc +compiler.version=195 +compiler.cppstd=20 +compiler.cstd=17 +compiler.runtime=static +build_type=Release + +[conf] +tools.cmake.cmaketoolchain:user_toolchain+={{profile_dir}}/Toolchains/ipo.cmake +tools.meson.mesontoolchain:extra_machine_files+={{profile_dir}}/Toolchains/ipo.ini + +tools.build:cflags=["/Zc:preprocessor", "/Zc:__STDC__", "/D_CRT_DECLARE_NONSTDC_NAMES=1"] +tools.build:cxxflags=["/Zc:preprocessor", "/permissive-", "/Zc:__cplusplus", "/Zc:enumTypes", "/Zc:templateScope", "/EHs-c-", "/GR-"] + +tools.build:defines=["_HAS_EXCEPTIONS=0"] + +tools.env.virtualenv:powershell=powershell.exe + +[tool_requires] +!cmake/*: cmake/4.3.2 + +[options] +bigfoot/*:build_tests=True \ No newline at end of file diff --git a/ConanProfiles/msvc_asan b/ConanProfiles/msvc_asan new file mode 100644 index 0000000..dc8b37c --- /dev/null +++ b/ConanProfiles/msvc_asan @@ -0,0 +1,24 @@ +[settings] +os=Windows +arch=x86_64 +compiler=msvc +compiler.version=195 +compiler.cppstd=20 +compiler.cstd=17 +compiler.runtime=static +build_type=Debug + +[conf] +tools.build:cflags=["/Zc:preprocessor", "/Zc:__STDC__", "/D_CRT_DECLARE_NONSTDC_NAMES=1", "/fsanitize=address"] +tools.build:cxxflags=["/Zc:preprocessor", "/permissive-", "/Zc:__cplusplus", "/Zc:enumTypes", "/Zc:templateScope", "/EHs-c-", "/GR-", "/fsanitize=address"] + +tools.build:defines=["_HAS_EXCEPTIONS=0"] + +tools.env.virtualenv:powershell=powershell.exe + +[tool_requires] +!cmake/*: cmake/4.3.2 + +[options] +bigfoot/*:asan=True +bigfoot/*:build_tests=True diff --git a/README.md b/README.md index 5a66607..76bac37 100644 --- a/README.md +++ b/README.md @@ -48,14 +48,12 @@ You can customize these scripts to opt-out of some Bigfoot features 'Just' modify these lines to disable them (I promise to one day modify the script to do it from the command line) ``` --o bigfoot/*:build_tests=True -o bigfoot/*:tracy=True -o bigfoot/*:build_tools=True -o bigfoot/*:vulkan=True -o bigfoot/*:build_benchmarks=True +-o bigfoot/*:build_tests=True -o bigfoot/*:tracy=True -o bigfoot/*:build_tools=True -o bigfoot/*:vulkan=True ``` 1. build_tests: Enable/Disable the tests 2. tracy: Enable/Disable profiling using [Tracy](https://github.com/wolfpld/tracy) -3. build_tools: Enable/Disable the tools (I'd absolutely recommand not disabling this) -4. vulkan: Enable/Disable Vulkan renderer (No point disabling it, since for now only Vulkan is available in Bigfoot) -5. build_benchmarks: Enable/Disable the benchmarks +3. vulkan: Enable/Disable Vulkan renderer (No point disabling it, since for now only Vulkan is available in Bigfoot) ### Generating Bigfoot diff --git a/Vendor/NatVis/EASTL/EASTL.natvis b/Vendor/NatVis/EASTL/EASTL.natvis index e1ec96d..472e834 100644 --- a/Vendor/NatVis/EASTL/EASTL.natvis +++ b/Vendor/NatVis/EASTL/EASTL.natvis @@ -103,20 +103,44 @@ - - [{mnSize}] {{}} - [{mnSize}] {{ {*mpData} }} - [{mnSize}] {{ {*mpData}, {*(mpData+1)} }} - [{mnSize}] {{ {*mpData}, {*(mpData+1)}, {*(mpData+2)} }} - [{mnSize}] {{ {*mpData}, {*(mpData+1)}, {*(mpData+2)}, {*(mpData+3)} }} - [{mnSize}] {{ {*mpData}, {*(mpData+1)}, {*(mpData+2)}, {*(mpData+3)}, {*(mpData+4)} }} - [{mnSize}] {{ {*mpData}, {*(mpData+1)}, {*(mpData+2)}, {*(mpData+3)}, {*(mpData+4)}, {*(mpData+5)} }} - [{mnSize}] {{ {*mpData}, {*(mpData+1)}, {*(mpData+2)}, {*(mpData+3)}, {*(mpData+4)}, {*(mpData+5)}, ... }} + + [{mStorage.mnSize}] {{}} + [{mStorage.mnSize}] {{ {*mStorage.mpData} }} + [{mStorage.mnSize}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)} }} + [{mStorage.mnSize}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)}, {*(mStorage.mpData+2)} }} + [{mStorage.mnSize}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)}, {*(mStorage.mpData+2)}, {*(mStorage.mpData+3)} }} + [{mStorage.mnSize}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)}, {*(mStorage.mpData+2)}, {*(mStorage.mpData+3)}, {*(mStorage.mpData+4)} }} + [{mStorage.mnSize}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)}, {*(mStorage.mpData+2)}, {*(mStorage.mpData+3)}, {*(mStorage.mpData+4)}, {*(mStorage.mpData+5)} }} + [{mStorage.mnSize}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)}, {*(mStorage.mpData+2)}, {*(mStorage.mpData+3)}, {*(mStorage.mpData+4)}, {*(mStorage.mpData+5)}, ... }} - mnSize + + DynamicSize + + mStorage.mnSize - mnSize - mpData + mStorage.mnSize + mStorage.mpData + + + + + + [{$T2}] {{}} + [{$T2}] {{ {*mStorage.mpData} }} + [{$T2}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)} }} + [{$T2}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)}, {*(mStorage.mpData+2)} }} + [{$T2}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)}, {*(mStorage.mpData+2)}, {*(mStorage.mpData+3)} }} + [{$T2}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)}, {*(mStorage.mpData+2)}, {*(mStorage.mpData+3)}, {*(mStorage.mpData+4)} }} + [{$T2}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)}, {*(mStorage.mpData+2)}, {*(mStorage.mpData+3)}, {*(mStorage.mpData+4)}, {*(mStorage.mpData+5)} }} + [{$T2}] {{ {*mStorage.mpData}, {*(mStorage.mpData+1)}, {*(mStorage.mpData+2)}, {*(mStorage.mpData+3)}, {*(mStorage.mpData+4)}, {*(mStorage.mpData+5)}, ... }} + + + ConstantSize + + $T2 + + $T2 + mStorage.mpData @@ -319,6 +343,22 @@ + + [0] {{}} + [1] {{ {mAnchor.mpNext} }} + [?] {{ {mAnchor.mpNext}, ... }} + + + Content of intrusive lists will repeat indefinitely. Keep that in mind! + + + mAnchor.mpNext + mpNext + *(($T1*)this) + + + + {*($T1*)mpNode} @@ -537,6 +577,25 @@ + + {mError} (Error) + {mValue} + + mError + mValue + mHasValue + + + + + void + {mError} (Error) + + mError + mHasValue + + + {$T1} to {$T2}} @@ -606,70 +665,70 @@ [valueless_by_exception] - {{ index=0, value={($T1*)mStorage.mBuffer.mCharData}} - {{ index=1, value={($T2*)mStorage.mBuffer.mCharData}} - {{ index=2, value={($T3*)mStorage.mBuffer.mCharData}} - {{ index=3, value={($T4*)mStorage.mBuffer.mCharData}} - {{ index=4, value={($T5*)mStorage.mBuffer.mCharData}} - {{ index=5, value={($T6*)mStorage.mBuffer.mCharData}} - {{ index=6, value={($T7*)mStorage.mBuffer.mCharData}} - {{ index=7, value={($T8*)mStorage.mBuffer.mCharData}} - {{ index=8, value={($T9*)mStorage.mBuffer.mCharData}} - {{ index=9, value={($T10*)mStorage.mBuffer.mCharData}} - {{ index=10, value={($T11*)mStorage.mBuffer.mCharData}} - {{ index=11, value={($T12*)mStorage.mBuffer.mCharData}} - {{ index=12, value={($T13*)mStorage.mBuffer.mCharData}} - {{ index=13, value={($T14*)mStorage.mBuffer.mCharData}} - {{ index=14, value={($T15*)mStorage.mBuffer.mCharData}} - {{ index=15, value={($T16*)mStorage.mBuffer.mCharData}} - {{ index=16, value={($T17*)mStorage.mBuffer.mCharData}} - {{ index=17, value={($T18*)mStorage.mBuffer.mCharData}} - {{ index=18, value={($T19*)mStorage.mBuffer.mCharData}} - {{ index=19, value={($T20*)mStorage.mBuffer.mCharData}} - {{ index=20, value={($T21*)mStorage.mBuffer.mCharData}} - {{ index=21, value={($T22*)mStorage.mBuffer.mCharData}} - {{ index=22, value={($T23*)mStorage.mBuffer.mCharData}} - {{ index=23, value={($T24*)mStorage.mBuffer.mCharData}} - {{ index=24, value={($T25*)mStorage.mBuffer.mCharData}} - {{ index=25, value={($T26*)mStorage.mBuffer.mCharData}} - {{ index=26, value={($T27*)mStorage.mBuffer.mCharData}} - {{ index=27, value={($T28*)mStorage.mBuffer.mCharData}} - {{ index=28, value={($T29*)mStorage.mBuffer.mCharData}} - {{ index=29, value={($T30*)mStorage.mBuffer.mCharData}} - {{ index=30, value={($T31*)mStorage.mBuffer.mCharData}} + {{ index=0, value={($T1*)mBuffer.mCharData}} + {{ index=1, value={($T2*)mBuffer.mCharData}} + {{ index=2, value={($T3*)mBuffer.mCharData}} + {{ index=3, value={($T4*)mBuffer.mCharData}} + {{ index=4, value={($T5*)mBuffer.mCharData}} + {{ index=5, value={($T6*)mBuffer.mCharData}} + {{ index=6, value={($T7*)mBuffer.mCharData}} + {{ index=7, value={($T8*)mBuffer.mCharData}} + {{ index=8, value={($T9*)mBuffer.mCharData}} + {{ index=9, value={($T10*)mBuffer.mCharData}} + {{ index=10, value={($T11*)mBuffer.mCharData}} + {{ index=11, value={($T12*)mBuffer.mCharData}} + {{ index=12, value={($T13*)mBuffer.mCharData}} + {{ index=13, value={($T14*)mBuffer.mCharData}} + {{ index=14, value={($T15*)mBuffer.mCharData}} + {{ index=15, value={($T16*)mBuffer.mCharData}} + {{ index=16, value={($T17*)mBuffer.mCharData}} + {{ index=17, value={($T18*)mBuffer.mCharData}} + {{ index=18, value={($T19*)mBuffer.mCharData}} + {{ index=19, value={($T20*)mBuffer.mCharData}} + {{ index=20, value={($T21*)mBuffer.mCharData}} + {{ index=21, value={($T22*)mBuffer.mCharData}} + {{ index=22, value={($T23*)mBuffer.mCharData}} + {{ index=23, value={($T24*)mBuffer.mCharData}} + {{ index=24, value={($T25*)mBuffer.mCharData}} + {{ index=25, value={($T26*)mBuffer.mCharData}} + {{ index=26, value={($T27*)mBuffer.mCharData}} + {{ index=27, value={($T28*)mBuffer.mCharData}} + {{ index=28, value={($T29*)mBuffer.mCharData}} + {{ index=29, value={($T30*)mBuffer.mCharData}} + {{ index=30, value={($T31*)mBuffer.mCharData}} index() - ($T1*)mStorage.mBuffer.mCharData - ($T2*)mStorage.mBuffer.mCharData - ($T3*)mStorage.mBuffer.mCharData - ($T4*)mStorage.mBuffer.mCharData - ($T5*)mStorage.mBuffer.mCharData - ($T6*)mStorage.mBuffer.mCharData - ($T7*)mStorage.mBuffer.mCharData - ($T8*)mStorage.mBuffer.mCharData - ($T9*)mStorage.mBuffer.mCharData - ($T10*)mStorage.mBuffer.mCharData - ($T11*)mStorage.mBuffer.mCharData - ($T12*)mStorage.mBuffer.mCharData - ($T13*)mStorage.mBuffer.mCharData - ($T14*)mStorage.mBuffer.mCharData - ($T15*)mStorage.mBuffer.mCharData - ($T16*)mStorage.mBuffer.mCharData - ($T17*)mStorage.mBuffer.mCharData - ($T18*)mStorage.mBuffer.mCharData - ($T19*)mStorage.mBuffer.mCharData - ($T20*)mStorage.mBuffer.mCharData - ($T21*)mStorage.mBuffer.mCharData - ($T22*)mStorage.mBuffer.mCharData - ($T23*)mStorage.mBuffer.mCharData - ($T24*)mStorage.mBuffer.mCharData - ($T25*)mStorage.mBuffer.mCharData - ($T26*)mStorage.mBuffer.mCharData - ($T27*)mStorage.mBuffer.mCharData - ($T28*)mStorage.mBuffer.mCharData - ($T29*)mStorage.mBuffer.mCharData - ($T30*)mStorage.mBuffer.mCharData - ($T31*)mStorage.mBuffer.mCharData + ($T1*)mBuffer.mCharData + ($T2*)mBuffer.mCharData + ($T3*)mBuffer.mCharData + ($T4*)mBuffer.mCharData + ($T5*)mBuffer.mCharData + ($T6*)mBuffer.mCharData + ($T7*)mBuffer.mCharData + ($T8*)mBuffer.mCharData + ($T9*)mBuffer.mCharData + ($T10*)mBuffer.mCharData + ($T11*)mBuffer.mCharData + ($T12*)mBuffer.mCharData + ($T13*)mBuffer.mCharData + ($T14*)mBuffer.mCharData + ($T15*)mBuffer.mCharData + ($T16*)mBuffer.mCharData + ($T17*)mBuffer.mCharData + ($T18*)mBuffer.mCharData + ($T19*)mBuffer.mCharData + ($T20*)mBuffer.mCharData + ($T21*)mBuffer.mCharData + ($T22*)mBuffer.mCharData + ($T23*)mBuffer.mCharData + ($T24*)mBuffer.mCharData + ($T25*)mBuffer.mCharData + ($T26*)mBuffer.mCharData + ($T27*)mBuffer.mCharData + ($T28*)mBuffer.mCharData + ($T29*)mBuffer.mCharData + ($T30*)mBuffer.mCharData + ($T31*)mBuffer.mCharData @@ -757,5 +816,94 @@ + + (nothing) + {static_cast<flag_type>(m_mask),en} + + m_mask,bb + (flag_type)(1 << 0),en + (flag_type)(1 << 1),en + (flag_type)(1 << 2),en + (flag_type)(1 << 3),en + (flag_type)(1 << 4),en + (flag_type)(1 << 5),en + (flag_type)(1 << 6),en + (flag_type)(1 << 7),en - + (flag_type)(1 << 8),en + (flag_type)(1 << 9),en + (flag_type)(1 << 10),en + (flag_type)(1 << 11),en + (flag_type)(1 << 12),en + (flag_type)(1 << 13),en + (flag_type)(1 << 14),en + (flag_type)(1 << 15),en + + (flag_type)(1 << 16),en + (flag_type)(1 << 17),en + (flag_type)(1 << 18),en + (flag_type)(1 << 19),en + (flag_type)(1 << 20),en + (flag_type)(1 << 21),en + (flag_type)(1 << 22),en + (flag_type)(1 << 23),en + + (flag_type)(1 << 24),en + (flag_type)(1 << 25),en + (flag_type)(1 << 26),en + (flag_type)(1 << 27),en + (flag_type)(1 << 28),en + (flag_type)(1 << 29),en + (flag_type)(1 << 30),en + (flag_type)(1 << 31),en + + + + + + {static_cast<flag_type>(__log2(m_mask)),en} + + (multiple values) + + (nothing) + + + m_mask,bb + (flag_type)(0),en + (flag_type)(1),en + (flag_type)(2),en + (flag_type)(3),en + (flag_type)(4),en + (flag_type)(5),en + (flag_type)(6),en + (flag_type)(7),en + + (flag_type)(8),en + (flag_type)(9),en + (flag_type)(10),en + (flag_type)(11),en + (flag_type)(12),en + (flag_type)(13),en + (flag_type)(14),en + (flag_type)(15),en + + (flag_type)(16),en + (flag_type)(17),en + (flag_type)(18),en + (flag_type)(19),en + (flag_type)(20),en + (flag_type)(21),en + (flag_type)(22),en + (flag_type)(23),en + + (flag_type)(24),en + (flag_type)(25),en + (flag_type)(26),en + (flag_type)(27),en + (flag_type)(28),en + (flag_type)(29),en + (flag_type)(30),en + (flag_type)(31),en + + + \ No newline at end of file diff --git a/Vendor/NatVis/GLM/GLM.natvis b/Vendor/NatVis/GLM/GLM.natvis index 018be8d..349d3c1 100644 --- a/Vendor/NatVis/GLM/GLM.natvis +++ b/Vendor/NatVis/GLM/GLM.natvis @@ -403,7 +403,7 @@ - + [{value[0]} {value[1]} {value[2]}] diff --git a/Vendor/Tools/Tracy0.13.1/tracy-capture.exe b/Vendor/Tools/Tracy0.13.1/tracy-capture.exe new file mode 100644 index 0000000..9dd844d Binary files /dev/null and b/Vendor/Tools/Tracy0.13.1/tracy-capture.exe differ diff --git a/Vendor/Tools/Tracy0.13.1/tracy-csvexport.exe b/Vendor/Tools/Tracy0.13.1/tracy-csvexport.exe new file mode 100644 index 0000000..0811b9c Binary files /dev/null and b/Vendor/Tools/Tracy0.13.1/tracy-csvexport.exe differ diff --git a/Vendor/Tools/Tracy0.13.1/tracy-import-chrome.exe b/Vendor/Tools/Tracy0.13.1/tracy-import-chrome.exe new file mode 100644 index 0000000..7de4d00 Binary files /dev/null and b/Vendor/Tools/Tracy0.13.1/tracy-import-chrome.exe differ diff --git a/Vendor/Tools/Tracy0.13.1/tracy-import-fuchsia.exe b/Vendor/Tools/Tracy0.13.1/tracy-import-fuchsia.exe new file mode 100644 index 0000000..9f64f42 Binary files /dev/null and b/Vendor/Tools/Tracy0.13.1/tracy-import-fuchsia.exe differ diff --git a/Vendor/Tools/Tracy0.13.1/tracy-profiler.exe b/Vendor/Tools/Tracy0.13.1/tracy-profiler.exe new file mode 100644 index 0000000..6d0d858 Binary files /dev/null and b/Vendor/Tools/Tracy0.13.1/tracy-profiler.exe differ diff --git a/Vendor/Tools/Tracy0.13.1/tracy-update.exe b/Vendor/Tools/Tracy0.13.1/tracy-update.exe new file mode 100644 index 0000000..8db7dec Binary files /dev/null and b/Vendor/Tools/Tracy0.13.1/tracy-update.exe differ diff --git a/conanfile.py b/conanfile.py index ffad6ab..f8bfa00 100644 --- a/conanfile.py +++ b/conanfile.py @@ -18,20 +18,22 @@ class Bigfoot(ConanFile): options = { "shared": [True, False], "fPIC": [True, False], + "asan": [True, False], + "coverage": [True, False], "build_tests": [True, False], - "tracy": [True, False], - "build_tools": [True, False], - "vulkan": [True, False], "build_benchmarks": [True, False], + "tracy": [True, False], + "vulkan": [True, False] } default_options = { "shared": False, "fPIC": True, + "asan": False, + "coverage": False, "build_tests": False, - "tracy": False, - "build_tools": True, - "vulkan": True, "build_benchmarks": False, + "tracy": False, + "vulkan": True, } generators = "CMakeDeps" @@ -43,10 +45,8 @@ class Bigfoot(ConanFile): if self.settings.os == "Windows": del self.options.fPIC - self.options['mimalloc'].override = True - self.options['mimalloc'].shared = True - if(self.settings.os == "Windows"): - self.options["mimalloc"].win_redirect = True + if(self.options.asan): + self.options["mimalloc"].asan = True self.options['stduuid'].with_cxx20_span = True self.options['flatbuffers'].header_only = True @@ -56,65 +56,50 @@ class Bigfoot(ConanFile): if(self.options.vulkan): self.options["spirv-cross"].exceptions = False - - if(self.options.build_benchmarks): - self.options["benchmark"].enable_exceptions = False - self.options["benchmark"].enable_lto = True + + def build_requirements(self): + self.tool_requires("bin2cpp/1.0.0@bigfootdev/main") def requirements(self): self.requires("eastl/3.27.01@bigfootdev/main", transitive_headers=True) self.requires("unordered_dense/4.8.1@bigfootdev/main", transitive_headers=True) - self.requires("mimalloc/3.1.5@bigfootdev/main", transitive_headers=True) + self.requires("mimalloc/3.3.2@bigfootdev/main", transitive_headers=True) self.requires("stduuid/1.2.3@bigfootdev/main", transitive_headers=True) - self.requires("sqlite3/3.51.0@bigfootdev/main", transitive_headers=True) - self.requires("cli11/2.6.0") + self.requires("sqlite3/3.53.3@bigfootdev/main", transitive_headers=True) self.requires("rapidhash/3.0@bigfootdev/main", transitive_headers=True) self.requires("effolkronium-random/1.5.0", transitive_headers=True) - self.requires("flatbuffers/25.12.19@bigfootdev/main", transitive_headers=True) + self.requires("flatbuffers/25.12.19-2026-02-06-03fffb2-bigfoot@bigfootdev/main", transitive_headers=True) if(self.settings.build_type == "RelWithDebInfo" or self.settings.build_type == "Debug"): - self.requires("quill/11.0.2", transitive_headers=True) - self.requires("cpptrace/1.0.4", transitive_headers=True) + self.requires("quill/12.0.0", transitive_headers=True) if(self.options.tracy): - self.requires("tracy/0.12.2", transitive_headers=True) + self.requires("tracy/0.13.1", transitive_headers=True) - self.requires("glm/1.0.1", transitive_headers=True) - self.requires("lodepng/cci.20250727@bigfootdev/main", transitive_headers=True) - self.requires("imgui/1.92.5-docking", transitive_headers=True) + self.requires("glm/1.0.3@bigfootdev/main", transitive_headers=True) + self.requires("lodepng/cci.20260210@bigfootdev/main", transitive_headers=True) + self.requires("imgui/1.92.8-docking@bigfootdev/main", transitive_headers=True) if(self.options.vulkan): - self.requires("vulkan-headers/1.4.313.0") - if(self.settings.build_type == "RelWithDebInfo" or self.settings.build_type == "Debug"): - self.requires("vulkan-validationlayers/1.4.313.0@bigfootdev/main") + self.requires("vulkan-headers/1.4.341.0@bigfootdev/main", override=True) self.requires("vulkan-memory-allocator/3.3.0@bigfootdev/main") - if(self.options.build_tests or self.options.build_benchmarks): - self.requires("glfw/3.4") - if(self.options.build_tests): self.test_requires("gtest/1.17.0") self.test_requires("pixelmatch-cpp17/1.0.3@bigfootdev/main") - if(self.options.build_tools): - self.requires("spirv-cross/1.4.313.0") - self.requires("shaderc/2025.3@bigfootdev/main") - self.requires("stb/cci.20240531", override=True) - self.requires("assimp/6.0.2") - self.requires("meshoptimizer/1.0@bigfootdev/main") - self.requires("libsquish/1.15") - if(self.options.build_benchmarks): - self.requires("benchmark/1.9.4") + self.requires("benchmark/1.9.5") def generate(self): tc = CMakeToolchain(self) + tc.variables["ASAN"] = self.options.asan + tc.variables["COVERAGE"] = self.options.coverage tc.variables["BUILD_TESTS"] = self.options.build_tests - tc.variables["TRACY"] = self.options.tracy - tc.variables["BUILD_TOOLS"] = self.options.build_tools - tc.variables["VULKAN"] = self.options.vulkan tc.variables["BUILD_BENCHMARKS"] = self.options.build_benchmarks + tc.variables["TRACY"] = self.options.tracy + tc.variables["VULKAN"] = self.options.vulkan tc.generate() diff --git a/generate_bigfoot.bat b/generate_bigfoot.bat index 0f4298f..5ec1ffb 100644 --- a/generate_bigfoot.bat +++ b/generate_bigfoot.bat @@ -1 +1,60 @@ -cmake -S . -B build --toolchain build/generators/conan_toolchain.cmake --graphviz=graphviz/graph.dot \ No newline at end of file +@echo off +setlocal + +REM ─── Validate argument ─────────────────────────────────────────────────────── +if "%~1"=="force" set "build_option=--build=*" & goto :start +if "%~1"=="missing" set "build_option=--build=missing" & goto :start + +echo Usage: %~n0 [force^|missing] +echo force - Rebuild all packages from source +echo missing - Only build packages not already cached +exit /b 1 + +:start +REM ─── Register remote (skip if already registered) ──────────────────────────── +conan remote list | findstr /i "bigfootpackages" >nul 2>&1 +if errorlevel 1 ( + echo Adding Conan remote: bigfootpackages + conan remote add bigfootpackages https://conan.romainboullard.com/artifactory/api/conan/BigfootPackages + if errorlevel 1 ( + echo ERROR: Failed to add Conan remote. + exit /b 1 + ) +) else ( + echo Conan remote 'bigfootpackages' already registered, skipping. +) + +REM ─── Shared flags ──────────────────────────────────────────────────────────── +set "conan_common=--remote=bigfootpackages -pr:h=./ConanProfiles/msvc -pr:b=./ConanProfiles/Tools/msvc -of build-windows -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=True -o bigfoot/*:vulkan=True" + +REM ─── Install dependencies for each build type ──────────────────────────────── +for %%C in (Release RelWithDebInfo Debug) do ( + echo. + echo [%%C] Installing dependencies... + conan install . %conan_common% %build_option% -s:h build_type=%%C + if errorlevel 1 ( + echo ERROR: conan install failed for build type %%C + exit /b 1 + ) + echo [%%C] Done. +) + +echo. +echo All build types installed successfully. + +REM ─── Activate build environment and run CMake ──────────────────────────────── +echo. +echo Activating build environment and configuring CMake... +mkdir graphviz-windows 2>nul + +powershell -ExecutionPolicy Bypass -Command "& 'build-windows/build/generators/conanbuild.ps1'; cmake -S . -B build-windows --toolchain build-windows/build/generators/conan_toolchain.cmake --graphviz=graphviz-windows/graph.dot; if ($LASTEXITCODE -ne 0) { Write-Host 'ERROR: CMake configuration failed'; exit 1 }" + +if errorlevel 1 ( + echo ERROR: Build environment or CMake step failed. + exit /b 1 +) + +echo. +echo CMake configuration successful. + +endlocal \ No newline at end of file diff --git a/generate_bigfoot.sh b/generate_bigfoot.sh index 1b72527..c0d1161 100644 --- a/generate_bigfoot.sh +++ b/generate_bigfoot.sh @@ -1,3 +1,104 @@ -cmake -S . -B build/Debug --toolchain build/build/Debug/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE="Debug" -G "Ninja" --graphviz=graphviz/Debug/graph.dot -cmake -S . -B build/Release --toolchain build/build/Release/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE="Release" -G "Ninja" --graphviz=graphviz/Release/graph.dot -cmake -S . -B build/RelWithDebInfo --toolchain build/build/RelWithDebInfo/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE="RelWithDebInfo" -G "Ninja" --graphviz=graphviz/RelWithDebInfo/graph.dot \ No newline at end of file +#!/usr/bin/env bash +set -euo pipefail + +# ─── Validate arguments ─────────────────────────────────────────────────────── +if [[ $# -lt 1 ]]; then + echo "Usage: $(basename "$0") [force|missing] [Release|RelWithDebInfo|Debug]" + echo " force - Rebuild all packages from source" + echo " missing - Only build packages not already cached" + echo " build_type (optional) - One of: Release, RelWithDebInfo, Debug" + echo " If omitted, all build types are processed" + exit 1 +fi + +case "${1:-}" in + force) build_option="--build=*" ;; + missing) build_option="--build=missing" ;; + *) + echo "Usage: $(basename "$0") [force|missing] [Release|RelWithDebInfo|Debug]" + echo " force - Rebuild all packages from source" + echo " missing - Only build packages not already cached" + exit 1 + ;; +esac + +# ─── Validate optional build_type argument ──────────────────────────────────── +all_build_types=(Release RelWithDebInfo Debug) + +if [[ -n "${2:-}" ]]; then + case "${2}" in + Release|RelWithDebInfo|Debug) + build_types=("${2}") + ;; + *) + echo "ERROR: Invalid build type '${2}'. Must be one of: Release, RelWithDebInfo, Debug" + exit 1 + ;; + esac +else + build_types=("${all_build_types[@]}") +fi + +# ─── Register remote (skip if already registered) ───────────────────────────── +if conan remote list 2>/dev/null | grep -qi "bigfootpackages"; then + echo "Conan remote 'bigfootpackages' already registered, skipping." +else + echo "Adding Conan remote: bigfootpackages" + if ! conan remote add bigfootpackages https://conan.romainboullard.com/artifactory/api/conan/BigfootPackages; then + echo "ERROR: Failed to add Conan remote." + exit 1 + fi +fi + +# ─── Shared flags ───────────────────────────────────────────────────────────── +conan_common=( + --remote=bigfootpackages + -pr:h=./ConanProfiles/clang + -pr:b=./ConanProfiles/Tools/clang + -of build-linux + -o "bigfoot/*:build_tests=True" + -o "bigfoot/*:build_benchmarks=True" + -o "bigfoot/*:tracy=True" + -o "bigfoot/*:vulkan=True" +) + +# ─── Install dependencies for each build type ───────────────────────────────── +for build_type in "${build_types[@]}"; do + echo + echo "[${build_type}] Installing dependencies..." + if ! conan install . "${conan_common[@]}" ${build_option} -s:h "build_type=${build_type}"; then + echo "ERROR: conan install failed for build type ${build_type}" + exit 1 + fi + echo "[${build_type}] Done." +done + +echo +echo "All build types installed successfully." + +# ─── Configure CMake for each build type ───────────────────────────────────── +echo +echo "Configuring CMake for each build type..." + +for build_type in "${build_types[@]}"; do + echo + echo "[${build_type}] Activating build environment..." + # shellcheck disable=SC1090 + source "build-linux/build/${build_type}/generators/conanbuild.sh" + + mkdir -p "graphviz-linux/${build_type}" + + echo "[${build_type}] Running CMake..." + if ! cmake -S . -B "build-linux/${build_type}" \ + --toolchain "build-linux/build/${build_type}/generators/conan_toolchain.cmake" \ + -DCMAKE_BUILD_TYPE="${build_type}" \ + -G "Ninja" \ + --graphviz="graphviz-linux/${build_type}/graph.dot"; then + echo "ERROR: CMake configuration failed for build type ${build_type}." + exit 1 + fi + echo "[${build_type}] Done." +done + +echo +echo "CMake configuration successful." \ No newline at end of file