Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f034fed3c | ||
|
|
33a79ed12f | ||
|
|
c4467ea2f2 | ||
|
|
8c9f78dbc7 | ||
|
|
1558a19f19 | ||
|
|
3a5dd1affe | ||
|
|
dc534acdd5 | ||
|
|
9fd1cd0d68 | ||
|
|
b7f4677c68 |
+25
-10
@@ -127,22 +127,37 @@ IncludeCategories:
|
|||||||
Priority: 2
|
Priority: 2
|
||||||
- Regex: '^<Utils/'
|
- Regex: '^<Utils/'
|
||||||
Priority: 3
|
Priority: 3
|
||||||
- Regex: '^<EngineTests/'
|
- Regex: '^<SasquatchBaker/'
|
||||||
Priority: 4
|
Priority: 4
|
||||||
- Regex: '^<SystemTests/'
|
- Regex: '^<EngineTests/'
|
||||||
Priority: 5
|
Priority: 5
|
||||||
- Regex: '^<UtilsTests/'
|
- Regex: '^<SystemTests/'
|
||||||
Priority: 6
|
Priority: 6
|
||||||
- Regex: '^<AssetsForTesting/'
|
- Regex: '^<UtilsTests/'
|
||||||
Priority: 7
|
Priority: 7
|
||||||
- Regex: '^<EngineBenchmarks/'
|
- Regex: '^<AssetsForTesting/'
|
||||||
Priority: 8
|
Priority: 8
|
||||||
- Regex: '^<AssetsForBenchmarking/'
|
- Regex: '^<SasquatchBakerTests/'
|
||||||
Priority: 9
|
Priority: 9
|
||||||
- Regex: '^<[a-zA-Z0-9_/]+\.h>'
|
- Regex: '^<EngineBenchmarks/'
|
||||||
Priority: 10
|
Priority: 10
|
||||||
- Regex: '^<[a-zA-Z0-9_/]+\.hpp>'
|
- Regex: '^<AssetsForBenchmarking/'
|
||||||
Priority: 10
|
|
||||||
- Regex: '^<[a-zA-Z0-9_/]+>'
|
|
||||||
Priority: 11
|
Priority: 11
|
||||||
|
- Regex: '^<SasquatchBakerBenchmarks/'
|
||||||
|
Priority: 12
|
||||||
|
- Regex: '^<[a-zA-Z0-9_/]+\.h>'
|
||||||
|
Priority: 13
|
||||||
|
- Regex: '^<[a-zA-Z0-9_/]+\.hpp>'
|
||||||
|
Priority: 13
|
||||||
|
- Regex: '^<[a-zA-Z0-9_/]+>'
|
||||||
|
Priority: 14
|
||||||
MainIncludeChar: AngleBracket
|
MainIncludeChar: AngleBracket
|
||||||
|
Macros:
|
||||||
|
- 'BIGFOOT_OPTIMIZED_ONLY(x)=x'
|
||||||
|
- 'BIGFOOT_OPTIMIZED_ONLY(x,y)=x,y'
|
||||||
|
- 'BIGFOOT_NOT_OPTIMIZED_ONLY(x)=x'
|
||||||
|
- 'BIGFOOT_NOT_OPTIMIZED_ONLY(x,y)=x,y'
|
||||||
|
- 'BIGFOOT_TOOLMODE_ONLY(x)=x'
|
||||||
|
- 'BIGFOOT_TOOLMODE_ONLY(x,y)=x,y'
|
||||||
|
- 'BIGFOOT_GAME_ONLY(x)=x'
|
||||||
|
- 'BIGFOOT_GAME_ONLY(x,y)=x,y'
|
||||||
|
|||||||
+5
-1
@@ -11,9 +11,13 @@ Checks: >
|
|||||||
portability-*,
|
portability-*,
|
||||||
|
|
||||||
-modernize-use-trailing-return-type,
|
-modernize-use-trailing-return-type,
|
||||||
|
-modernize-use-auto,
|
||||||
-readability-avoid-const-params-in-decls,
|
-readability-avoid-const-params-in-decls,
|
||||||
-cppcoreguidelines-macro-usage,
|
-cppcoreguidelines-macro-usage,
|
||||||
-cppcoreguidelines-avoid-do-while
|
-cppcoreguidelines-avoid-do-while,
|
||||||
|
-cppcoreguidelines-pro-bounds-avoid-unchecked-container-access,
|
||||||
|
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||||
|
-cppcoreguidelines-pro-type-reinterpret-cast
|
||||||
|
|
||||||
ExcludeHeaderFilterRegex: '_generated.*'
|
ExcludeHeaderFilterRegex: '_generated.*'
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -18,10 +18,10 @@ jobs:
|
|||||||
build_type: ["Debug", "RelWithDebInfo", "Release"]
|
build_type: ["Debug", "RelWithDebInfo", "Release"]
|
||||||
unity_build: ["ON", "OFF"]
|
unity_build: ["ON", "OFF"]
|
||||||
conan_profile: ["./ConanProfiles/host/clang", "./ConanProfiles/host/clang_asan"]
|
conan_profile: ["./ConanProfiles/host/clang", "./ConanProfiles/host/clang_asan"]
|
||||||
toolmode:
|
variant:
|
||||||
- { value: "True", name: "toolmode" }
|
- { value: "True", name: "toolmode" }
|
||||||
- { value: "False", name: "game" }
|
- { value: "False", name: "game" }
|
||||||
name: "Build & Test ${{ matrix.build_type }} with ${{ matrix.conan_profile }} (Unity Build: ${{ matrix.unity_build }}, Variant: ${{ matrix.toolmode.name }})"
|
name: "Build & Test ${{ matrix.build_type }} with ${{ matrix.conan_profile }} (Unity Build: ${{ matrix.unity_build }}, Variant: ${{ matrix.variant.name }})"
|
||||||
steps:
|
steps:
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
run: apt-get update && apt-get install -y nodejs
|
run: apt-get update && apt-get install -y nodejs
|
||||||
@@ -33,18 +33,18 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
conan install . --remote=bigfootpackages -pr:h=${{ matrix.conan_profile }} -pr:b=./ConanProfiles/build/clang --build=missing -s build_type=${{ matrix.build_type }} -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=False -o bigfoot/*:vulkan=True -o bigfoot/*:toolmode=${{ matrix.toolmode.value }} -of build-${{ matrix.toolmode.name }}
|
conan install . --remote=bigfootpackages -pr:h=${{ matrix.conan_profile }} -pr:b=./ConanProfiles/build/clang --build=missing -s build_type=${{ matrix.build_type }} -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=False -o bigfoot/*:vulkan=True -o bigfoot/*:toolmode=${{ matrix.variant.value }} -of build-${{ matrix.variant.name }}
|
||||||
. ./build-${{ matrix.toolmode.name }}/build/${{ matrix.build_type }}/generators/conanbuild.sh
|
. ./build-${{ matrix.variant.name }}/build/${{ matrix.build_type }}/generators/conanbuild.sh
|
||||||
cmake -S . -B ./build-${{ matrix.toolmode.name }}/${{ matrix.build_type }} --toolchain ./build-${{ matrix.toolmode.name }}/build/${{ matrix.build_type }}/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_UNITY_BUILD=${{ matrix.unity_build }} -G "Ninja"
|
cmake -S . -B ./build-${{ matrix.variant.name }}/${{ matrix.build_type }} --toolchain ./build-${{ matrix.variant.name }}/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.toolmode.name }}/${{ matrix.build_type }} --parallel $(nproc)
|
cmake --build build-${{ matrix.variant.name }}/${{ matrix.build_type }} --parallel $(nproc)
|
||||||
. ./build-${{ matrix.toolmode.name }}/build/${{ matrix.build_type }}/generators/deactivate_conanbuild.sh
|
. ./build-${{ matrix.variant.name }}/build/${{ matrix.build_type }}/generators/deactivate_conanbuild.sh
|
||||||
|
|
||||||
- name: Unit Tests
|
- name: Unit Tests
|
||||||
run: |
|
run: |
|
||||||
cd ./build-${{ matrix.toolmode.name }}/${{ matrix.build_type }}
|
cd ./build-${{ matrix.variant.name }}/${{ matrix.build_type }}
|
||||||
. ../../build-${{ matrix.toolmode.name }}/build/${{ matrix.build_type }}/generators/conanbuild.sh
|
. ../../build-${{ matrix.variant.name }}/build/${{ matrix.build_type }}/generators/conanbuild.sh
|
||||||
xvfb-run ctest . --output-on-failure
|
xvfb-run ctest . --output-on-failure
|
||||||
. ../../build-${{ matrix.toolmode.name }}/build/${{ matrix.build_type }}/generators/deactivate_conanbuild.sh
|
. ../../build-${{ matrix.variant.name }}/build/${{ matrix.build_type }}/generators/deactivate_conanbuild.sh
|
||||||
|
|
||||||
clang-format:
|
clang-format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- Development
|
- Development
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- Development
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-test:
|
build-and-test:
|
||||||
@@ -13,7 +17,14 @@ jobs:
|
|||||||
container:
|
container:
|
||||||
image: git.romainboullard.com/bigfootdev/linuxcppbuilder:development
|
image: git.romainboullard.com/bigfootdev/linuxcppbuilder:development
|
||||||
|
|
||||||
name: "Sonarqube"
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
variant:
|
||||||
|
- { value: "True", name: "toolmode", projectKey: "Bigfoot-Tool", projectName: "Bigfoot Tool" }
|
||||||
|
- { value: "False", name: "game", projectKey: "Bigfoot-Game", projectName: "Bigfoot Game" }
|
||||||
|
|
||||||
|
name: "Sonarqube (${{ matrix.variant.name }})"
|
||||||
steps:
|
steps:
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
run: apt-get update && apt-get install -y nodejs
|
run: apt-get update && apt-get install -y nodejs
|
||||||
@@ -23,28 +34,64 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||||
|
|
||||||
|
- name: Read version
|
||||||
|
id: version
|
||||||
|
run: echo "version=$(cat VERSION)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
conan install . --remote=bigfootpackages -pr:h=./ConanProfiles/host/clang_coverage -pr:b=./ConanProfiles/build/clang --build=missing -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
|
conan install . --remote=bigfootpackages -pr:h=./ConanProfiles/host/clang_coverage -pr:b=./ConanProfiles/build/clang --build=missing -s build_type=Debug -o bigfoot/*:build_tests=True -o bigfoot/*:build_benchmarks=True -o bigfoot/*:tracy=False -o bigfoot/*:toolmode=${{ matrix.variant.value }} -o bigfoot/*:vulkan=True -of build-${{ matrix.variant.name }}
|
||||||
. ./build/Debug/generators/conanbuild.sh
|
. ./build-${{ matrix.variant.name }}/build/Debug/generators/conanbuild.sh
|
||||||
cmake -S . -B ./build/Debug --toolchain ./build/Debug/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -G "Ninja"
|
cmake -S . -B ./build-${{ matrix.variant.name }}/Debug --toolchain ./build-${{ matrix.variant.name }}/build/Debug/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -G "Ninja"
|
||||||
cmake --build build/Debug --parallel $(nproc)
|
cmake --build build-${{ matrix.variant.name }}/Debug --parallel $(nproc)
|
||||||
. ./build/Debug/generators/deactivate_conanbuild.sh
|
. ./build-${{ matrix.variant.name }}/build/Debug/generators/deactivate_conanbuild.sh
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
cd ./build-${{ matrix.variant.name }}/Debug
|
||||||
|
. ../../build-${{ matrix.variant.name }}/build/Debug/generators/conanbuild.sh
|
||||||
|
LLVM_PROFILE_FILE="%p.profraw%c" xvfb-run ctest --output-on-failure
|
||||||
|
. ../../build-${{ matrix.variant.name }}/build/Debug/generators/deactivate_conanbuild.sh
|
||||||
|
|
||||||
- name: Clang-Tidy
|
- name: Clang-Tidy
|
||||||
run: run-clang-tidy -p ./build/Debug/ >> tidy_result.txt
|
run: run-clang-tidy -p ./build-${{ matrix.variant.name }}/Debug/ > tidy_result.txt
|
||||||
|
|
||||||
- name: Infer
|
- name: Infer
|
||||||
run: infer run --compilation-database build/Debug/compile_commands.json
|
run: infer run --compilation-database build-${{ matrix.variant.name }}/Debug/compile_commands.json
|
||||||
|
|
||||||
|
- name: Generate coverage report
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# gcovr's own LLVM-JSON reader only understands coverage-mapping format
|
||||||
|
# 2.x; this image's clang 22 llvm-cov emits format 3.x, which gcovr
|
||||||
|
# rejects outright ("Wrong major version"). Bypassing gcovr's JSON
|
||||||
|
# path entirely: llvm-cov's lcov exporter is a separate, unaffected
|
||||||
|
# code path, so merge -> export lcov -> convert lcov to Cobertura.
|
||||||
|
llvm-profdata merge -sparse $(find build-${{ matrix.variant.name }}/Debug -name "*.profraw") -o merged.profdata
|
||||||
|
BINARIES=($(find build-${{ matrix.variant.name }}/Debug -maxdepth 8 -type f -executable -iname "*Tests"))
|
||||||
|
OBJECT_ARGS=$(printf -- '-object %s ' "${BINARIES[@]:1}")
|
||||||
|
llvm-cov export -format=lcov -instr-profile=merged.profdata "${BINARIES[0]}" $OBJECT_ARGS > coverage.lcov
|
||||||
|
# lcov_cobertura isn't preinstalled on the image; inject it into
|
||||||
|
# gcovr's existing pipx venv and expose its CLI on PATH.
|
||||||
|
pipx inject gcovr lcov_cobertura --include-apps
|
||||||
|
lcov_cobertura coverage.lcov -b . -o coverage.xml
|
||||||
|
|
||||||
- name: SonarQube Scan
|
- name: SonarQube Scan
|
||||||
if: github.head_ref == 'main' || github.ref_name == 'main'
|
|
||||||
uses: SonarSource/sonarqube-scan-action@v7.0.0
|
uses: SonarSource/sonarqube-scan-action@v7.0.0
|
||||||
with:
|
with:
|
||||||
args: >
|
args: >
|
||||||
-Dsonar.cxx.jsonCompilationDatabase=./build/Debug/compile_commands.json
|
-Dsonar.projectKey=${{ matrix.variant.projectKey }}
|
||||||
-Dsonar.verbose=true
|
"-Dsonar.projectName=${{ matrix.variant.projectName }}"
|
||||||
|
-Dsonar.projectVersion=${{ steps.version.outputs.version }}
|
||||||
|
-Dsonar.cxx.jsonCompilationDatabase=./build-${{ matrix.variant.name }}/Debug/compile_commands.json
|
||||||
|
-Dsonar.cxx.xunit.reportPaths=build-${{ matrix.variant.name }}/Debug/TestResults/*.xml
|
||||||
|
-Dsonar.qualitygate.wait=true
|
||||||
|
${{ github.event_name == 'pull_request' &&
|
||||||
|
format('-Dsonar.pullrequest.key={0} -Dsonar.pullrequest.branch={1} -Dsonar.pullrequest.base={2} -Dsonar.analysis.sqbot={3}',
|
||||||
|
github.event.pull_request.number, github.head_ref, github.base_ref, github.event.pull_request.head.sha)
|
||||||
|
|| format('-Dsonar.branch.name={0}', github.ref_name) }}
|
||||||
env:
|
env:
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
SONAR_HOST_URL: ${{ secrets.SONAR_HOST }}
|
SONAR_HOST_URL: ${{ secrets.SONAR_HOST }}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
InheritParentConfig: true
|
||||||
|
Checks: >
|
||||||
|
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||||
|
-cppcoreguidelines-avoid-magic-numbers,
|
||||||
|
-readability-magic-numbers
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file BenchmarkAssetReferred.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred.hpp>
|
||||||
|
|
||||||
|
#include <Engine/Asset/AssetHelper.hpp>
|
||||||
|
|
||||||
|
BIGFOOT_ASSET(BenchmarkAssetReferred, ::Bigfoot::BenchmarkAssetReferred)
|
||||||
+3
@@ -1,8 +1,11 @@
|
|||||||
|
include "Engine/Asset/Reference.fbs";
|
||||||
|
|
||||||
namespace Flat.Bigfoot;
|
namespace Flat.Bigfoot;
|
||||||
|
|
||||||
table BenchmarkAsset
|
table BenchmarkAsset
|
||||||
{
|
{
|
||||||
payload: [ubyte];
|
payload: [ubyte];
|
||||||
|
refs: [HardReference] (native_inline, bigfoot_ref: "::Bigfoot::BenchmarkAssetReferred");
|
||||||
}
|
}
|
||||||
|
|
||||||
root_type BenchmarkAsset;
|
root_type BenchmarkAsset;
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Flat.Bigfoot;
|
||||||
|
|
||||||
|
table BenchmarkAssetReferred
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
root_type BenchmarkAssetReferred;
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file BenchmarkAssetReferred.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_ASSETSFORBENCHMARKING_ASSET_BENCHMARKASSETREFERRED_HPP
|
||||||
|
#define BIGFOOT_ASSETSFORBENCHMARKING_ASSET_BENCHMARKASSETREFERRED_HPP
|
||||||
|
#include <Engine/Asset/Asset.hpp>
|
||||||
|
|
||||||
|
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred_generated.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
struct BenchmarkAssetReferredTraits
|
||||||
|
{
|
||||||
|
using FLAT = ::Flat::Bigfoot::BenchmarkAssetReferred;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BenchmarkAssetReferred: public Asset<BenchmarkAssetReferredTraits>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
+172
@@ -0,0 +1,172 @@
|
|||||||
|
// automatically generated by the FlatBuffers compiler, do not modify
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_GENERATED_BENCHMARKASSETREFERRED_FLAT_BIGFOOT_H_
|
||||||
|
#define FLATBUFFERS_GENERATED_BENCHMARKASSETREFERRED_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 "EASTL/unique_ptr.h"
|
||||||
|
#include "EASTL/string.h"
|
||||||
|
#include "EASTL/vector.h"
|
||||||
|
|
||||||
|
namespace Flat {
|
||||||
|
namespace Bigfoot {
|
||||||
|
|
||||||
|
struct BenchmarkAssetReferred;
|
||||||
|
struct BenchmarkAssetReferredBuilder;
|
||||||
|
struct BenchmarkAssetReferredT;
|
||||||
|
|
||||||
|
inline const ::flatbuffers::TypeTable *BenchmarkAssetReferredTypeTable();
|
||||||
|
|
||||||
|
struct BenchmarkAssetReferredT : public ::flatbuffers::NativeTable {
|
||||||
|
typedef BenchmarkAssetReferred TableType;
|
||||||
|
static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() {
|
||||||
|
return "Flat.Bigfoot.BenchmarkAssetReferredT";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BenchmarkAssetReferred FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||||
|
typedef BenchmarkAssetReferredT NativeTableType;
|
||||||
|
typedef BenchmarkAssetReferredBuilder Builder;
|
||||||
|
struct Traits;
|
||||||
|
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
|
||||||
|
return BenchmarkAssetReferredTypeTable();
|
||||||
|
}
|
||||||
|
static FLATBUFFERS_CONSTEXPR_CPP11 const char *GetFullyQualifiedName() {
|
||||||
|
return "Flat.Bigfoot.BenchmarkAssetReferred";
|
||||||
|
}
|
||||||
|
template <bool B = false>
|
||||||
|
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
||||||
|
return VerifyTableStart(verifier) &&
|
||||||
|
verifier.EndTable();
|
||||||
|
}
|
||||||
|
BenchmarkAssetReferredT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
||||||
|
void UnPackTo(BenchmarkAssetReferredT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
||||||
|
static ::flatbuffers::Offset<BenchmarkAssetReferred> Pack(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetReferredT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BenchmarkAssetReferredBuilder {
|
||||||
|
typedef BenchmarkAssetReferred Table;
|
||||||
|
::flatbuffers::FlatBufferBuilder &fbb_;
|
||||||
|
::flatbuffers::uoffset_t start_;
|
||||||
|
explicit BenchmarkAssetReferredBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
|
||||||
|
: fbb_(_fbb) {
|
||||||
|
start_ = fbb_.StartTable();
|
||||||
|
}
|
||||||
|
::flatbuffers::Offset<BenchmarkAssetReferred> Finish() {
|
||||||
|
const auto end = fbb_.EndTable(start_);
|
||||||
|
auto o = ::flatbuffers::Offset<BenchmarkAssetReferred>(end);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline ::flatbuffers::Offset<BenchmarkAssetReferred> CreateBenchmarkAssetReferred(
|
||||||
|
::flatbuffers::FlatBufferBuilder &_fbb) {
|
||||||
|
BenchmarkAssetReferredBuilder builder_(_fbb);
|
||||||
|
return builder_.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BenchmarkAssetReferred::Traits {
|
||||||
|
using type = BenchmarkAssetReferred;
|
||||||
|
static auto constexpr Create = CreateBenchmarkAssetReferred;
|
||||||
|
};
|
||||||
|
|
||||||
|
::flatbuffers::Offset<BenchmarkAssetReferred> CreateBenchmarkAssetReferred(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetReferredT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
|
||||||
|
|
||||||
|
inline BenchmarkAssetReferredT *BenchmarkAssetReferred::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const {
|
||||||
|
auto _o = std::make_unique<BenchmarkAssetReferredT>();
|
||||||
|
UnPackTo(_o.get(), _resolver);
|
||||||
|
return _o.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void BenchmarkAssetReferred::UnPackTo(BenchmarkAssetReferredT *_o, const ::flatbuffers::resolver_function_t *_resolver) const {
|
||||||
|
(void)_o;
|
||||||
|
(void)_resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ::flatbuffers::Offset<BenchmarkAssetReferred> CreateBenchmarkAssetReferred(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetReferredT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
|
||||||
|
return BenchmarkAssetReferred::Pack(_fbb, _o, _rehasher);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ::flatbuffers::Offset<BenchmarkAssetReferred> BenchmarkAssetReferred::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetReferredT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) {
|
||||||
|
(void)_rehasher;
|
||||||
|
(void)_o;
|
||||||
|
struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const BenchmarkAssetReferredT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
|
||||||
|
return Flat::Bigfoot::CreateBenchmarkAssetReferred(
|
||||||
|
_fbb);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const ::flatbuffers::TypeTable *BenchmarkAssetReferredTypeTable() {
|
||||||
|
static const ::flatbuffers::TypeTable tt = {
|
||||||
|
::flatbuffers::ST_TABLE, 0, nullptr, nullptr, nullptr, nullptr, nullptr
|
||||||
|
};
|
||||||
|
return &tt;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Flat::Bigfoot::BenchmarkAssetReferred *GetBenchmarkAssetReferred(const void *buf) {
|
||||||
|
return ::flatbuffers::GetRoot<Flat::Bigfoot::BenchmarkAssetReferred>(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Flat::Bigfoot::BenchmarkAssetReferred *GetSizePrefixedBenchmarkAssetReferred(const void *buf) {
|
||||||
|
return ::flatbuffers::GetSizePrefixedRoot<Flat::Bigfoot::BenchmarkAssetReferred>(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool B = false>
|
||||||
|
inline bool VerifyBenchmarkAssetReferredBuffer(
|
||||||
|
::flatbuffers::VerifierTemplate<B> &verifier) {
|
||||||
|
return verifier.template VerifyBuffer<Flat::Bigfoot::BenchmarkAssetReferred>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool B = false>
|
||||||
|
inline bool VerifySizePrefixedBenchmarkAssetReferredBuffer(
|
||||||
|
::flatbuffers::VerifierTemplate<B> &verifier) {
|
||||||
|
return verifier.template VerifySizePrefixedBuffer<Flat::Bigfoot::BenchmarkAssetReferred>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char *BenchmarkAssetReferredExtension() {
|
||||||
|
return "bfbs";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void FinishBenchmarkAssetReferredBuffer(
|
||||||
|
::flatbuffers::FlatBufferBuilder &fbb,
|
||||||
|
::flatbuffers::Offset<Flat::Bigfoot::BenchmarkAssetReferred> root) {
|
||||||
|
fbb.Finish(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void FinishSizePrefixedBenchmarkAssetReferredBuffer(
|
||||||
|
::flatbuffers::FlatBufferBuilder &fbb,
|
||||||
|
::flatbuffers::Offset<Flat::Bigfoot::BenchmarkAssetReferred> root) {
|
||||||
|
fbb.FinishSizePrefixed(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline eastl::unique_ptr<Flat::Bigfoot::BenchmarkAssetReferredT> UnPackBenchmarkAssetReferred(
|
||||||
|
const void *buf,
|
||||||
|
const ::flatbuffers::resolver_function_t *res = nullptr) {
|
||||||
|
return eastl::unique_ptr<Flat::Bigfoot::BenchmarkAssetReferredT>(GetBenchmarkAssetReferred(buf)->UnPack(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline eastl::unique_ptr<Flat::Bigfoot::BenchmarkAssetReferredT> UnPackSizePrefixedBenchmarkAssetReferred(
|
||||||
|
const void *buf,
|
||||||
|
const ::flatbuffers::resolver_function_t *res = nullptr) {
|
||||||
|
return eastl::unique_ptr<Flat::Bigfoot::BenchmarkAssetReferredT>(GetSizePrefixedBenchmarkAssetReferred(buf)->UnPack(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Bigfoot
|
||||||
|
} // namespace Flat
|
||||||
|
|
||||||
|
#endif // FLATBUFFERS_GENERATED_BENCHMARKASSETREFERRED_FLAT_BIGFOOT_H_
|
||||||
+51
-5
@@ -20,6 +20,10 @@ static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
|||||||
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
|
static_assert(FLATBUFFERS_BIGFOOT_VERSION == 1,
|
||||||
"Non-compatible Bigfoot flatbuffers fork version included");
|
"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/unique_ptr.h"
|
||||||
#include "EASTL/string.h"
|
#include "EASTL/string.h"
|
||||||
#include "EASTL/vector.h"
|
#include "EASTL/vector.h"
|
||||||
@@ -31,6 +35,21 @@ struct BenchmarkAsset;
|
|||||||
struct BenchmarkAssetBuilder;
|
struct BenchmarkAssetBuilder;
|
||||||
struct BenchmarkAssetT;
|
struct BenchmarkAssetT;
|
||||||
|
|
||||||
|
} // namespace Bigfoot
|
||||||
|
} // namespace Flat
|
||||||
|
|
||||||
|
namespace Bigfoot {
|
||||||
|
class BenchmarkAssetReferred;
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
Flat::Bigfoot::HardReference PackHardReferenceBenchmarkAssetReferred(const ::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred>& p_asset);
|
||||||
|
::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred> UnPackHardReferenceBenchmarkAssetReferred(const Flat::Bigfoot::HardReference& p_asset);
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
namespace Flat {
|
||||||
|
namespace Bigfoot {
|
||||||
|
|
||||||
inline const ::flatbuffers::TypeTable *BenchmarkAssetTypeTable();
|
inline const ::flatbuffers::TypeTable *BenchmarkAssetTypeTable();
|
||||||
|
|
||||||
struct BenchmarkAssetT : public ::flatbuffers::NativeTable {
|
struct BenchmarkAssetT : public ::flatbuffers::NativeTable {
|
||||||
@@ -39,6 +58,7 @@ struct BenchmarkAssetT : public ::flatbuffers::NativeTable {
|
|||||||
return "Flat.Bigfoot.BenchmarkAssetT";
|
return "Flat.Bigfoot.BenchmarkAssetT";
|
||||||
}
|
}
|
||||||
eastl::vector<uint8_t> payload{};
|
eastl::vector<uint8_t> payload{};
|
||||||
|
eastl::vector<::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred>> refs{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BenchmarkAsset FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
struct BenchmarkAsset FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||||
@@ -52,16 +72,22 @@ struct BenchmarkAsset FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
|||||||
return "Flat.Bigfoot.BenchmarkAsset";
|
return "Flat.Bigfoot.BenchmarkAsset";
|
||||||
}
|
}
|
||||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||||
VT_PAYLOAD = 4
|
VT_PAYLOAD = 4,
|
||||||
|
VT_REFS = 6
|
||||||
};
|
};
|
||||||
const ::flatbuffers::Vector<uint8_t> *payload() const {
|
const ::flatbuffers::Vector<uint8_t> *payload() const {
|
||||||
return GetPointer<const ::flatbuffers::Vector<uint8_t> *>(VT_PAYLOAD);
|
return GetPointer<const ::flatbuffers::Vector<uint8_t> *>(VT_PAYLOAD);
|
||||||
}
|
}
|
||||||
|
const ::flatbuffers::Vector<const Flat::Bigfoot::HardReference *> *refs() const {
|
||||||
|
return GetPointer<const ::flatbuffers::Vector<const Flat::Bigfoot::HardReference *> *>(VT_REFS);
|
||||||
|
}
|
||||||
template <bool B = false>
|
template <bool B = false>
|
||||||
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
||||||
return VerifyTableStart(verifier) &&
|
return VerifyTableStart(verifier) &&
|
||||||
VerifyOffset(verifier, VT_PAYLOAD) &&
|
VerifyOffset(verifier, VT_PAYLOAD) &&
|
||||||
verifier.VerifyVector(payload()) &&
|
verifier.VerifyVector(payload()) &&
|
||||||
|
VerifyOffset(verifier, VT_REFS) &&
|
||||||
|
verifier.VerifyVector(refs()) &&
|
||||||
verifier.EndTable();
|
verifier.EndTable();
|
||||||
}
|
}
|
||||||
BenchmarkAssetT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
BenchmarkAssetT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
||||||
@@ -76,6 +102,9 @@ struct BenchmarkAssetBuilder {
|
|||||||
void add_payload(::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload) {
|
void add_payload(::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload) {
|
||||||
fbb_.AddOffset(BenchmarkAsset::VT_PAYLOAD, payload);
|
fbb_.AddOffset(BenchmarkAsset::VT_PAYLOAD, payload);
|
||||||
}
|
}
|
||||||
|
void add_refs(::flatbuffers::Offset<::flatbuffers::Vector<const Flat::Bigfoot::HardReference *>> refs) {
|
||||||
|
fbb_.AddOffset(BenchmarkAsset::VT_REFS, refs);
|
||||||
|
}
|
||||||
explicit BenchmarkAssetBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
|
explicit BenchmarkAssetBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
|
||||||
: fbb_(_fbb) {
|
: fbb_(_fbb) {
|
||||||
start_ = fbb_.StartTable();
|
start_ = fbb_.StartTable();
|
||||||
@@ -89,8 +118,10 @@ struct BenchmarkAssetBuilder {
|
|||||||
|
|
||||||
inline ::flatbuffers::Offset<BenchmarkAsset> CreateBenchmarkAsset(
|
inline ::flatbuffers::Offset<BenchmarkAsset> CreateBenchmarkAsset(
|
||||||
::flatbuffers::FlatBufferBuilder &_fbb,
|
::flatbuffers::FlatBufferBuilder &_fbb,
|
||||||
::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload = 0) {
|
::flatbuffers::Offset<::flatbuffers::Vector<uint8_t>> payload = 0,
|
||||||
|
::flatbuffers::Offset<::flatbuffers::Vector<const Flat::Bigfoot::HardReference *>> refs = 0) {
|
||||||
BenchmarkAssetBuilder builder_(_fbb);
|
BenchmarkAssetBuilder builder_(_fbb);
|
||||||
|
builder_.add_refs(refs);
|
||||||
builder_.add_payload(payload);
|
builder_.add_payload(payload);
|
||||||
return builder_.Finish();
|
return builder_.Finish();
|
||||||
}
|
}
|
||||||
@@ -112,6 +143,7 @@ inline void BenchmarkAsset::UnPackTo(BenchmarkAssetT *_o, const ::flatbuffers::r
|
|||||||
(void)_o;
|
(void)_o;
|
||||||
(void)_resolver;
|
(void)_resolver;
|
||||||
{ auto _e = payload(); if (_e) { _o->payload.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->payload.begin()); } }
|
{ auto _e = payload(); if (_e) { _o->payload.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->payload.begin()); } }
|
||||||
|
{ auto _e = refs(); if (_e) { _o->refs.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->refs[_i] = ::flatbuffers::UnPackHardReferenceBenchmarkAssetReferred(*_e->Get(_i)); } } else { _o->refs.resize(0); } }
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ::flatbuffers::Offset<BenchmarkAsset> CreateBenchmarkAsset(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
|
inline ::flatbuffers::Offset<BenchmarkAsset> CreateBenchmarkAsset(::flatbuffers::FlatBufferBuilder &_fbb, const BenchmarkAssetT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
|
||||||
@@ -123,17 +155,23 @@ inline ::flatbuffers::Offset<BenchmarkAsset> BenchmarkAsset::Pack(::flatbuffers:
|
|||||||
(void)_o;
|
(void)_o;
|
||||||
struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const BenchmarkAssetT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
|
struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const BenchmarkAssetT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
|
||||||
auto _payload = _fbb.CreateVector(_o->payload.data(), _o->payload.size());
|
auto _payload = _fbb.CreateVector(_o->payload.data(), _o->payload.size());
|
||||||
|
auto _refs = _fbb.CreateVectorOfNativeStructs<Flat::Bigfoot::HardReference, ::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred>>(_o->refs.data(), _o->refs.size(), ::flatbuffers::PackHardReferenceBenchmarkAssetReferred);
|
||||||
return Flat::Bigfoot::CreateBenchmarkAsset(
|
return Flat::Bigfoot::CreateBenchmarkAsset(
|
||||||
_fbb,
|
_fbb,
|
||||||
_payload);
|
_payload,
|
||||||
|
_refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const ::flatbuffers::TypeTable *BenchmarkAssetTypeTable() {
|
inline const ::flatbuffers::TypeTable *BenchmarkAssetTypeTable() {
|
||||||
static const ::flatbuffers::TypeCode type_codes[] = {
|
static const ::flatbuffers::TypeCode type_codes[] = {
|
||||||
{ ::flatbuffers::ET_UCHAR, 1, -1 }
|
{ ::flatbuffers::ET_UCHAR, 1, -1 },
|
||||||
|
{ ::flatbuffers::ET_SEQUENCE, 1, 0 }
|
||||||
|
};
|
||||||
|
static const ::flatbuffers::TypeFunction type_refs[] = {
|
||||||
|
Flat::Bigfoot::HardReferenceTypeTable
|
||||||
};
|
};
|
||||||
static const ::flatbuffers::TypeTable tt = {
|
static const ::flatbuffers::TypeTable tt = {
|
||||||
::flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, nullptr, nullptr
|
::flatbuffers::ST_TABLE, 2, type_codes, type_refs, nullptr, nullptr, nullptr
|
||||||
};
|
};
|
||||||
return &tt;
|
return &tt;
|
||||||
}
|
}
|
||||||
@@ -189,4 +227,12 @@ inline eastl::unique_ptr<Flat::Bigfoot::BenchmarkAssetT> UnPackSizePrefixedBench
|
|||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
} // namespace Flat
|
} // namespace Flat
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
#ifndef FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEBENCHMARKASSETREFERRED
|
||||||
|
#define FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEBENCHMARKASSETREFERRED
|
||||||
|
inline Flat::Bigfoot::HardReference PackHardReferenceBenchmarkAssetReferred(const ::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred>& p_asset) { return {Pack(p_asset.GetUUID())}; }
|
||||||
|
inline ::Bigfoot::HardReference<::Bigfoot::BenchmarkAssetReferred> UnPackHardReferenceBenchmarkAssetReferred(const Flat::Bigfoot::HardReference& p_asset) { return {UnPack(p_asset.uuid())}; }
|
||||||
|
#endif // FLATBUFFERS_BIGFOOT_REF_HARDREFERENCEBENCHMARKASSETREFERRED
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
#endif // FLATBUFFERS_GENERATED_BENCHMARKASSET_FLAT_BIGFOOT_H_
|
#endif // FLATBUFFERS_GENERATED_BENCHMARKASSET_FLAT_BIGFOOT_H_
|
||||||
|
|||||||
@@ -2,3 +2,6 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/AssetsForBenchmarking)
|
|||||||
|
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
||||||
|
if(${TOOLMODE})
|
||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Tools)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -20,9 +20,30 @@ namespace
|
|||||||
using Random = effolkronium::random_static;
|
using Random = effolkronium::random_static;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
class AssetContainerFixture: public benchmark::Fixture
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
[[nodiscard]]
|
||||||
|
static eastl::vector<UUID> InsertRandomAssets(AssetContainer<BenchmarkAsset>& p_container,
|
||||||
|
const std::uint32_t p_count)
|
||||||
|
{
|
||||||
|
eastl::vector<UUID> uuids;
|
||||||
|
uuids.reserve(p_count);
|
||||||
|
for (std::uint32_t i = 0; i < p_count; ++i)
|
||||||
|
{
|
||||||
|
uuids.push_back(p_container.Insert()->GetAsset()->GetHeader().uuid);
|
||||||
|
}
|
||||||
|
Random::shuffle(uuids);
|
||||||
|
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetContainer<BenchmarkAsset> m_container;
|
||||||
|
};
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
void Insert(benchmark::State& state)
|
BENCHMARK_DEFINE_F(AssetContainerFixture, Insert)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
@@ -41,29 +62,29 @@ void Insert(benchmark::State& state)
|
|||||||
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations() * count * sizeof(BenchmarkAsset)));
|
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations() * count * sizeof(BenchmarkAsset)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK(Insert)->Name("AssetContainer/Insert")->Arg(512)->Arg(8192)->Arg(131'072);
|
BENCHMARK_REGISTER_F(AssetContainerFixture, Insert)->Name("AssetContainer/Insert")->Arg(512)->Arg(8192)->Arg(131'072);
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
void Get(benchmark::State& state)
|
BENCHMARK_DEFINE_F(AssetContainerFixture, Get)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
AssetContainer<BenchmarkAsset> container;
|
const eastl::vector<UUID> uuids = InsertRandomAssets(m_container, count);
|
||||||
eastl::vector<SlotMapKey<>> keys;
|
|
||||||
keys.reserve(count);
|
eastl::vector<ContainerHandle*> handles;
|
||||||
for (std::uint32_t i = 0; i < count; ++i)
|
handles.reserve(count);
|
||||||
|
for (const UUID& uuid: uuids)
|
||||||
{
|
{
|
||||||
keys.push_back(container.Insert());
|
handles.push_back(m_container.AcquireContainerHandle(uuid));
|
||||||
}
|
}
|
||||||
Random::shuffle(keys);
|
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
std::uint64_t sum = 0;
|
std::uint64_t sum = 0;
|
||||||
for (const SlotMapKey<> key: keys)
|
for (ContainerHandle* const handle: handles)
|
||||||
{
|
{
|
||||||
if (const BenchmarkAsset* const asset = container.Get(key))
|
if (const auto* const asset = static_cast<const BenchmarkAsset*>(handle->GetAsset()))
|
||||||
{
|
{
|
||||||
sum += asset->GetHeader().type_id;
|
sum += asset->GetHeader().type_id;
|
||||||
}
|
}
|
||||||
@@ -74,30 +95,22 @@ void Get(benchmark::State& state)
|
|||||||
state.SetItemsProcessed(state.iterations() * count);
|
state.SetItemsProcessed(state.iterations() * count);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK(Get)->Name("AssetContainer/Get")->Arg(512)->Arg(8192)->Arg(131'072);
|
BENCHMARK_REGISTER_F(AssetContainerFixture, Get)->Name("AssetContainer/Get")->Arg(512)->Arg(8192)->Arg(131'072);
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
void Has(benchmark::State& state)
|
BENCHMARK_DEFINE_F(AssetContainerFixture, Has)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
AssetContainer<BenchmarkAsset> container;
|
const eastl::vector<UUID> uuids = InsertRandomAssets(m_container, count);
|
||||||
eastl::vector<UUID> uuids;
|
|
||||||
uuids.reserve(count);
|
|
||||||
for (std::uint32_t i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
const SlotMapKey<> key = container.Insert();
|
|
||||||
uuids.push_back(container.Get(key)->GetHeader().uuid);
|
|
||||||
}
|
|
||||||
Random::shuffle(uuids);
|
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
for (const UUID& uuid: uuids)
|
for (const UUID& uuid: uuids)
|
||||||
{
|
{
|
||||||
result = result && container.Has(uuid);
|
result = result && m_container.Has(uuid);
|
||||||
}
|
}
|
||||||
benchmark::DoNotOptimize(result);
|
benchmark::DoNotOptimize(result);
|
||||||
}
|
}
|
||||||
@@ -105,30 +118,22 @@ void Has(benchmark::State& state)
|
|||||||
state.SetItemsProcessed(state.iterations() * count);
|
state.SetItemsProcessed(state.iterations() * count);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK(Has)->Name("AssetContainer/Has")->Arg(512)->Arg(8192)->Arg(131'072);
|
BENCHMARK_REGISTER_F(AssetContainerFixture, Has)->Name("AssetContainer/Has")->Arg(512)->Arg(8192)->Arg(131'072);
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
void AcquireContainerHandle(benchmark::State& state)
|
BENCHMARK_DEFINE_F(AssetContainerFixture, AcquireContainerHandle)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
AssetContainer<BenchmarkAsset> container;
|
const eastl::vector<UUID> uuids = InsertRandomAssets(m_container, count);
|
||||||
eastl::vector<UUID> uuids;
|
|
||||||
uuids.reserve(count);
|
|
||||||
for (std::uint32_t i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
const SlotMapKey<> key = container.Insert();
|
|
||||||
uuids.push_back(container.Get(key)->GetHeader().uuid);
|
|
||||||
}
|
|
||||||
Random::shuffle(uuids);
|
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
std::uint64_t sum = 0;
|
std::uint64_t sum = 0;
|
||||||
for (const UUID& uuid: uuids)
|
for (const UUID& uuid: uuids)
|
||||||
{
|
{
|
||||||
sum += container.AcquireContainerHandle(uuid)->GetHardRefCount();
|
sum += m_container.AcquireContainerHandle(uuid)->GetHardRefCount();
|
||||||
}
|
}
|
||||||
benchmark::DoNotOptimize(sum);
|
benchmark::DoNotOptimize(sum);
|
||||||
}
|
}
|
||||||
@@ -136,33 +141,29 @@ void AcquireContainerHandle(benchmark::State& state)
|
|||||||
state.SetItemsProcessed(state.iterations() * count);
|
state.SetItemsProcessed(state.iterations() * count);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK(AcquireContainerHandle)->Name("AssetContainer/AcquireContainerHandle")->Arg(512)->Arg(8192)->Arg(131'072);
|
BENCHMARK_REGISTER_F(AssetContainerFixture, AcquireContainerHandle)
|
||||||
|
->Name("AssetContainer/AcquireContainerHandle")
|
||||||
|
->Arg(512)
|
||||||
|
->Arg(8192)
|
||||||
|
->Arg(131'072);
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
void Remove(benchmark::State& state)
|
BENCHMARK_DEFINE_F(AssetContainerFixture, Remove)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto count = static_cast<std::uint32_t>(state.range(0));
|
const auto count = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
AssetContainer<BenchmarkAsset> container;
|
|
||||||
eastl::vector<UUID> uuids;
|
eastl::vector<UUID> uuids;
|
||||||
uuids.reserve(count);
|
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
state.PauseTiming();
|
state.PauseTiming();
|
||||||
uuids.clear();
|
uuids = InsertRandomAssets(m_container, count);
|
||||||
for (std::uint32_t i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
const SlotMapKey<> key = container.Insert();
|
|
||||||
uuids.push_back(container.Get(key)->GetHeader().uuid);
|
|
||||||
}
|
|
||||||
Random::shuffle(uuids);
|
|
||||||
state.ResumeTiming();
|
state.ResumeTiming();
|
||||||
|
|
||||||
for (const UUID& uuid: uuids)
|
for (const UUID& uuid: uuids)
|
||||||
{
|
{
|
||||||
container.Remove(uuid);
|
m_container.Remove(uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,5 +171,5 @@ void Remove(benchmark::State& state)
|
|||||||
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations() * count * sizeof(BenchmarkAsset)));
|
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations() * count * sizeof(BenchmarkAsset)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK(Remove)->Name("AssetContainer/Remove")->Arg(512)->Arg(8192)->Arg(131'072);
|
BENCHMARK_REGISTER_F(AssetContainerFixture, Remove)->Name("AssetContainer/Remove")->Arg(512)->Arg(8192)->Arg(131'072);
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/optional.h>
|
||||||
#include <EASTL/vector.h>
|
#include <EASTL/vector.h>
|
||||||
#include <benchmark/benchmark.h>
|
#include <benchmark/benchmark.h>
|
||||||
|
|
||||||
@@ -19,96 +20,119 @@
|
|||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
template<template<class> class REFERENCE>
|
template<template<class> class REFERENCE>
|
||||||
void Construct(benchmark::State& state)
|
class ReferenceFixture: public benchmark::Fixture
|
||||||
{
|
{
|
||||||
AssetLibrary library;
|
protected:
|
||||||
AssetContainer<BenchmarkAsset> container;
|
using ReferenceType = REFERENCE<BenchmarkAsset>;
|
||||||
std::ignore = library.Insert(&container);
|
|
||||||
ScopedActiveAssetLibrary scopedLibrary {&library};
|
|
||||||
|
|
||||||
const SlotMapKey<> key = container.Insert();
|
void SetUp(benchmark::State&) override
|
||||||
const UUID uuid = container.Get(key)->GetHeader().uuid;
|
{
|
||||||
|
SetActiveAssetLibrary(&m_library);
|
||||||
|
std::ignore = m_library.Insert(&m_container);
|
||||||
|
|
||||||
|
m_uuid = CreateAsset<BenchmarkAsset>()->GetHeader().uuid;
|
||||||
|
m_reference.emplace(m_uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown(benchmark::State&) override
|
||||||
|
{
|
||||||
|
SetActiveAssetLibrary(&g_assetLibrary);
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetLibrary m_library;
|
||||||
|
AssetContainer<BenchmarkAsset> m_container;
|
||||||
|
UUID m_uuid;
|
||||||
|
eastl::optional<ReferenceType> m_reference;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, HardReferenceConstruct, HardReference)(benchmark::State& state)
|
||||||
|
{
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
REFERENCE<BenchmarkAsset> reference {uuid};
|
ReferenceType reference {m_uuid};
|
||||||
benchmark::DoNotOptimize(reference);
|
benchmark::DoNotOptimize(reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(Construct, HardReference)->Name("Reference/HardReference/Construct");
|
BENCHMARK_REGISTER_F(ReferenceFixture, HardReferenceConstruct)->Name("Reference/HardReference/Construct");
|
||||||
BENCHMARK_TEMPLATE(Construct, SoftReference)->Name("Reference/SoftReference/Construct");
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, SoftReferenceConstruct, SoftReference)(benchmark::State& state)
|
||||||
|
|
||||||
template<template<class> class REFERENCE>
|
|
||||||
void Get(benchmark::State& state)
|
|
||||||
{
|
{
|
||||||
AssetLibrary library;
|
|
||||||
AssetContainer<BenchmarkAsset> container;
|
|
||||||
std::ignore = library.Insert(&container);
|
|
||||||
ScopedActiveAssetLibrary scopedLibrary {&library};
|
|
||||||
|
|
||||||
const SlotMapKey<> key = container.Insert();
|
|
||||||
const UUID uuid = container.Get(key)->GetHeader().uuid;
|
|
||||||
|
|
||||||
REFERENCE<BenchmarkAsset> reference {uuid};
|
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
benchmark::DoNotOptimize(reference.Get());
|
ReferenceType reference {m_uuid};
|
||||||
|
benchmark::DoNotOptimize(reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(Get, HardReference)->Name("Reference/HardReference/Get");
|
BENCHMARK_REGISTER_F(ReferenceFixture, SoftReferenceConstruct)->Name("Reference/SoftReference/Construct");
|
||||||
BENCHMARK_TEMPLATE(Get, SoftReference)->Name("Reference/SoftReference/Get");
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
template<template<class> class REFERENCE>
|
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, HardReferenceGet, HardReference)(benchmark::State& state)
|
||||||
void Copy(benchmark::State& state)
|
|
||||||
{
|
{
|
||||||
AssetLibrary library;
|
|
||||||
AssetContainer<BenchmarkAsset> container;
|
|
||||||
std::ignore = library.Insert(&container);
|
|
||||||
ScopedActiveAssetLibrary scopedLibrary {&library};
|
|
||||||
|
|
||||||
const SlotMapKey<> key = container.Insert();
|
|
||||||
const UUID uuid = container.Get(key)->GetHeader().uuid;
|
|
||||||
|
|
||||||
REFERENCE<BenchmarkAsset> reference {uuid};
|
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
REFERENCE<BenchmarkAsset> copy {reference};
|
benchmark::DoNotOptimize(m_reference->Get());
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations());
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(ReferenceFixture, HardReferenceGet)->Name("Reference/HardReference/Get");
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, SoftReferenceGet, SoftReference)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
benchmark::DoNotOptimize(m_reference->Get());
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations());
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(ReferenceFixture, SoftReferenceGet)->Name("Reference/SoftReference/Get");
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, HardReferenceCopy, HardReference)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
ReferenceType copy {*m_reference};
|
||||||
benchmark::DoNotOptimize(copy);
|
benchmark::DoNotOptimize(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(Copy, HardReference)->Name("Reference/HardReference/Copy");
|
BENCHMARK_REGISTER_F(ReferenceFixture, HardReferenceCopy)->Name("Reference/HardReference/Copy");
|
||||||
BENCHMARK_TEMPLATE(Copy, SoftReference)->Name("Reference/SoftReference/Copy");
|
|
||||||
|
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, SoftReferenceCopy, SoftReference)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
ReferenceType copy {*m_reference};
|
||||||
|
benchmark::DoNotOptimize(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations());
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(ReferenceFixture, SoftReferenceCopy)->Name("Reference/SoftReference/Copy");
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
template<template<class> class REFERENCE>
|
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, HardReferenceMove, HardReference)(benchmark::State& state)
|
||||||
void Move(benchmark::State& state)
|
|
||||||
{
|
{
|
||||||
AssetLibrary library;
|
|
||||||
AssetContainer<BenchmarkAsset> container;
|
|
||||||
std::ignore = library.Insert(&container);
|
|
||||||
ScopedActiveAssetLibrary scopedLibrary {&library};
|
|
||||||
|
|
||||||
const SlotMapKey<> key = container.Insert();
|
|
||||||
const UUID uuid = container.Get(key)->GetHeader().uuid;
|
|
||||||
|
|
||||||
constexpr std::size_t BATCH_SIZE = 128;
|
constexpr std::size_t BATCH_SIZE = 128;
|
||||||
eastl::vector<REFERENCE<BenchmarkAsset>> batch;
|
eastl::vector<ReferenceType> batch;
|
||||||
batch.reserve(BATCH_SIZE);
|
batch.reserve(BATCH_SIZE);
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
@@ -117,13 +141,13 @@ void Move(benchmark::State& state)
|
|||||||
batch.clear();
|
batch.clear();
|
||||||
for (std::size_t i = 0; i < BATCH_SIZE; ++i)
|
for (std::size_t i = 0; i < BATCH_SIZE; ++i)
|
||||||
{
|
{
|
||||||
batch.emplace_back(uuid);
|
batch.emplace_back(m_uuid);
|
||||||
}
|
}
|
||||||
state.ResumeTiming();
|
state.ResumeTiming();
|
||||||
|
|
||||||
for (REFERENCE<BenchmarkAsset>& reference: batch)
|
for (ReferenceType& reference: batch)
|
||||||
{
|
{
|
||||||
REFERENCE<BenchmarkAsset> moved {std::move(reference)};
|
ReferenceType moved {std::move(reference)};
|
||||||
benchmark::DoNotOptimize(moved);
|
benchmark::DoNotOptimize(moved);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,6 +155,33 @@ void Move(benchmark::State& state)
|
|||||||
state.SetItemsProcessed(state.iterations() * BATCH_SIZE);
|
state.SetItemsProcessed(state.iterations() * BATCH_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_TEMPLATE(Move, HardReference)->Name("Reference/HardReference/Move");
|
BENCHMARK_REGISTER_F(ReferenceFixture, HardReferenceMove)->Name("Reference/HardReference/Move");
|
||||||
BENCHMARK_TEMPLATE(Move, SoftReference)->Name("Reference/SoftReference/Move");
|
|
||||||
|
BENCHMARK_TEMPLATE_DEFINE_F(ReferenceFixture, SoftReferenceMove, SoftReference)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
constexpr std::size_t BATCH_SIZE = 128;
|
||||||
|
eastl::vector<ReferenceType> batch;
|
||||||
|
batch.reserve(BATCH_SIZE);
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
state.PauseTiming();
|
||||||
|
batch.clear();
|
||||||
|
for (std::size_t i = 0; i < BATCH_SIZE; ++i)
|
||||||
|
{
|
||||||
|
batch.emplace_back(m_uuid);
|
||||||
|
}
|
||||||
|
state.ResumeTiming();
|
||||||
|
|
||||||
|
for (ReferenceType& reference: batch)
|
||||||
|
{
|
||||||
|
ReferenceType moved {std::move(reference)};
|
||||||
|
benchmark::DoNotOptimize(moved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * BATCH_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(ReferenceFixture, SoftReferenceMove)->Name("Reference/SoftReference/Move");
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -12,7 +12,10 @@
|
|||||||
#include <EngineBenchmarks/BigFileInfo_generated.hpp>
|
#include <EngineBenchmarks/BigFileInfo_generated.hpp>
|
||||||
|
|
||||||
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
||||||
|
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/optional.h>
|
||||||
|
#include <EASTL/span.h>
|
||||||
#include <EASTL/vector.h>
|
#include <EASTL/vector.h>
|
||||||
#include <benchmark/benchmark.h>
|
#include <benchmark/benchmark.h>
|
||||||
#include <effolkronium/random.hpp>
|
#include <effolkronium/random.hpp>
|
||||||
@@ -23,47 +26,30 @@
|
|||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
#ifdef BIGFOOT_TOOLMODE
|
#ifdef BIGFOOT_TOOLMODE
|
||||||
namespace
|
|
||||||
{
|
|
||||||
using Random = effolkronium::random_static;
|
using Random = effolkronium::random_static;
|
||||||
|
|
||||||
constexpr std::uint32_t ASSET_COUNT = 20'000;
|
class BigFileFixture: public benchmark::Fixture
|
||||||
constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
|
|
||||||
|
|
||||||
class Fixture: public benchmark::Fixture
|
|
||||||
{
|
{
|
||||||
public:
|
protected:
|
||||||
void SetUp(benchmark::State&) override
|
static constexpr std::uint32_t ASSET_COUNT = 20'000;
|
||||||
|
static constexpr std::uint32_t REFS_PER_ASSET = 4;
|
||||||
|
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
|
||||||
|
|
||||||
|
void SetUp([[maybe_unused]] benchmark::State& p_state) override
|
||||||
{
|
{
|
||||||
BigFile::Request {m_bigFile, "DELETE FROM Asset;"}.Execute();
|
// The DB is populated exactly once for the entire benchmark process.
|
||||||
BigFile::Request {m_bigFile, "DELETE FROM AssetMetadata;"}.Execute();
|
// SetUp is called before every calibration round (Google Benchmark doubles
|
||||||
|
// iteration counts until it reaches a stable measurement), so rebuilding
|
||||||
m_uuids.clear();
|
// the DB each time would dominate the total benchmark time.
|
||||||
m_uuids.reserve(ASSET_COUNT);
|
m_uuids = BuildData();
|
||||||
|
m_bigFile.emplace(File {BIGFILE_ENGINEBENCHMARKS_LOCATION});
|
||||||
eastl::vector<AssetMetadata> metadatas;
|
}
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
|
||||||
metadatas.reserve(ASSET_COUNT);
|
void TearDown([[maybe_unused]] benchmark::State& p_state) override
|
||||||
flatbuffers.reserve(ASSET_COUNT);
|
{
|
||||||
|
m_bigFile.reset();
|
||||||
for (std::uint32_t i = 0; i < ASSET_COUNT; ++i)
|
|
||||||
{
|
|
||||||
BenchmarkAsset asset;
|
|
||||||
asset.SetName(asset.GetHeader().uuid.ToString().c_str());
|
|
||||||
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
|
||||||
|
|
||||||
metadatas.push_back(AssetMetadata {.m_uuid = asset.GetHeader().uuid,
|
|
||||||
.m_name = asset.GetHeader().name,
|
|
||||||
.m_typeID = asset.GetHeader().type_id,
|
|
||||||
.m_typeName = asset.GetHeader().type_name});
|
|
||||||
flatbuffers.push_back(asset.Pack());
|
|
||||||
m_uuids.push_back(asset.GetHeader().uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_bigFile.SaveAssetFlatbuffers(metadatas, flatbuffers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
eastl::vector<UUID> RandomBatch(const std::size_t p_batchSize) const
|
eastl::vector<UUID> RandomBatch(const std::size_t p_batchSize) const
|
||||||
{
|
{
|
||||||
@@ -91,38 +77,75 @@ class Fixture: public benchmark::Fixture
|
|||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
BigFile m_bigFile {File {BIGFILE_ENGINEBENCHMARKS_LOCATION}};
|
eastl::optional<BigFile> m_bigFile;
|
||||||
eastl::vector<UUID> m_uuids;
|
eastl::span<const UUID> m_uuids;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const eastl::vector<UUID>& BuildData()
|
||||||
|
{
|
||||||
|
static const eastl::vector<UUID> s_uuids = []()
|
||||||
|
{
|
||||||
|
eastl::vector<UUID> uuids;
|
||||||
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
|
eastl::vector<eastl::vector<UUID>> hardReferences;
|
||||||
|
uuids.reserve(ASSET_COUNT);
|
||||||
|
flatbuffers.reserve(ASSET_COUNT);
|
||||||
|
hardReferences.reserve(ASSET_COUNT);
|
||||||
|
|
||||||
|
for (std::uint32_t i = 0; i < ASSET_COUNT; ++i)
|
||||||
|
{
|
||||||
|
BenchmarkAsset asset;
|
||||||
|
asset.SetName(asset.GetHeader().uuid.ToString());
|
||||||
|
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
|
for (std::uint32_t j = 0; j < REFS_PER_ASSET; ++j)
|
||||||
|
{
|
||||||
|
BenchmarkAssetReferred assetReferred;
|
||||||
|
assetReferred.SetName(assetReferred.GetHeader().uuid.ToString());
|
||||||
|
|
||||||
|
asset.GetAsset().refs.emplace_back(assetReferred.GetHeader().uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<std::byte> flatbuffer = asset.Pack();
|
||||||
|
hardReferences.push_back(asset.GetHardReferences(flatbuffer));
|
||||||
|
flatbuffers.push_back(std::move(flatbuffer));
|
||||||
|
uuids.push_back(asset.GetHeader().uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigFile bigFile {File {BIGFILE_ENGINEBENCHMARKS_LOCATION}};
|
||||||
|
bigFile.Clear();
|
||||||
|
bigFile.SaveAssetFlatbuffers(uuids, flatbuffers, hardReferences);
|
||||||
|
|
||||||
|
return uuids;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return s_uuids;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffer)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetFlatbuffer)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
std::int64_t bytesProcessed = 0;
|
std::int64_t bytesProcessed = 0;
|
||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
eastl::optional<eastl::vector<std::byte>> flatbuffer = m_bigFile.GetAssetFlatbuffer(
|
eastl::vector<std::byte> flatbuffer = m_bigFile->GetAssetFlatbuffer(
|
||||||
m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
||||||
benchmark::DoNotOptimize(flatbuffer);
|
benchmark::DoNotOptimize(flatbuffer);
|
||||||
|
|
||||||
if (flatbuffer.has_value())
|
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
||||||
{
|
|
||||||
bytesProcessed += static_cast<std::int64_t>(flatbuffer->size());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(Fixture, GetAssetFlatbuffer)->Name("BigFile/GetAssetFlatbuffer");
|
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetFlatbuffer)->Name("BigFile/GetAssetFlatbuffer")->UseRealTime();
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffers)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetFlatbuffers)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
||||||
|
|
||||||
@@ -134,7 +157,7 @@ BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffers)(benchmark::State& state)
|
|||||||
|
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile.GetAssetFlatbuffers(batchPool[batchIndex]);
|
eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile->GetAssetFlatbuffers(batchPool[batchIndex]);
|
||||||
benchmark::DoNotOptimize(flatbuffers);
|
benchmark::DoNotOptimize(flatbuffers);
|
||||||
|
|
||||||
for (const eastl::vector<std::byte>& flatbuffer: flatbuffers)
|
for (const eastl::vector<std::byte>& flatbuffer: flatbuffers)
|
||||||
@@ -149,31 +172,34 @@ BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffers)(benchmark::State& state)
|
|||||||
state.SetBytesProcessed(bytesProcessed);
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(Fixture, GetAssetFlatbuffers)
|
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetFlatbuffers)
|
||||||
->Name("BigFile/GetAssetFlatbuffers")
|
->Name("BigFile/GetAssetFlatbuffers")
|
||||||
->Arg(1)
|
->Arg(1)
|
||||||
->Arg(8)
|
->Arg(8)
|
||||||
->Arg(64)
|
->Arg(64)
|
||||||
->Arg(512)
|
->Arg(512)
|
||||||
->Arg(4096);
|
->Arg(4096)
|
||||||
|
->UseRealTime();
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(Fixture, GetAssetMetadata)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetHardReferences)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
benchmark::DoNotOptimize(m_bigFile.GetAssetMetadata(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]));
|
benchmark::DoNotOptimize(
|
||||||
|
m_bigFile->GetAssetHardReferences(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
|
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations()) * REFS_PER_ASSET * UUID::UUID_BYTE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(Fixture, GetAssetMetadata)->Name("BigFile/GetAssetMetadata");
|
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetHardReferences)->Name("BigFile/GetAssetHardReferences")->UseRealTime();
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(Fixture, GetAssetMetadatas)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetsHardReferences)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
||||||
|
|
||||||
@@ -183,24 +209,27 @@ BENCHMARK_DEFINE_F(Fixture, GetAssetMetadatas)(benchmark::State& state)
|
|||||||
std::size_t batchIndex = 0;
|
std::size_t batchIndex = 0;
|
||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
benchmark::DoNotOptimize(m_bigFile.GetAssetMetadatas(batchPool[batchIndex]));
|
benchmark::DoNotOptimize(m_bigFile->GetAssetsHardReferences(batchPool[batchIndex]));
|
||||||
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
|
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * batchSize);
|
state.SetItemsProcessed(state.iterations() * batchSize);
|
||||||
|
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations()) * batchSize * REFS_PER_ASSET *
|
||||||
|
UUID::UUID_BYTE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(Fixture, GetAssetMetadatas)
|
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetsHardReferences)
|
||||||
->Name("BigFile/GetAssetMetadatas")
|
->Name("BigFile/GetAssetsHardReferences")
|
||||||
->Arg(1)
|
->Arg(1)
|
||||||
->Arg(8)
|
->Arg(8)
|
||||||
->Arg(64)
|
->Arg(64)
|
||||||
->Arg(512)
|
->Arg(512)
|
||||||
->Arg(4096);
|
->Arg(4096)
|
||||||
|
->UseRealTime();
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(Fixture, SaveAssetFlatbuffer)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(BigFileFixture, SaveAssetFlatbuffer)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
std::int64_t bytesProcessed = 0;
|
std::int64_t bytesProcessed = 0;
|
||||||
|
|
||||||
@@ -208,29 +237,30 @@ BENCHMARK_DEFINE_F(Fixture, SaveAssetFlatbuffer)(benchmark::State& state)
|
|||||||
{
|
{
|
||||||
state.PauseTiming();
|
state.PauseTiming();
|
||||||
BenchmarkAsset asset;
|
BenchmarkAsset asset;
|
||||||
asset.SetName(asset.GetHeader().uuid.ToString().c_str());
|
asset.SetName(asset.GetHeader().uuid.ToString());
|
||||||
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
|
for (std::uint32_t j = 0; j < REFS_PER_ASSET; ++j)
|
||||||
|
{
|
||||||
|
asset.GetAsset().refs.emplace_back(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
||||||
|
}
|
||||||
|
|
||||||
const AssetMetadata metadata {.m_uuid = asset.GetHeader().uuid,
|
|
||||||
.m_name = asset.GetHeader().name,
|
|
||||||
.m_typeID = asset.GetHeader().type_id,
|
|
||||||
.m_typeName = asset.GetHeader().type_name};
|
|
||||||
const eastl::vector<std::byte> flatbuffer = asset.Pack();
|
const eastl::vector<std::byte> flatbuffer = asset.Pack();
|
||||||
|
const eastl::vector<UUID> hardReferences = asset.GetHardReferences(flatbuffer);
|
||||||
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
||||||
state.ResumeTiming();
|
state.ResumeTiming();
|
||||||
|
|
||||||
m_bigFile.SaveAssetFlatbuffer(metadata, flatbuffer);
|
m_bigFile->SaveAssetFlatbuffer(asset.GetHeader().uuid, flatbuffer, hardReferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations());
|
state.SetItemsProcessed(state.iterations());
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(Fixture, SaveAssetFlatbuffer)->Name("BigFile/SaveAssetFlatbuffer");
|
BENCHMARK_REGISTER_F(BigFileFixture, SaveAssetFlatbuffer)->Name("BigFile/SaveAssetFlatbuffer")->UseRealTime();
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BENCHMARK_DEFINE_F(Fixture, SaveAssetFlatbuffers)(benchmark::State& state)
|
BENCHMARK_DEFINE_F(BigFileFixture, SaveAssetFlatbuffers)(benchmark::State& state)
|
||||||
{
|
{
|
||||||
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
||||||
std::int64_t bytesProcessed = 0;
|
std::int64_t bytesProcessed = 0;
|
||||||
@@ -238,39 +268,45 @@ BENCHMARK_DEFINE_F(Fixture, SaveAssetFlatbuffers)(benchmark::State& state)
|
|||||||
for (auto _: state)
|
for (auto _: state)
|
||||||
{
|
{
|
||||||
state.PauseTiming();
|
state.PauseTiming();
|
||||||
eastl::vector<AssetMetadata> metadatas;
|
eastl::vector<UUID> uuids;
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
metadatas.reserve(batchSize);
|
eastl::vector<eastl::vector<UUID>> hardReferences;
|
||||||
|
uuids.reserve(batchSize);
|
||||||
flatbuffers.reserve(batchSize);
|
flatbuffers.reserve(batchSize);
|
||||||
|
hardReferences.reserve(batchSize);
|
||||||
|
|
||||||
for (std::size_t i = 0; i < batchSize; ++i)
|
for (std::size_t i = 0; i < batchSize; ++i)
|
||||||
{
|
{
|
||||||
BenchmarkAsset asset;
|
BenchmarkAsset asset;
|
||||||
asset.SetName(asset.GetHeader().uuid.ToString().c_str());
|
asset.SetName(asset.GetHeader().uuid.ToString());
|
||||||
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
|
for (std::uint32_t j = 0; j < REFS_PER_ASSET; ++j)
|
||||||
|
{
|
||||||
|
asset.GetAsset().refs.emplace_back(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
||||||
|
}
|
||||||
|
|
||||||
metadatas.push_back(AssetMetadata {.m_uuid = asset.GetHeader().uuid,
|
eastl::vector<std::byte> flatbuffer = asset.Pack();
|
||||||
.m_name = asset.GetHeader().name,
|
uuids.push_back(asset.GetHeader().uuid);
|
||||||
.m_typeID = asset.GetHeader().type_id,
|
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
||||||
.m_typeName = asset.GetHeader().type_name});
|
hardReferences.push_back(asset.GetHardReferences(flatbuffer));
|
||||||
flatbuffers.push_back(asset.Pack());
|
flatbuffers.push_back(std::move(flatbuffer));
|
||||||
bytesProcessed += static_cast<std::int64_t>(flatbuffers.back().size());
|
|
||||||
}
|
}
|
||||||
state.ResumeTiming();
|
state.ResumeTiming();
|
||||||
|
|
||||||
m_bigFile.SaveAssetFlatbuffers(metadatas, flatbuffers);
|
m_bigFile->SaveAssetFlatbuffers(uuids, flatbuffers, hardReferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.SetItemsProcessed(state.iterations() * batchSize);
|
state.SetItemsProcessed(state.iterations() * batchSize);
|
||||||
state.SetBytesProcessed(bytesProcessed);
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
}
|
}
|
||||||
|
|
||||||
BENCHMARK_REGISTER_F(Fixture, SaveAssetFlatbuffers)
|
BENCHMARK_REGISTER_F(BigFileFixture, SaveAssetFlatbuffers)
|
||||||
->Name("BigFile/SaveAssetFlatbuffers")
|
->Name("BigFile/SaveAssetFlatbuffers")
|
||||||
->Arg(1)
|
->Arg(1)
|
||||||
->Arg(8)
|
->Arg(8)
|
||||||
->Arg(64)
|
->Arg(64)
|
||||||
->Arg(512)
|
->Arg(512)
|
||||||
->Arg(4096);
|
->Arg(4096)
|
||||||
|
->UseRealTime();
|
||||||
#endif
|
#endif
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -10,3 +10,5 @@ target_link_libraries(${PROJECT_NAME}
|
|||||||
$<LINK_LIBRARY:WHOLE_ARCHIVE,AssetsForBenchmarking>)
|
$<LINK_LIBRARY:WHOLE_ARCHIVE,AssetsForBenchmarking>)
|
||||||
|
|
||||||
bigfoot_create_bigfile("Benchmarks/Bigfoot")
|
bigfoot_create_bigfile("Benchmarks/Bigfoot")
|
||||||
|
|
||||||
|
bigfoot_create_sasquatch_info()
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Bigfoot
|
|||||||
/*
|
/*
|
||||||
* BigFile location
|
* BigFile location
|
||||||
*/
|
*/
|
||||||
constexpr eastl::string_view BIGFILE_ENGINEBENCHMARKS_LOCATION {"./EngineBenchmarks-bigfile.db"};
|
constexpr eastl::string_view BIGFILE_ENGINEBENCHMARKS_LOCATION {"./EngineBenchmarks.db"};
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// AUTO-GENERATED DO NOT TOUCH
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SasquatchInfo.generated.hpp
|
||||||
|
*
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_ENGINEBENCHMARKS_SASQUATCHINFO_GENERATED_HPP
|
||||||
|
#define BIGFOOT_ENGINEBENCHMARKS_SASQUATCHINFO_GENERATED_HPP
|
||||||
|
|
||||||
|
#include <EASTL/string_view.h>
|
||||||
|
|
||||||
|
#if defined BIGFOOT_GAME
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Sasquatch location
|
||||||
|
*/
|
||||||
|
constexpr eastl::string_view SASQUATCH_ENGINEBENCHMARKS_LOCATION {"./EngineBenchmarks.sasquatch"};
|
||||||
|
} // namespace Bigfoot
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file Sasquatch.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Engine/Sasquatch/Sasquatch.hpp>
|
||||||
|
|
||||||
|
#include <System/File/File.hpp>
|
||||||
|
#include <System/UUID/UUID.hpp>
|
||||||
|
|
||||||
|
#include <EngineBenchmarks/SasquatchInfo_generated.hpp>
|
||||||
|
|
||||||
|
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
||||||
|
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/optional.h>
|
||||||
|
#include <EASTL/span.h>
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
#include <benchmark/benchmark.h>
|
||||||
|
#include <effolkronium/random.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
#ifdef BIGFOOT_GAME
|
||||||
|
using Random = effolkronium::random_static;
|
||||||
|
|
||||||
|
class SasquatchFixture: public benchmark::Fixture
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
static constexpr std::uint32_t ASSET_COUNT = 20'000;
|
||||||
|
static constexpr std::uint32_t REFS_PER_ASSET = 4;
|
||||||
|
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
|
||||||
|
|
||||||
|
void SetUp([[maybe_unused]] benchmark::State& p_state) override
|
||||||
|
{
|
||||||
|
// The Sasquatch file is built exactly once for the entire benchmark process.
|
||||||
|
// SetUp is called before every calibration round (Google Benchmark doubles
|
||||||
|
// iteration counts until it reaches a stable measurement), so rebuilding
|
||||||
|
// the file each time would dominate the total benchmark time.
|
||||||
|
m_uuids = BuildData();
|
||||||
|
m_sasquatch.emplace(File {SASQUATCH_ENGINEBENCHMARKS_LOCATION});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown([[maybe_unused]] benchmark::State& p_state) override
|
||||||
|
{
|
||||||
|
m_sasquatch.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<UUID> RandomBatch(const std::size_t p_batchSize) const
|
||||||
|
{
|
||||||
|
eastl::vector<UUID> batch;
|
||||||
|
batch.reserve(p_batchSize);
|
||||||
|
for (std::size_t i = 0; i < p_batchSize; ++i)
|
||||||
|
{
|
||||||
|
batch.push_back(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return batch;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<eastl::vector<UUID>> RandomBatchPool(const std::size_t p_batchSize,
|
||||||
|
const std::size_t p_poolSize) const
|
||||||
|
{
|
||||||
|
eastl::vector<eastl::vector<UUID>> pool;
|
||||||
|
pool.reserve(p_poolSize);
|
||||||
|
for (std::size_t i = 0; i < p_poolSize; ++i)
|
||||||
|
{
|
||||||
|
pool.push_back(RandomBatch(p_batchSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::optional<Sasquatch> m_sasquatch;
|
||||||
|
eastl::span<const UUID> m_uuids;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const eastl::vector<UUID>& BuildData()
|
||||||
|
{
|
||||||
|
static const eastl::vector<UUID> s_uuids = []()
|
||||||
|
{
|
||||||
|
File {SASQUATCH_ENGINEBENCHMARKS_LOCATION}.Delete();
|
||||||
|
|
||||||
|
eastl::vector<UUID> uuids;
|
||||||
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
|
eastl::vector<eastl::vector<UUID>> hardReferences;
|
||||||
|
uuids.reserve(ASSET_COUNT);
|
||||||
|
flatbuffers.reserve(ASSET_COUNT);
|
||||||
|
hardReferences.reserve(ASSET_COUNT);
|
||||||
|
|
||||||
|
for (std::uint32_t i = 0; i < ASSET_COUNT; ++i)
|
||||||
|
{
|
||||||
|
BenchmarkAsset asset;
|
||||||
|
asset.SetName(asset.GetHeader().uuid.ToString());
|
||||||
|
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
|
for (std::uint32_t j = 0; j < REFS_PER_ASSET; ++j)
|
||||||
|
{
|
||||||
|
BenchmarkAssetReferred assetReferred;
|
||||||
|
assetReferred.SetName(assetReferred.GetHeader().uuid.ToString());
|
||||||
|
|
||||||
|
asset.GetAsset().refs.emplace_back(assetReferred.GetHeader().uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<std::byte> flatbuffer = asset.Pack();
|
||||||
|
hardReferences.push_back(asset.GetHardReferences(flatbuffer));
|
||||||
|
flatbuffers.push_back(std::move(flatbuffer));
|
||||||
|
uuids.push_back(asset.GetHeader().uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t totalFlatbufferBytes = 0;
|
||||||
|
std::size_t totalHardReferencesBytes = 0;
|
||||||
|
for (std::size_t i = 0; i < uuids.size(); ++i)
|
||||||
|
{
|
||||||
|
totalFlatbufferBytes += flatbuffers[i].size();
|
||||||
|
totalHardReferencesBytes += hardReferences[i].size() * UUID::UUID_BYTE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
SasquatchWriter writer {File {SASQUATCH_ENGINEBENCHMARKS_LOCATION},
|
||||||
|
uuids.size(),
|
||||||
|
totalFlatbufferBytes,
|
||||||
|
totalHardReferencesBytes};
|
||||||
|
for (std::size_t i = 0; i < uuids.size(); ++i)
|
||||||
|
{
|
||||||
|
writer.WriteAsset(uuids[i], flatbuffers[i], hardReferences[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uuids;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return s_uuids;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetHardReferences)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
benchmark::DoNotOptimize(
|
||||||
|
m_sasquatch->GetAssetHardReferences(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]));
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations());
|
||||||
|
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations()) * REFS_PER_ASSET * UUID::UUID_BYTE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetHardReferences)->Name("Sasquatch/GetAssetHardReferences")->UseRealTime();
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetsHardReferences)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
||||||
|
|
||||||
|
constexpr std::size_t BATCH_POOL_SIZE = 64;
|
||||||
|
const eastl::vector<eastl::vector<UUID>> batchPool = RandomBatchPool(batchSize, BATCH_POOL_SIZE);
|
||||||
|
|
||||||
|
std::size_t batchIndex = 0;
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
benchmark::DoNotOptimize(m_sasquatch->GetAssetsHardReferences(batchPool[batchIndex]));
|
||||||
|
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * batchSize);
|
||||||
|
state.SetBytesProcessed(static_cast<std::int64_t>(state.iterations()) * batchSize * REFS_PER_ASSET *
|
||||||
|
UUID::UUID_BYTE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetsHardReferences)
|
||||||
|
->Name("Sasquatch/GetAssetsHardReferences")
|
||||||
|
->Arg(1)
|
||||||
|
->Arg(8)
|
||||||
|
->Arg(64)
|
||||||
|
->Arg(512)
|
||||||
|
->Arg(4096)
|
||||||
|
->UseRealTime();
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetFlatbuffer)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
std::int64_t bytesProcessed = 0;
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
eastl::vector<std::byte> flatbuffer = m_sasquatch->GetAssetFlatbuffer(
|
||||||
|
m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
|
||||||
|
benchmark::DoNotOptimize(flatbuffer);
|
||||||
|
|
||||||
|
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations());
|
||||||
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetFlatbuffer)->Name("Sasquatch/GetAssetFlatbuffer")->UseRealTime();
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetFlatbuffers)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
||||||
|
|
||||||
|
constexpr std::size_t BATCH_POOL_SIZE = 64;
|
||||||
|
const eastl::vector<eastl::vector<UUID>> batchPool = RandomBatchPool(batchSize, BATCH_POOL_SIZE);
|
||||||
|
|
||||||
|
std::int64_t bytesProcessed = 0;
|
||||||
|
std::size_t batchIndex = 0;
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
eastl::vector<eastl::vector<std::byte>> flatbuffers = m_sasquatch->GetAssetFlatbuffers(batchPool[batchIndex]);
|
||||||
|
benchmark::DoNotOptimize(flatbuffers);
|
||||||
|
|
||||||
|
for (const eastl::vector<std::byte>& flatbuffer: flatbuffers)
|
||||||
|
{
|
||||||
|
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * batchSize);
|
||||||
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetFlatbuffers)
|
||||||
|
->Name("Sasquatch/GetAssetFlatbuffers")
|
||||||
|
->Arg(1)
|
||||||
|
->Arg(8)
|
||||||
|
->Arg(64)
|
||||||
|
->Arg(512)
|
||||||
|
->Arg(4096)
|
||||||
|
->UseRealTime();
|
||||||
|
#endif
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -0,0 +1,391 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file SerializationManager.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Engine/SerializationManager/SerializationManager.hpp>
|
||||||
|
|
||||||
|
#include <Engine/Asset/AssetLibrary.hpp>
|
||||||
|
#include <Engine/DataAccessor/DataAccessor.hpp>
|
||||||
|
|
||||||
|
#if defined BIGFOOT_TOOLMODE
|
||||||
|
#include <Engine/BigFile/BigFile.hpp>
|
||||||
|
|
||||||
|
#include <EngineBenchmarks/BigFileInfo_generated.hpp>
|
||||||
|
#elif defined BIGFOOT_GAME
|
||||||
|
#include <Engine/Sasquatch/Sasquatch.hpp>
|
||||||
|
|
||||||
|
#include <EngineBenchmarks/SasquatchInfo_generated.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <System/File/File.hpp>
|
||||||
|
#include <System/UUID/UUID.hpp>
|
||||||
|
|
||||||
|
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
||||||
|
#include <AssetsForBenchmarking/Asset/BenchmarkAssetReferred.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/optional.h>
|
||||||
|
#include <EASTL/span.h>
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
#include <ankerl/unordered_dense.h>
|
||||||
|
#include <benchmark/benchmark.h>
|
||||||
|
#include <effolkronium/random.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
using Random = effolkronium::random_static;
|
||||||
|
|
||||||
|
class SerializationManagerFixture: public benchmark::Fixture
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
static constexpr std::uint32_t ROOT_ASSET_COUNT = 20'000;
|
||||||
|
static constexpr std::uint32_t REFS_PER_ROOT = 4;
|
||||||
|
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
|
||||||
|
|
||||||
|
void SetUp([[maybe_unused]] benchmark::State& p_state) override
|
||||||
|
{
|
||||||
|
m_previousDataAccessor = g_dataAccessor;
|
||||||
|
m_previousAssetLibrary = g_activeAssetLibrary;
|
||||||
|
|
||||||
|
// The data store is populated exactly once for the entire benchmark process.
|
||||||
|
// SetUp is called before every calibration round (Google Benchmark doubles
|
||||||
|
// iteration counts until it reaches a stable measurement), so rebuilding
|
||||||
|
// the data store each time would dominate the total benchmark time.
|
||||||
|
static const SharedData& s_data = BuildData();
|
||||||
|
m_rootUuids = s_data.rootUuids;
|
||||||
|
m_leafUuids = s_data.leafUuids;
|
||||||
|
m_rootTotalBytes = &s_data.rootTotalBytes;
|
||||||
|
|
||||||
|
#if defined BIGFOOT_TOOLMODE
|
||||||
|
m_bigFile.emplace(File {BIGFILE_ENGINEBENCHMARKS_LOCATION});
|
||||||
|
SetDataAccessor(&*m_bigFile);
|
||||||
|
#elif defined BIGFOOT_GAME
|
||||||
|
m_sasquatch.emplace(File {SASQUATCH_ENGINEBENCHMARKS_LOCATION});
|
||||||
|
SetDataAccessor(&*m_sasquatch);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown([[maybe_unused]] benchmark::State& p_state) override
|
||||||
|
{
|
||||||
|
#if defined BIGFOOT_TOOLMODE
|
||||||
|
m_bigFile.reset();
|
||||||
|
#elif defined BIGFOOT_GAME
|
||||||
|
m_sasquatch.reset();
|
||||||
|
#endif
|
||||||
|
SetDataAccessor(m_previousDataAccessor);
|
||||||
|
SetActiveAssetLibrary(m_previousAssetLibrary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Registers a fresh, empty AssetLibrary as the active one, so that every root and leaf asset appears unloaded
|
||||||
|
*
|
||||||
|
* \param p_library The library to register
|
||||||
|
* \param p_leafContainer The container to register leaves into
|
||||||
|
* \param p_rootContainer The container to register roots into
|
||||||
|
*/
|
||||||
|
static void ResetActiveLibrary(AssetLibrary& p_library,
|
||||||
|
AssetContainer<BenchmarkAssetReferred>& p_leafContainer,
|
||||||
|
AssetContainer<BenchmarkAsset>& p_rootContainer)
|
||||||
|
{
|
||||||
|
std::ignore = p_library.Insert(&p_leafContainer);
|
||||||
|
std::ignore = p_library.Insert(&p_rootContainer);
|
||||||
|
SetActiveAssetLibrary(&p_library);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<UUID> RandomRootBatch(const std::size_t p_batchSize) const
|
||||||
|
{
|
||||||
|
eastl::vector<UUID> batch;
|
||||||
|
batch.reserve(p_batchSize);
|
||||||
|
for (std::size_t i = 0; i < p_batchSize; ++i)
|
||||||
|
{
|
||||||
|
batch.push_back(m_rootUuids[Random::get<std::size_t>(0, m_rootUuids.size() - 1)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return batch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Total flatbuffer bytes (root + its leaves) that loading p_roots will actually read, deduplicated the same way
|
||||||
|
* SerializationManager::LoadAssets deduplicates its own transitive discovery
|
||||||
|
*
|
||||||
|
* \param p_roots The root assets that would be loaded
|
||||||
|
* \return The total flatbuffer bytes across the unique roots
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
std::int64_t TotalBytes(const eastl::vector<UUID>& p_roots) const
|
||||||
|
{
|
||||||
|
ankerl::unordered_dense::set<UUID> unique;
|
||||||
|
unique.reserve(p_roots.size());
|
||||||
|
for (const UUID& uuid: p_roots)
|
||||||
|
{
|
||||||
|
unique.insert(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t bytes = 0;
|
||||||
|
for (const UUID& uuid: unique)
|
||||||
|
{
|
||||||
|
bytes += static_cast<std::int64_t>(m_rootTotalBytes->at(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataAccessor* m_previousDataAccessor = nullptr;
|
||||||
|
AssetLibrary* m_previousAssetLibrary = nullptr;
|
||||||
|
|
||||||
|
eastl::span<const UUID> m_rootUuids;
|
||||||
|
eastl::span<const UUID> m_leafUuids;
|
||||||
|
const ankerl::unordered_dense::map<UUID, std::size_t>* m_rootTotalBytes = nullptr;
|
||||||
|
|
||||||
|
#if defined BIGFOOT_TOOLMODE
|
||||||
|
eastl::optional<BigFile> m_bigFile;
|
||||||
|
#elif defined BIGFOOT_GAME
|
||||||
|
eastl::optional<Sasquatch> m_sasquatch;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct SharedData
|
||||||
|
{
|
||||||
|
eastl::vector<UUID> rootUuids;
|
||||||
|
eastl::vector<UUID> leafUuids;
|
||||||
|
ankerl::unordered_dense::map<UUID, std::size_t> rootTotalBytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const SharedData& BuildData()
|
||||||
|
{
|
||||||
|
static const SharedData s_data = []()
|
||||||
|
{
|
||||||
|
SharedData data;
|
||||||
|
data.rootUuids.reserve(ROOT_ASSET_COUNT);
|
||||||
|
data.leafUuids.reserve(ROOT_ASSET_COUNT * REFS_PER_ROOT);
|
||||||
|
data.rootTotalBytes.reserve(ROOT_ASSET_COUNT);
|
||||||
|
|
||||||
|
eastl::vector<UUID> uuids;
|
||||||
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
|
eastl::vector<eastl::vector<UUID>> hardReferences;
|
||||||
|
uuids.reserve(ROOT_ASSET_COUNT * (1 + REFS_PER_ROOT));
|
||||||
|
flatbuffers.reserve(uuids.capacity());
|
||||||
|
hardReferences.reserve(uuids.capacity());
|
||||||
|
|
||||||
|
for (std::uint32_t i = 0; i < ROOT_ASSET_COUNT; ++i)
|
||||||
|
{
|
||||||
|
BenchmarkAsset root;
|
||||||
|
root.SetName(root.GetHeader().uuid.ToString());
|
||||||
|
root.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
|
|
||||||
|
std::size_t totalBytes = 0;
|
||||||
|
for (std::uint32_t j = 0; j < REFS_PER_ROOT; ++j)
|
||||||
|
{
|
||||||
|
BenchmarkAssetReferred leaf;
|
||||||
|
leaf.SetName(leaf.GetHeader().uuid.ToString());
|
||||||
|
|
||||||
|
root.GetAsset().refs.emplace_back(leaf.GetHeader().uuid);
|
||||||
|
|
||||||
|
eastl::vector<std::byte> leafFlatbuffer = leaf.Pack();
|
||||||
|
totalBytes += leafFlatbuffer.size();
|
||||||
|
data.leafUuids.push_back(leaf.GetHeader().uuid);
|
||||||
|
uuids.push_back(leaf.GetHeader().uuid);
|
||||||
|
hardReferences.push_back(leaf.GetHardReferences(leafFlatbuffer));
|
||||||
|
flatbuffers.push_back(std::move(leafFlatbuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<std::byte> rootFlatbuffer = root.Pack();
|
||||||
|
totalBytes += rootFlatbuffer.size();
|
||||||
|
data.rootTotalBytes.emplace(root.GetHeader().uuid, totalBytes);
|
||||||
|
data.rootUuids.push_back(root.GetHeader().uuid);
|
||||||
|
uuids.push_back(root.GetHeader().uuid);
|
||||||
|
hardReferences.push_back(root.GetHardReferences(rootFlatbuffer));
|
||||||
|
flatbuffers.push_back(std::move(rootFlatbuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined BIGFOOT_TOOLMODE
|
||||||
|
BigFile bigFile {File { BIGFILE_ENGINEBENCHMARKS_LOCATION }};
|
||||||
|
bigFile.Clear();
|
||||||
|
bigFile.SaveAssetFlatbuffers(uuids, flatbuffers, hardReferences);
|
||||||
|
#elif defined BIGFOOT_GAME
|
||||||
|
std::size_t totalFlatbufferBytes = 0;
|
||||||
|
std::size_t totalHardReferencesBytes = 0;
|
||||||
|
for (std::size_t i = 0; i < uuids.size(); ++i)
|
||||||
|
{
|
||||||
|
totalFlatbufferBytes += flatbuffers[i].size();
|
||||||
|
totalHardReferencesBytes += hardReferences[i].size() * UUID::UUID_BYTE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
File {SASQUATCH_ENGINEBENCHMARKS_LOCATION}.Delete();
|
||||||
|
SasquatchWriter writer {File {SASQUATCH_ENGINEBENCHMARKS_LOCATION},
|
||||||
|
uuids.size(),
|
||||||
|
totalFlatbufferBytes,
|
||||||
|
totalHardReferencesBytes};
|
||||||
|
for (std::size_t i = 0; i < uuids.size(); ++i)
|
||||||
|
{
|
||||||
|
writer.WriteAsset(uuids[i], flatbuffers[i], hardReferences[i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return s_data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(SerializationManagerFixture, LoadAsset)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
std::int64_t bytesProcessed = 0;
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
state.PauseTiming();
|
||||||
|
AssetLibrary library;
|
||||||
|
// leafContainer must outlive rootContainer: the loaded root's HardReferences release into leafContainer's
|
||||||
|
// handles on destruction, so declaring it second would tear it down first and use-after-free those handles.
|
||||||
|
AssetContainer<BenchmarkAssetReferred> leafContainer;
|
||||||
|
AssetContainer<BenchmarkAsset> rootContainer;
|
||||||
|
ResetActiveLibrary(library, leafContainer, rootContainer);
|
||||||
|
|
||||||
|
const UUID uuid = m_rootUuids[Random::get<std::size_t>(0, m_rootUuids.size() - 1)];
|
||||||
|
const std::size_t uuidBytes = m_rootTotalBytes->at(uuid);
|
||||||
|
state.ResumeTiming();
|
||||||
|
|
||||||
|
SerializationManager::LoadAsset(uuid);
|
||||||
|
bytesProcessed += static_cast<std::int64_t>(uuidBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * (1 + REFS_PER_ROOT));
|
||||||
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(SerializationManagerFixture, LoadAsset)->Name("SerializationManager/LoadAsset")->UseRealTime();
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(SerializationManagerFixture, LoadAssets)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
||||||
|
std::int64_t bytesProcessed = 0;
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
state.PauseTiming();
|
||||||
|
AssetLibrary library;
|
||||||
|
// leafContainer must outlive rootContainer, see the same comment in the LoadAsset benchmark above.
|
||||||
|
AssetContainer<BenchmarkAssetReferred> leafContainer;
|
||||||
|
AssetContainer<BenchmarkAsset> rootContainer;
|
||||||
|
ResetActiveLibrary(library, leafContainer, rootContainer);
|
||||||
|
|
||||||
|
const eastl::vector<UUID> batch = RandomRootBatch(batchSize);
|
||||||
|
const std::int64_t batchBytes = TotalBytes(batch);
|
||||||
|
state.ResumeTiming();
|
||||||
|
|
||||||
|
SerializationManager::LoadAssets(batch);
|
||||||
|
bytesProcessed += batchBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * batchSize * (1 + REFS_PER_ROOT));
|
||||||
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(SerializationManagerFixture, LoadAssets)
|
||||||
|
->Name("SerializationManager/LoadAssets")
|
||||||
|
->Arg(1)
|
||||||
|
->Arg(8)
|
||||||
|
->Arg(64)
|
||||||
|
->Arg(512)
|
||||||
|
->Arg(4096)
|
||||||
|
->UseRealTime();
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
#if defined BIGFOOT_TOOLMODE
|
||||||
|
BENCHMARK_DEFINE_F(SerializationManagerFixture, SaveAsset)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
AssetLibrary library;
|
||||||
|
AssetContainer<BenchmarkAsset> container;
|
||||||
|
std::ignore = library.Insert(&container);
|
||||||
|
SetActiveAssetLibrary(&library);
|
||||||
|
|
||||||
|
std::int64_t bytesProcessed = 0;
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
state.PauseTiming();
|
||||||
|
auto* asset = CreateAsset<BenchmarkAsset>();
|
||||||
|
asset->SetName(asset->GetHeader().uuid.ToString());
|
||||||
|
asset->GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
|
for (std::uint32_t j = 0; j < REFS_PER_ROOT; ++j)
|
||||||
|
{
|
||||||
|
asset->GetAsset().refs.emplace_back(m_leafUuids[Random::get<std::size_t>(0, m_leafUuids.size() - 1)]);
|
||||||
|
}
|
||||||
|
const UUID uuid = asset->GetHeader().uuid;
|
||||||
|
const std::size_t assetBytes = asset->Pack().size();
|
||||||
|
bytesProcessed += static_cast<std::int64_t>(assetBytes);
|
||||||
|
state.ResumeTiming();
|
||||||
|
|
||||||
|
benchmark::DoNotOptimize(SerializationManager::SaveAsset(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations());
|
||||||
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(SerializationManagerFixture, SaveAsset)->Name("SerializationManager/SaveAsset")->UseRealTime();
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(SerializationManagerFixture, SaveAssets)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
const auto batchSize = static_cast<std::size_t>(state.range(0));
|
||||||
|
|
||||||
|
AssetLibrary library;
|
||||||
|
AssetContainer<BenchmarkAsset> container;
|
||||||
|
std::ignore = library.Insert(&container);
|
||||||
|
SetActiveAssetLibrary(&library);
|
||||||
|
|
||||||
|
std::int64_t bytesProcessed = 0;
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
state.PauseTiming();
|
||||||
|
eastl::vector<UUID> uuids;
|
||||||
|
uuids.reserve(batchSize);
|
||||||
|
std::size_t batchBytes = 0;
|
||||||
|
for (std::size_t i = 0; i < batchSize; ++i)
|
||||||
|
{
|
||||||
|
auto* asset = CreateAsset<BenchmarkAsset>();
|
||||||
|
asset->SetName(asset->GetHeader().uuid.ToString());
|
||||||
|
asset->GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
|
for (std::uint32_t j = 0; j < REFS_PER_ROOT; ++j)
|
||||||
|
{
|
||||||
|
asset->GetAsset().refs.emplace_back(m_leafUuids[Random::get<std::size_t>(0, m_leafUuids.size() - 1)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
batchBytes += asset->Pack().size();
|
||||||
|
uuids.push_back(asset->GetHeader().uuid);
|
||||||
|
}
|
||||||
|
state.ResumeTiming();
|
||||||
|
|
||||||
|
benchmark::DoNotOptimize(SerializationManager::SaveAssets(uuids));
|
||||||
|
bytesProcessed += static_cast<std::int64_t>(batchBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * batchSize);
|
||||||
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(SerializationManagerFixture, SaveAssets)
|
||||||
|
->Name("SerializationManager/SaveAssets")
|
||||||
|
->Arg(1)
|
||||||
|
->Arg(8)
|
||||||
|
->Arg(64)
|
||||||
|
->Arg(512)
|
||||||
|
->UseRealTime();
|
||||||
|
#endif
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/SasquatchBaker)
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
project(${PackageName}Benchmarks)
|
||||||
|
|
||||||
|
bigfoot_create_package_benchmarks(
|
||||||
|
"Tools")
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
PRIVATE
|
||||||
|
$<LINK_LIBRARY:WHOLE_ARCHIVE,AssetsForBenchmarking>)
|
||||||
|
|
||||||
|
bigfoot_create_bigfile("Benchmarks/Tools")
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
// AUTO-GENERATED DO NOT TOUCH
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* \file BigFileInfo.generated.hpp
|
||||||
|
*
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_SASQUATCHBAKERBENCHMARKS_BIGFILEINFO_GENERATED_HPP
|
||||||
|
#define BIGFOOT_SASQUATCHBAKERBENCHMARKS_BIGFILEINFO_GENERATED_HPP
|
||||||
|
|
||||||
|
#include <EASTL/string_view.h>
|
||||||
|
|
||||||
|
#if defined BIGFOOT_TOOLMODE
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* BigFile location
|
||||||
|
*/
|
||||||
|
constexpr eastl::string_view BIGFILE_SASQUATCHBAKERBENCHMARKS_LOCATION {"./SasquatchBakerBenchmarks.db"};
|
||||||
|
} // namespace Bigfoot
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file SasquatchBaker.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <SasquatchBaker/SasquatchBaker.hpp>
|
||||||
|
|
||||||
|
#include <Engine/BigFile/BigFile.hpp>
|
||||||
|
#include <Engine/Sasquatch/Sasquatch.hpp>
|
||||||
|
|
||||||
|
#include <System/File/File.hpp>
|
||||||
|
|
||||||
|
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
|
||||||
|
|
||||||
|
#include <SasquatchBakerBenchmarks/BigFileInfo_generated.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
#include <benchmark/benchmark.h>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
class SasquatchBakerFixture: public benchmark::Fixture
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
static constexpr std::uint32_t ASSET_COUNT = 20'000;
|
||||||
|
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
|
||||||
|
|
||||||
|
void SetUp(benchmark::State&) override
|
||||||
|
{
|
||||||
|
m_bigFile.Clear();
|
||||||
|
m_outputFile.Delete();
|
||||||
|
|
||||||
|
eastl::vector<UUID> uuids;
|
||||||
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
|
eastl::vector<eastl::vector<UUID>> hardReferences;
|
||||||
|
uuids.reserve(ASSET_COUNT);
|
||||||
|
flatbuffers.reserve(ASSET_COUNT);
|
||||||
|
hardReferences.reserve(ASSET_COUNT);
|
||||||
|
|
||||||
|
for (std::uint32_t i = 0; i < ASSET_COUNT; ++i)
|
||||||
|
{
|
||||||
|
BenchmarkAsset asset;
|
||||||
|
asset.SetName(asset.GetHeader().uuid.ToString());
|
||||||
|
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
|
||||||
|
|
||||||
|
const eastl::vector<std::byte> flatbuffer = asset.Pack();
|
||||||
|
flatbuffers.push_back(flatbuffer);
|
||||||
|
hardReferences.push_back(asset.GetHardReferences(flatbuffer));
|
||||||
|
uuids.push_back(asset.GetHeader().uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bigFile.SaveAssetFlatbuffers(uuids, flatbuffers, hardReferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown(benchmark::State&) override
|
||||||
|
{
|
||||||
|
m_outputFile.Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr eastl::string_view SASQUATCH_SASQUATCHBAKERBENCHMARKS_LOCATION {
|
||||||
|
"./SasquatchBakerBenchmarks.sasquatch"};
|
||||||
|
BigFile m_bigFile {File {BIGFILE_SASQUATCHBAKERBENCHMARKS_LOCATION}};
|
||||||
|
File m_outputFile {SASQUATCH_SASQUATCHBAKERBENCHMARKS_LOCATION};
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(SasquatchBakerFixture, Bake)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
std::int64_t bytesProcessed = 0;
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
Bake(m_bigFile, m_outputFile);
|
||||||
|
bytesProcessed += static_cast<std::int64_t>(m_outputFile.GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * ASSET_COUNT);
|
||||||
|
state.SetBytesProcessed(bytesProcessed);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(SasquatchBakerFixture, Bake)->Name("SasquatchBaker/Bake")->Unit(benchmark::kMillisecond);
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file Graph.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Utils/Algorithm/Graph.hpp>
|
||||||
|
|
||||||
|
#include <ankerl/unordered_dense.h>
|
||||||
|
#include <benchmark/benchmark.h>
|
||||||
|
#include <effolkronium/random.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
using Random = effolkronium::random_static;
|
||||||
|
|
||||||
|
class LayeredTopologicalSortFixture: public benchmark::Fixture
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/*
|
||||||
|
* Nodes are grouped into layers, and every node in a layer depends on up to DEPENDENCY_MAX_COUNT
|
||||||
|
* distinct nodes randomly picked from the previous layer.
|
||||||
|
*/
|
||||||
|
void SetUp(benchmark::State& state) override
|
||||||
|
{
|
||||||
|
Random::seed(0x5EEDU);
|
||||||
|
|
||||||
|
const auto nodeCount = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
|
m_graph.clear();
|
||||||
|
m_nodes.clear();
|
||||||
|
m_graph.reserve(nodeCount);
|
||||||
|
m_nodes.reserve(nodeCount);
|
||||||
|
|
||||||
|
for (std::uint32_t node = 0; node < nodeCount; ++node)
|
||||||
|
{
|
||||||
|
m_nodes.insert(node);
|
||||||
|
eastl::vector<std::uint32_t>& edges = m_graph[node];
|
||||||
|
|
||||||
|
const std::uint32_t layerStart = (node / NODE_COUNT_PER_LAYER) * NODE_COUNT_PER_LAYER;
|
||||||
|
if (layerStart == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::uint32_t previousLayerStart = layerStart - NODE_COUNT_PER_LAYER;
|
||||||
|
ankerl::unordered_dense::set<std::uint32_t> picked;
|
||||||
|
for (std::uint32_t i = 0; i < DEPENDENCY_MAX_COUNT; ++i)
|
||||||
|
{
|
||||||
|
const std::uint32_t dependency = Random::get<std::uint32_t>(previousLayerStart, layerStart - 1);
|
||||||
|
if (picked.insert(dependency).second)
|
||||||
|
{
|
||||||
|
edges.push_back(dependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr std::uint32_t NODE_COUNT_PER_LAYER = 64;
|
||||||
|
static constexpr std::uint32_t DEPENDENCY_MAX_COUNT = 4;
|
||||||
|
|
||||||
|
ankerl::unordered_dense::map<std::uint32_t, eastl::vector<std::uint32_t>> m_graph;
|
||||||
|
ankerl::unordered_dense::set<std::uint32_t> m_nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BENCHMARK_DEFINE_F(LayeredTopologicalSortFixture, LayeredTopologicalSortBench)(benchmark::State& state)
|
||||||
|
{
|
||||||
|
const auto nodeCount = static_cast<std::uint32_t>(state.range(0));
|
||||||
|
|
||||||
|
for (auto _: state)
|
||||||
|
{
|
||||||
|
eastl::vector<eastl::vector<std::uint32_t>> waves;
|
||||||
|
eastl::vector<std::uint32_t> cyclicNodes;
|
||||||
|
benchmark::DoNotOptimize(LayeredTopologicalSort(m_graph, m_nodes, waves, cyclicNodes));
|
||||||
|
benchmark::DoNotOptimize(waves);
|
||||||
|
benchmark::ClobberMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.SetItemsProcessed(state.iterations() * nodeCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_REGISTER_F(LayeredTopologicalSortFixture, LayeredTopologicalSortBench)
|
||||||
|
->Name("Bigfoot::LayeredTopologicalSort")
|
||||||
|
->Arg(512)
|
||||||
|
->Arg(8192)
|
||||||
|
->Arg(262'144)
|
||||||
|
->Arg(4'194'304);
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -11,10 +11,7 @@
|
|||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
namespace
|
|
||||||
{
|
|
||||||
using Random = effolkronium::random_static;
|
using Random = effolkronium::random_static;
|
||||||
} // namespace
|
|
||||||
|
|
||||||
struct MyComplexStruct
|
struct MyComplexStruct
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System)
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
||||||
|
if(${TOOLMODE})
|
||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Tools)
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file AssetBase.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date April 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Engine/Asset/AssetBase.hpp>
|
||||||
|
|
||||||
|
#include <Engine/Asset/Reference_generated.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
void AssetBase::HardReferenceVisitor::Field([[maybe_unused]] size_t p_fieldIndex,
|
||||||
|
[[maybe_unused]] size_t p_setIndex,
|
||||||
|
const flatbuffers::ElementaryType p_type,
|
||||||
|
const bool p_isVector,
|
||||||
|
const flatbuffers::TypeTable* p_typeTable,
|
||||||
|
[[maybe_unused]] const char* p_name,
|
||||||
|
const std::uint8_t* p_val)
|
||||||
|
{
|
||||||
|
if (!p_isVector)
|
||||||
|
{
|
||||||
|
Visit(p_type, p_typeTable, p_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void AssetBase::HardReferenceVisitor::Element([[maybe_unused]] size_t p_index,
|
||||||
|
const flatbuffers::ElementaryType p_type,
|
||||||
|
const flatbuffers::TypeTable* p_typeTable,
|
||||||
|
const std::uint8_t* p_val)
|
||||||
|
{
|
||||||
|
Visit(p_type, p_typeTable, p_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::vector<UUID> AssetBase::HardReferenceVisitor::GetUUIDs() const
|
||||||
|
{
|
||||||
|
eastl::vector<UUID> uuids;
|
||||||
|
uuids.reserve(m_uuids.size());
|
||||||
|
std::copy(m_uuids.begin(), m_uuids.end(), eastl::back_inserter(uuids));
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void AssetBase::HardReferenceVisitor::Visit(const flatbuffers::ElementaryType p_type,
|
||||||
|
const flatbuffers::TypeTable* p_typeTable,
|
||||||
|
const std::uint8_t* p_val)
|
||||||
|
{
|
||||||
|
if (p_val == nullptr || p_type != flatbuffers::ET_SEQUENCE ||
|
||||||
|
p_typeTable != ::Flat::Bigfoot::HardReference::MiniReflectTypeTable())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ::Flat::Bigfoot::HardReference* hardReference = reinterpret_cast<const ::Flat::Bigfoot::HardReference*>(
|
||||||
|
p_val);
|
||||||
|
m_uuids.emplace(flatbuffers::UnPack(hardReference->uuid()));
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file AssetContainer.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Engine/Asset/AssetContainer.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
ContainerHandle::ContainerHandle(AssetContainerBase* p_assetContainer, const UUID p_uuid):
|
||||||
|
m_assetContainer(p_assetContainer),
|
||||||
|
m_uuid(p_uuid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
std::uint32_t ContainerHandle::GetHardRefCount() const
|
||||||
|
{
|
||||||
|
return m_hardRefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void ContainerHandle::IncrementHardRefCount()
|
||||||
|
{
|
||||||
|
if (m_hardRefCount == 0)
|
||||||
|
{
|
||||||
|
m_assetContainer->CancelRemoval(m_uuid);
|
||||||
|
}
|
||||||
|
++m_hardRefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void ContainerHandle::DecrementHardRefCount()
|
||||||
|
{
|
||||||
|
--m_hardRefCount;
|
||||||
|
if (m_hardRefCount == 0)
|
||||||
|
{
|
||||||
|
m_assetContainer->QueueForRemoval(m_uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
std::uint32_t ContainerHandle::GetSoftRefCount() const
|
||||||
|
{
|
||||||
|
return m_softRefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void ContainerHandle::IncrementSoftRefCount()
|
||||||
|
{
|
||||||
|
++m_softRefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void ContainerHandle::DecrementSoftRefCount()
|
||||||
|
{
|
||||||
|
--m_softRefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
AssetBase* ContainerHandle::GetAsset()
|
||||||
|
{
|
||||||
|
return m_asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const AssetBase* ContainerHandle::GetAsset() const
|
||||||
|
{
|
||||||
|
return m_asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void ContainerHandle::SetAsset(AssetBase* p_asset)
|
||||||
|
{
|
||||||
|
m_asset = p_asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
bool AssetContainerBase::Has(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
const Entry* entry = FindEntry(p_uuid);
|
||||||
|
return entry != nullptr && entry->m_assetSlotKey.Valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
ContainerHandle* AssetContainerBase::AcquireContainerHandle(const UUID& p_uuid)
|
||||||
|
{
|
||||||
|
return GetOrCreateEntry(p_uuid).m_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void AssetContainerBase::Remove(const UUID& p_uuid)
|
||||||
|
{
|
||||||
|
if (Entry* entry = FindEntry(p_uuid); entry != nullptr)
|
||||||
|
{
|
||||||
|
if (entry->m_assetSlotKey.Valid())
|
||||||
|
{
|
||||||
|
entry->m_handle->SetAsset(nullptr);
|
||||||
|
RemoveAsset(entry->m_assetSlotKey);
|
||||||
|
entry->m_assetSlotKey = SlotMapKey {};
|
||||||
|
}
|
||||||
|
m_handles.Remove(entry->m_handleSlotKey);
|
||||||
|
m_uuidToEntry.erase(p_uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void AssetContainerBase::QueueForRemoval(const UUID& p_uuid)
|
||||||
|
{
|
||||||
|
m_pendingRemovalUuids.push_back(p_uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void AssetContainerBase::CancelRemoval(const UUID& p_uuid)
|
||||||
|
{
|
||||||
|
auto* const pendingIt = eastl::find(m_pendingRemovalUuids.begin(), m_pendingRemovalUuids.end(), p_uuid);
|
||||||
|
if (pendingIt != m_pendingRemovalUuids.end())
|
||||||
|
{
|
||||||
|
m_pendingRemovalUuids.erase_unsorted(pendingIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void AssetContainerBase::ProcessPendingRemovals()
|
||||||
|
{
|
||||||
|
eastl::vector<UUID> toRemove;
|
||||||
|
toRemove.swap(m_pendingRemovalUuids);
|
||||||
|
|
||||||
|
for (const UUID& uuid: toRemove)
|
||||||
|
{
|
||||||
|
Remove(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
bool AssetContainerBase::IsMarkedForRemove(const UUID& p_uuid)
|
||||||
|
{
|
||||||
|
return eastl::find(m_pendingRemovalUuids.begin(), m_pendingRemovalUuids.end(), p_uuid) !=
|
||||||
|
m_pendingRemovalUuids.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
AssetContainerBase::Entry* AssetContainerBase::FindEntry(const UUID& p_uuid)
|
||||||
|
{
|
||||||
|
const auto entryIt = m_uuidToEntry.find(p_uuid);
|
||||||
|
return entryIt != m_uuidToEntry.end() ? &entryIt->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const AssetContainerBase::Entry* AssetContainerBase::FindEntry(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
const auto entryIt = m_uuidToEntry.find(p_uuid);
|
||||||
|
return entryIt != m_uuidToEntry.end() ? &entryIt->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
AssetContainerBase::Entry& AssetContainerBase::GetOrCreateEntry(const UUID& p_uuid)
|
||||||
|
{
|
||||||
|
auto [entryIt, inserted] = m_uuidToEntry.try_emplace(p_uuid);
|
||||||
|
if (inserted)
|
||||||
|
{
|
||||||
|
entryIt->second.m_handleSlotKey = m_handles.Insert(this, p_uuid);
|
||||||
|
entryIt->second.m_handle = m_handles.Get(entryIt->second.m_handleSlotKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entryIt->second;
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -8,6 +8,77 @@
|
|||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
|
AssetContainerBase* AssetLibrary::GetAssetContainer(const AssetTypeID p_typeID)
|
||||||
|
{
|
||||||
|
if (const auto container = m_assetContainers.find(p_typeID); container != m_assetContainers.end())
|
||||||
|
{
|
||||||
|
return container->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const AssetContainerBase* AssetLibrary::GetAssetContainer(const AssetTypeID p_typeID) const
|
||||||
|
{
|
||||||
|
if (const auto container = m_assetContainers.find(p_typeID); container != m_assetContainers.end())
|
||||||
|
{
|
||||||
|
return container->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const AssetContainerBase* AssetLibrary::GetAssetContainer(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
for (const auto [typeId, container]: m_assetContainers)
|
||||||
|
{
|
||||||
|
if (container->Has(p_uuid))
|
||||||
|
{
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
AssetContainerBase* AssetLibrary::GetAssetContainer(const UUID& p_uuid)
|
||||||
|
{
|
||||||
|
for (const auto [typeId, container]: m_assetContainers)
|
||||||
|
{
|
||||||
|
if (container->Has(p_uuid))
|
||||||
|
{
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
bool AssetLibrary::IsLoaded(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
return GetAssetContainer(p_uuid) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void AssetLibrary::ProcessPendingRemovals()
|
||||||
|
{
|
||||||
|
for (const auto [typeId, container]: m_assetContainers)
|
||||||
|
{
|
||||||
|
container->ProcessPendingRemovals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
void SetActiveAssetLibrary(AssetLibrary* p_assetLibrary)
|
void SetActiveAssetLibrary(AssetLibrary* p_assetLibrary)
|
||||||
{
|
{
|
||||||
g_activeAssetLibrary = p_assetLibrary;
|
g_activeAssetLibrary = p_assetLibrary;
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
#include <Engine/EngineAssertHandler.hpp>
|
#include <Engine/EngineAssertHandler.hpp>
|
||||||
|
|
||||||
|
#include <Utils/Format.hpp>
|
||||||
|
|
||||||
#include <EASTL/algorithm.h>
|
#include <EASTL/algorithm.h>
|
||||||
#include <EASTL/sort.h>
|
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
@@ -69,6 +69,19 @@ void BigFile::RollbackTransaction()
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void BigFile::Clear()
|
||||||
|
{
|
||||||
|
BeginTransaction();
|
||||||
|
|
||||||
|
BigFile::Request {*this, "DELETE FROM AssetHardReference;"}.Execute();
|
||||||
|
BigFile::Request {*this, "DELETE FROM Asset;"}.Execute();
|
||||||
|
BigFile::Request {*this, "DELETE FROM AssetMetadata;"}.Execute();
|
||||||
|
|
||||||
|
CommitTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
BigFile::~BigFile()
|
BigFile::~BigFile()
|
||||||
{
|
{
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
@@ -78,14 +91,14 @@ BigFile::~BigFile()
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
eastl::optional<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffer(const UUID& p_uuid) const
|
eastl::vector<std::byte> BigFile::GetAssetFlatbuffer(const UUID& p_uuid) const
|
||||||
{
|
{
|
||||||
BigFile::Request assetRequest {*this, "SELECT Asset FROM Asset WHERE UUID = ?1;"};
|
BigFile::Request assetRequest {*this, "SELECT Asset FROM Asset WHERE UUID = ?1;"};
|
||||||
assetRequest.Bind(1, p_uuid.ToBytes());
|
assetRequest.Bind(1, p_uuid.ToBytes());
|
||||||
|
|
||||||
if (!assetRequest.Step())
|
if (!assetRequest.Step())
|
||||||
{
|
{
|
||||||
return eastl::nullopt;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const eastl::span<const std::byte> flatbuffer = assetRequest.Get(0);
|
const eastl::span<const std::byte> flatbuffer = assetRequest.Get(0);
|
||||||
@@ -96,58 +109,74 @@ eastl::optional<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffer(const UUID
|
|||||||
|
|
||||||
eastl::vector<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffers(const eastl::span<const UUID> p_uuids) const
|
eastl::vector<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffers(const eastl::span<const UUID> p_uuids) const
|
||||||
{
|
{
|
||||||
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
eastl::vector<eastl::vector<std::byte>> flatbuffers(p_uuids.size());
|
||||||
|
|
||||||
if (p_uuids.empty())
|
if (p_uuids.empty())
|
||||||
{
|
{
|
||||||
return flatbuffers;
|
return flatbuffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
flatbuffers.reserve(p_uuids.size());
|
ankerl::unordered_dense::map<UUID, eastl::vector<std::size_t>> uuidToIndices;
|
||||||
|
uuidToIndices.reserve(p_uuids.size());
|
||||||
if (p_uuids.size() == 1)
|
for (std::size_t i = 0; i < p_uuids.size(); ++i)
|
||||||
{
|
{
|
||||||
if (eastl::optional<eastl::vector<std::byte>> flatbuffer = GetAssetFlatbuffer(p_uuids[0]);
|
uuidToIndices[p_uuids[i]].push_back(i);
|
||||||
flatbuffer.has_value())
|
|
||||||
{
|
|
||||||
flatbuffers.push_back(std::move(*flatbuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
return flatbuffers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eastl::vector<UUID> uniqueUUIDs {p_uuids.begin(), p_uuids.end()};
|
eastl::vector<UUID> distinctUUIDs;
|
||||||
eastl::sort(uniqueUUIDs.begin(), uniqueUUIDs.end());
|
distinctUUIDs.reserve(uuidToIndices.size());
|
||||||
uniqueUUIDs.erase(eastl::unique(uniqueUUIDs.begin(), uniqueUUIDs.end()), uniqueUUIDs.end());
|
for (const auto& [uuid, indices]: uuidToIndices)
|
||||||
|
|
||||||
eastl::string placeholders;
|
|
||||||
placeholders.reserve(uniqueUUIDs.size() * 3);
|
|
||||||
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
|
||||||
{
|
{
|
||||||
if (i > 0)
|
distinctUUIDs.push_back(uuid);
|
||||||
{
|
|
||||||
placeholders += ", ";
|
|
||||||
}
|
|
||||||
placeholders += "?";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string sqlRequest = fmt::format("SELECT Asset FROM Asset WHERE UUID IN ({});", placeholders);
|
constexpr std::size_t PARAMS_PER_ROW = 1;
|
||||||
|
const std::size_t maxRowsPerStatement = static_cast<std::size_t>(
|
||||||
|
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
||||||
|
PARAMS_PER_ROW;
|
||||||
|
|
||||||
BigFile::Request assetRequest {*this, sqlRequest.c_str()};
|
for (std::size_t chunkStart = 0; chunkStart < distinctUUIDs.size(); chunkStart += maxRowsPerStatement)
|
||||||
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
|
||||||
{
|
{
|
||||||
assetRequest.Bind(static_cast<std::uint32_t>(i + 1), uniqueUUIDs[i].ToBytes());
|
const std::size_t chunkSize = eastl::min(maxRowsPerStatement, distinctUUIDs.size() - chunkStart);
|
||||||
}
|
|
||||||
|
|
||||||
flatbuffers.reserve(uniqueUUIDs.size());
|
eastl::string placeholders;
|
||||||
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
placeholders.reserve(chunkSize * 2);
|
||||||
{
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
if (!assetRequest.Step())
|
|
||||||
{
|
{
|
||||||
break;
|
if (i > 0)
|
||||||
|
{
|
||||||
|
placeholders += ", ";
|
||||||
|
}
|
||||||
|
placeholders += "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
const eastl::span<const std::byte> flatbuffer = assetRequest.Get(0);
|
const eastl::string sql = Format("SELECT UUID, Asset FROM Asset WHERE UUID IN ({});", placeholders);
|
||||||
flatbuffers.emplace_back(flatbuffer.begin(), flatbuffer.end());
|
|
||||||
|
BigFile::Request assetRequest {*this, sql};
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
assetRequest.Bind(static_cast<std::uint32_t>(i + 1), distinctUUIDs[chunkStart + i].ToBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (assetRequest.Step())
|
||||||
|
{
|
||||||
|
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawUUID {
|
||||||
|
static_cast<std::span<const std::byte>>(assetRequest.Get(0))};
|
||||||
|
const UUID uuid {rawUUID};
|
||||||
|
|
||||||
|
const auto indicesIt = uuidToIndices.find(uuid);
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
indicesIt != uuidToIndices.end(),
|
||||||
|
"Returned UUID {} not found in requested UUIDs",
|
||||||
|
uuid);
|
||||||
|
|
||||||
|
const eastl::span<const std::byte> flatbuffer = assetRequest.Get(1);
|
||||||
|
|
||||||
|
for (const std::size_t index: indicesIt->second)
|
||||||
|
{
|
||||||
|
flatbuffers[index].assign(flatbuffer.begin(), flatbuffer.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return flatbuffers;
|
return flatbuffers;
|
||||||
@@ -155,133 +184,271 @@ eastl::vector<eastl::vector<std::byte>> BigFile::GetAssetFlatbuffers(const eastl
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
eastl::optional<AssetMetadata> BigFile::GetAssetMetadata(const UUID& p_uuid) const
|
eastl::vector<UUID> BigFile::GetAssetHardReferences(const UUID& p_uuid) const
|
||||||
{
|
{
|
||||||
BigFile::Request assetRequest {
|
BigFile::Request hardReferencesRequest {*this, "SELECT HardReference FROM AssetHardReference WHERE UUID = ?1;"};
|
||||||
*this,
|
hardReferencesRequest.Bind(1, p_uuid.ToBytes());
|
||||||
"SELECT UUID, Name, TypeID, TypeName, CreateTime, ModificationTime FROM AssetMetadata WHERE UUID = ?1;"};
|
|
||||||
assetRequest.Bind(1, p_uuid.ToBytes());
|
|
||||||
|
|
||||||
if (!assetRequest.Step())
|
eastl::vector<UUID> hardReferences;
|
||||||
|
while (hardReferencesRequest.Step())
|
||||||
|
{
|
||||||
|
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawUUID {
|
||||||
|
static_cast<std::span<const std::byte>>(hardReferencesRequest.Get(0))};
|
||||||
|
hardReferences.emplace_back(rawUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hardReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::vector<eastl::vector<UUID>> BigFile::GetAssetsHardReferences(eastl::span<const UUID> p_uuids) const
|
||||||
|
{
|
||||||
|
eastl::vector<eastl::vector<UUID>> hardReferences(p_uuids.size());
|
||||||
|
|
||||||
|
if (p_uuids.empty())
|
||||||
|
{
|
||||||
|
return hardReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
ankerl::unordered_dense::map<UUID, eastl::vector<std::size_t>> uuidToIndices;
|
||||||
|
uuidToIndices.reserve(p_uuids.size());
|
||||||
|
for (std::size_t i = 0; i < p_uuids.size(); ++i)
|
||||||
|
{
|
||||||
|
uuidToIndices[p_uuids[i]].push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<UUID> distinctUUIDs;
|
||||||
|
distinctUUIDs.reserve(uuidToIndices.size());
|
||||||
|
for (const auto& [uuid, indices]: uuidToIndices)
|
||||||
|
{
|
||||||
|
distinctUUIDs.push_back(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::size_t PARAMS_PER_ROW = 1;
|
||||||
|
const std::size_t maxRowsPerStatement = static_cast<std::size_t>(
|
||||||
|
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
||||||
|
PARAMS_PER_ROW;
|
||||||
|
|
||||||
|
for (std::size_t chunkStart = 0; chunkStart < distinctUUIDs.size(); chunkStart += maxRowsPerStatement)
|
||||||
|
{
|
||||||
|
const std::size_t chunkSize = eastl::min(maxRowsPerStatement, distinctUUIDs.size() - chunkStart);
|
||||||
|
|
||||||
|
eastl::string placeholders;
|
||||||
|
placeholders.reserve(chunkSize * 2);
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
placeholders += ", ";
|
||||||
|
}
|
||||||
|
placeholders += "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
const eastl::string sql = Format("SELECT UUID, HardReference FROM AssetHardReference WHERE UUID IN ({});",
|
||||||
|
placeholders);
|
||||||
|
|
||||||
|
BigFile::Request hardReferencesRequest {*this, sql};
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
hardReferencesRequest.Bind(static_cast<std::uint32_t>(i + 1), distinctUUIDs[chunkStart + i].ToBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (hardReferencesRequest.Step())
|
||||||
|
{
|
||||||
|
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawOwnerUUID {
|
||||||
|
static_cast<std::span<const std::byte>>(hardReferencesRequest.Get(0))};
|
||||||
|
const UUID ownerUUID {rawOwnerUUID};
|
||||||
|
|
||||||
|
const auto indicesIt = uuidToIndices.find(ownerUUID);
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
indicesIt != uuidToIndices.end(),
|
||||||
|
"Returned UUID {} not found in requested UUIDs",
|
||||||
|
ownerUUID);
|
||||||
|
|
||||||
|
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawHardReference {
|
||||||
|
static_cast<std::span<const std::byte>>(hardReferencesRequest.Get(1))};
|
||||||
|
|
||||||
|
for (const std::size_t index: indicesIt->second)
|
||||||
|
{
|
||||||
|
hardReferences[index].emplace_back(rawHardReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hardReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::optional<BigFile::AssetTime> BigFile::GetAssetTime(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
BigFile::Request timeRequest {*this, "SELECT CreateTime, ModificationTime FROM AssetMetadata WHERE UUID = ?1;"};
|
||||||
|
timeRequest.Bind(1, p_uuid.ToBytes());
|
||||||
|
|
||||||
|
if (!timeRequest.Step())
|
||||||
{
|
{
|
||||||
return eastl::nullopt;
|
return eastl::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AssetMetadata {.m_uuid = UUID {std::span<const std::byte, UUID::UUID_BYTE_SIZE> {
|
return AssetTime {.m_creationTime = Time {static_cast<std::uint64_t>(timeRequest.Get(0))},
|
||||||
static_cast<eastl::span<const std::byte>>(assetRequest.Get(0)).data(),
|
.m_modificationTime = Time {static_cast<std::uint64_t>(timeRequest.Get(1))}};
|
||||||
UUID::UUID_BYTE_SIZE}},
|
|
||||||
.m_name = eastl::string {static_cast<eastl::string_view>(assetRequest.Get(1))},
|
|
||||||
.m_typeID = assetRequest.Get(2),
|
|
||||||
.m_typeName = eastl::string {static_cast<eastl::string_view>(assetRequest.Get(3))},
|
|
||||||
.m_creationTime = Time {static_cast<std::uint64_t>(assetRequest.Get(4))},
|
|
||||||
.m_modificationTime = Time {static_cast<std::uint64_t>(assetRequest.Get(5))}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
eastl::vector<AssetMetadata> BigFile::GetAssetMetadatas(const eastl::span<const UUID> p_uuids) const
|
eastl::vector<eastl::optional<BigFile::AssetTime>> BigFile::GetAssetsTime(const eastl::span<const UUID> p_uuids) const
|
||||||
{
|
{
|
||||||
eastl::vector<AssetMetadata> metadatas;
|
eastl::vector<eastl::optional<AssetTime>> times(p_uuids.size());
|
||||||
|
|
||||||
if (p_uuids.empty())
|
if (p_uuids.empty())
|
||||||
{
|
{
|
||||||
return metadatas;
|
return times;
|
||||||
}
|
}
|
||||||
|
|
||||||
metadatas.reserve(p_uuids.size());
|
ankerl::unordered_dense::map<UUID, eastl::vector<std::size_t>> uuidToIndices;
|
||||||
|
uuidToIndices.reserve(p_uuids.size());
|
||||||
if (p_uuids.size() == 1)
|
for (std::size_t i = 0; i < p_uuids.size(); ++i)
|
||||||
{
|
{
|
||||||
if (eastl::optional<AssetMetadata> metadata = GetAssetMetadata(p_uuids[0]); metadata.has_value())
|
uuidToIndices[p_uuids[i]].push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<UUID> distinctUUIDs;
|
||||||
|
distinctUUIDs.reserve(uuidToIndices.size());
|
||||||
|
for (const auto& [uuid, indices]: uuidToIndices)
|
||||||
|
{
|
||||||
|
distinctUUIDs.push_back(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::size_t PARAMS_PER_ROW = 1;
|
||||||
|
const std::size_t maxRowsPerStatement = static_cast<std::size_t>(
|
||||||
|
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
||||||
|
PARAMS_PER_ROW;
|
||||||
|
|
||||||
|
for (std::size_t chunkStart = 0; chunkStart < distinctUUIDs.size(); chunkStart += maxRowsPerStatement)
|
||||||
|
{
|
||||||
|
const std::size_t chunkSize = eastl::min(maxRowsPerStatement, distinctUUIDs.size() - chunkStart);
|
||||||
|
|
||||||
|
eastl::string placeholders;
|
||||||
|
placeholders.reserve(chunkSize * 2);
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
{
|
{
|
||||||
metadatas.push_back(std::move(*metadata));
|
if (i > 0)
|
||||||
|
{
|
||||||
|
placeholders += ", ";
|
||||||
|
}
|
||||||
|
placeholders += "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadatas;
|
const eastl::string sql = Format(
|
||||||
}
|
"SELECT UUID, CreateTime, ModificationTime FROM AssetMetadata WHERE UUID IN ({});",
|
||||||
|
placeholders);
|
||||||
|
|
||||||
eastl::vector<UUID> uniqueUUIDs {p_uuids.begin(), p_uuids.end()};
|
BigFile::Request timeRequest {*this, sql};
|
||||||
eastl::sort(uniqueUUIDs.begin(), uniqueUUIDs.end());
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
uniqueUUIDs.erase(eastl::unique(uniqueUUIDs.begin(), uniqueUUIDs.end()), uniqueUUIDs.end());
|
|
||||||
|
|
||||||
eastl::string placeholders;
|
|
||||||
placeholders.reserve(uniqueUUIDs.size() * 3);
|
|
||||||
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
{
|
{
|
||||||
placeholders += ", ";
|
timeRequest.Bind(static_cast<std::uint32_t>(i + 1), distinctUUIDs[chunkStart + i].ToBytes());
|
||||||
}
|
|
||||||
placeholders += "?";
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string sqlRequest = fmt::format("SELECT UUID, Name, TypeID, TypeName, CreateTime, ModificationTime "
|
|
||||||
"FROM AssetMetadata WHERE UUID IN ({});",
|
|
||||||
placeholders);
|
|
||||||
|
|
||||||
BigFile::Request assetRequest {*this, sqlRequest.c_str()};
|
|
||||||
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
|
||||||
{
|
|
||||||
assetRequest.Bind(static_cast<std::uint32_t>(i + 1), uniqueUUIDs[i].ToBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
metadatas.reserve(uniqueUUIDs.size());
|
|
||||||
for (std::size_t i = 0; i < uniqueUUIDs.size(); ++i)
|
|
||||||
{
|
|
||||||
if (!assetRequest.Step())
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
metadatas.push_back(
|
while (timeRequest.Step())
|
||||||
AssetMetadata {.m_uuid = UUID {std::span<const std::byte, UUID::UUID_BYTE_SIZE> {
|
{
|
||||||
static_cast<eastl::span<const std::byte>>(assetRequest.Get(0)).data(),
|
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawUUID {
|
||||||
UUID::UUID_BYTE_SIZE}},
|
static_cast<std::span<const std::byte>>(timeRequest.Get(0))};
|
||||||
.m_name = eastl::string {static_cast<eastl::string_view>(assetRequest.Get(1))},
|
const UUID uuid {rawUUID};
|
||||||
.m_typeID = assetRequest.Get(2),
|
|
||||||
.m_typeName = eastl::string {static_cast<eastl::string_view>(assetRequest.Get(3))},
|
const auto indicesIt = uuidToIndices.find(uuid);
|
||||||
.m_creationTime = Time {static_cast<std::uint64_t>(assetRequest.Get(4))},
|
ASSERT(EngineAssertHandler,
|
||||||
.m_modificationTime = Time {static_cast<std::uint64_t>(assetRequest.Get(5))}});
|
indicesIt != uuidToIndices.end(),
|
||||||
|
"Returned UUID {} not found in requested UUIDs",
|
||||||
|
uuid);
|
||||||
|
|
||||||
|
const AssetTime assetTime {.m_creationTime = Time {static_cast<std::uint64_t>(timeRequest.Get(1))},
|
||||||
|
.m_modificationTime = Time {static_cast<std::uint64_t>(timeRequest.Get(2))}};
|
||||||
|
|
||||||
|
for (const std::size_t index: indicesIt->second)
|
||||||
|
{
|
||||||
|
times[index] = assetTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadatas;
|
return times;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
void BigFile::SaveAssetFlatbuffer(const AssetMetadata& p_metadata, const eastl::span<const std::byte> p_flatbuffer)
|
void BigFile::SaveAssetFlatbuffer(const UUID& p_uuid,
|
||||||
|
const eastl::span<const std::byte> p_flatbuffer,
|
||||||
|
const eastl::span<const UUID> p_hardReferences)
|
||||||
{
|
{
|
||||||
BeginTransaction();
|
BeginTransaction();
|
||||||
|
|
||||||
BigFile::Request metadataRequest {
|
BigFile::Request metadataRequest {*this,
|
||||||
*this,
|
"INSERT INTO AssetMetadata (UUID) VALUES (?1) "
|
||||||
"INSERT INTO AssetMetadata (UUID, Name, TypeID, TypeName) VALUES (?1, ?2, ?3, ?4) "
|
"ON CONFLICT(UUID) DO NOTHING;"};
|
||||||
"ON CONFLICT(UUID) DO UPDATE SET Name = excluded.Name, TypeID = excluded.TypeID, TypeName = excluded.TypeName;"};
|
metadataRequest.Bind(1, p_uuid.ToBytes());
|
||||||
metadataRequest.Bind(1, p_metadata.m_uuid.ToBytes());
|
|
||||||
metadataRequest.Bind(2, p_metadata.m_name);
|
|
||||||
metadataRequest.Bind(3, p_metadata.m_typeID);
|
|
||||||
metadataRequest.Bind(4, p_metadata.m_typeName);
|
|
||||||
metadataRequest.Execute();
|
metadataRequest.Execute();
|
||||||
|
|
||||||
BigFile::Request assetRequest {*this,
|
BigFile::Request assetRequest {*this,
|
||||||
"INSERT INTO Asset (UUID, Asset) VALUES (?1, ?2) "
|
"INSERT INTO Asset (UUID, Asset) VALUES (?1, ?2) "
|
||||||
"ON CONFLICT(UUID) DO UPDATE SET Asset = excluded.Asset;"};
|
"ON CONFLICT(UUID) DO UPDATE SET Asset = excluded.Asset;"};
|
||||||
assetRequest.Bind(1, p_metadata.m_uuid.ToBytes());
|
assetRequest.Bind(1, p_uuid.ToBytes());
|
||||||
assetRequest.Bind(2, p_flatbuffer);
|
assetRequest.Bind(2, p_flatbuffer);
|
||||||
assetRequest.Execute();
|
assetRequest.Execute();
|
||||||
|
|
||||||
|
BigFile::Request deleteHardReferencesRequest {*this, "DELETE FROM AssetHardReference WHERE UUID = ?1;"};
|
||||||
|
deleteHardReferencesRequest.Bind(1, p_uuid.ToBytes());
|
||||||
|
deleteHardReferencesRequest.Execute();
|
||||||
|
|
||||||
|
constexpr std::size_t HARDREF_PARAMS_PER_ROW = 2;
|
||||||
|
constexpr std::size_t HARDREF_PLACEHOLDER_RESERVE_CHARS_PER_ROW = 8;
|
||||||
|
const std::size_t maxHardRefRowsPerStatement = static_cast<std::size_t>(
|
||||||
|
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
||||||
|
HARDREF_PARAMS_PER_ROW;
|
||||||
|
|
||||||
|
for (std::size_t chunkStart = 0; chunkStart < p_hardReferences.size(); chunkStart += maxHardRefRowsPerStatement)
|
||||||
|
{
|
||||||
|
const std::size_t chunkSize = eastl::min(maxHardRefRowsPerStatement, p_hardReferences.size() - chunkStart);
|
||||||
|
|
||||||
|
eastl::string hardReferencePlaceholders;
|
||||||
|
hardReferencePlaceholders.reserve(chunkSize * HARDREF_PLACEHOLDER_RESERVE_CHARS_PER_ROW);
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
hardReferencePlaceholders += ", ";
|
||||||
|
}
|
||||||
|
hardReferencePlaceholders += "(?, ?)";
|
||||||
|
}
|
||||||
|
|
||||||
|
const eastl::string hardReferenceSQL = Format("INSERT INTO AssetHardReference (UUID, HardReference) VALUES {} "
|
||||||
|
"ON CONFLICT(UUID, HardReference) DO NOTHING;",
|
||||||
|
hardReferencePlaceholders);
|
||||||
|
|
||||||
|
BigFile::Request hardReferenceRequest {*this, hardReferenceSQL};
|
||||||
|
std::uint32_t bindIndex = 1;
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
hardReferenceRequest.Bind(bindIndex++, p_uuid.ToBytes());
|
||||||
|
hardReferenceRequest.Bind(bindIndex++, p_hardReferences[chunkStart + i].ToBytes());
|
||||||
|
}
|
||||||
|
hardReferenceRequest.Execute();
|
||||||
|
}
|
||||||
|
|
||||||
CommitTransaction();
|
CommitTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
void BigFile::SaveAssetFlatbuffers(const eastl::span<const AssetMetadata> p_metadatas,
|
void BigFile::SaveAssetFlatbuffers(const eastl::span<const UUID> p_uuids,
|
||||||
const eastl::span<const eastl::vector<std::byte>> p_flatbuffers)
|
const eastl::span<const eastl::vector<std::byte>> p_flatbuffers,
|
||||||
|
const eastl::span<const eastl::vector<UUID>> p_hardReferences)
|
||||||
{
|
{
|
||||||
ASSERT(EngineAssertHandler,
|
ASSERT(EngineAssertHandler,
|
||||||
p_metadatas.size() == p_flatbuffers.size(),
|
p_uuids.size() == p_flatbuffers.size() && p_uuids.size() == p_hardReferences.size(),
|
||||||
"p_metadatas and p_flatbuffers must have the same size");
|
"p_metadatas and p_flatbuffers and p_hardReferences must have the same size");
|
||||||
|
|
||||||
if (p_metadatas.empty())
|
if (p_uuids.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -289,45 +456,41 @@ void BigFile::SaveAssetFlatbuffers(const eastl::span<const AssetMetadata> p_meta
|
|||||||
BeginTransaction();
|
BeginTransaction();
|
||||||
|
|
||||||
constexpr std::size_t METADATA_PARAMS_PER_ROW = 4;
|
constexpr std::size_t METADATA_PARAMS_PER_ROW = 4;
|
||||||
|
constexpr std::size_t METADATA_PLACEHOLDER_RESERVE_CHARS_PER_ROW = 14;
|
||||||
|
constexpr std::size_t ASSET_PLACEHOLDER_RESERVE_CHARS_PER_ROW = 8;
|
||||||
const std::size_t maxRowsPerStatement = static_cast<std::size_t>(
|
const std::size_t maxRowsPerStatement = static_cast<std::size_t>(
|
||||||
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
||||||
METADATA_PARAMS_PER_ROW;
|
METADATA_PARAMS_PER_ROW;
|
||||||
|
|
||||||
for (std::size_t chunkStart = 0; chunkStart < p_metadatas.size(); chunkStart += maxRowsPerStatement)
|
for (std::size_t chunkStart = 0; chunkStart < p_uuids.size(); chunkStart += maxRowsPerStatement)
|
||||||
{
|
{
|
||||||
const std::size_t chunkSize = eastl::min(maxRowsPerStatement, p_metadatas.size() - chunkStart);
|
const std::size_t chunkSize = eastl::min(maxRowsPerStatement, p_uuids.size() - chunkStart);
|
||||||
|
|
||||||
eastl::string metadataPlaceholders;
|
eastl::string metadataPlaceholders;
|
||||||
metadataPlaceholders.reserve(chunkSize * 14);
|
metadataPlaceholders.reserve(chunkSize * METADATA_PLACEHOLDER_RESERVE_CHARS_PER_ROW);
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
{
|
{
|
||||||
metadataPlaceholders += ", ";
|
metadataPlaceholders += ", ";
|
||||||
}
|
}
|
||||||
metadataPlaceholders += "(?, ?, ?, ?)";
|
metadataPlaceholders += "(?)";
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string metadataSQL = fmt::format(
|
const eastl::string metadataSQL = Format(
|
||||||
"INSERT INTO AssetMetadata (UUID, Name, TypeID, TypeName) VALUES {} "
|
"INSERT INTO AssetMetadata (UUID) VALUES {} ON CONFLICT(UUID) DO NOTHING;",
|
||||||
"ON CONFLICT(UUID) DO UPDATE SET Name = excluded.Name, TypeID = excluded.TypeID, TypeName = "
|
|
||||||
"excluded.TypeName;",
|
|
||||||
metadataPlaceholders);
|
metadataPlaceholders);
|
||||||
|
|
||||||
BigFile::Request metadataRequest {*this, metadataSQL.c_str()};
|
BigFile::Request metadataRequest {*this, metadataSQL};
|
||||||
std::uint32_t metadataBindIndex = 1;
|
std::uint32_t metadataBindIndex = 1;
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
{
|
{
|
||||||
const AssetMetadata& metadata = p_metadatas[chunkStart + i];
|
metadataRequest.Bind(metadataBindIndex++, p_uuids[chunkStart + i].ToBytes());
|
||||||
metadataRequest.Bind(metadataBindIndex++, metadata.m_uuid.ToBytes());
|
|
||||||
metadataRequest.Bind(metadataBindIndex++, metadata.m_name);
|
|
||||||
metadataRequest.Bind(metadataBindIndex++, metadata.m_typeID);
|
|
||||||
metadataRequest.Bind(metadataBindIndex++, metadata.m_typeName);
|
|
||||||
}
|
}
|
||||||
metadataRequest.Execute();
|
metadataRequest.Execute();
|
||||||
|
|
||||||
eastl::string assetPlaceholders;
|
eastl::string assetPlaceholders;
|
||||||
assetPlaceholders.reserve(chunkSize * 8);
|
assetPlaceholders.reserve(chunkSize * ASSET_PLACEHOLDER_RESERVE_CHARS_PER_ROW);
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
@@ -337,18 +500,88 @@ void BigFile::SaveAssetFlatbuffers(const eastl::span<const AssetMetadata> p_meta
|
|||||||
assetPlaceholders += "(?, ?)";
|
assetPlaceholders += "(?, ?)";
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string assetSQL = fmt::format(
|
const eastl::string assetSQL = Format(
|
||||||
"INSERT INTO Asset (UUID, Asset) VALUES {} ON CONFLICT(UUID) DO UPDATE SET Asset = excluded.Asset;",
|
"INSERT INTO Asset (UUID, Asset) VALUES {} ON CONFLICT(UUID) DO UPDATE SET Asset = excluded.Asset;",
|
||||||
assetPlaceholders);
|
assetPlaceholders);
|
||||||
|
|
||||||
BigFile::Request assetRequest {*this, assetSQL.c_str()};
|
BigFile::Request assetRequest {*this, assetSQL};
|
||||||
std::uint32_t assetBindIndex = 1;
|
std::uint32_t assetBindIndex = 1;
|
||||||
for (std::size_t i = 0; i < chunkSize; ++i)
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
{
|
{
|
||||||
assetRequest.Bind(assetBindIndex++, p_metadatas[chunkStart + i].m_uuid.ToBytes());
|
assetRequest.Bind(assetBindIndex++, p_uuids[chunkStart + i].ToBytes());
|
||||||
assetRequest.Bind(assetBindIndex++, p_flatbuffers[chunkStart + i]);
|
assetRequest.Bind(assetBindIndex++, p_flatbuffers[chunkStart + i]);
|
||||||
}
|
}
|
||||||
assetRequest.Execute();
|
assetRequest.Execute();
|
||||||
|
|
||||||
|
// Replace hard references for every asset in this chunk with its current set.
|
||||||
|
eastl::string deleteInPlaceholders;
|
||||||
|
deleteInPlaceholders.reserve(chunkSize * 3);
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
deleteInPlaceholders += ", ";
|
||||||
|
}
|
||||||
|
deleteInPlaceholders += "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
const eastl::string deleteHardReferencesSQL = Format("DELETE FROM AssetHardReference WHERE UUID IN ({});",
|
||||||
|
deleteInPlaceholders);
|
||||||
|
|
||||||
|
BigFile::Request deleteHardReferencesRequest {*this, deleteHardReferencesSQL};
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
deleteHardReferencesRequest.Bind(static_cast<std::uint32_t>(i + 1), p_uuids[chunkStart + i].ToBytes());
|
||||||
|
}
|
||||||
|
deleteHardReferencesRequest.Execute();
|
||||||
|
|
||||||
|
eastl::vector<eastl::pair<UUID, UUID>> hardReferencePairs;
|
||||||
|
for (std::size_t i = 0; i < chunkSize; ++i)
|
||||||
|
{
|
||||||
|
for (const UUID& hardReference: p_hardReferences[chunkStart + i])
|
||||||
|
{
|
||||||
|
hardReferencePairs.emplace_back(p_uuids[chunkStart + i], hardReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::size_t HARDREF_PARAMS_PER_ROW = 2;
|
||||||
|
constexpr std::size_t HARDREF_PLACEHOLDER_RESERVE_CHARS_PER_ROW = 8;
|
||||||
|
const std::size_t maxHardRefRowsPerStatement = static_cast<std::size_t>(
|
||||||
|
sqlite3_limit(m_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1)) /
|
||||||
|
HARDREF_PARAMS_PER_ROW;
|
||||||
|
|
||||||
|
for (std::size_t hardRefChunkStart = 0; hardRefChunkStart < hardReferencePairs.size();
|
||||||
|
hardRefChunkStart += maxHardRefRowsPerStatement)
|
||||||
|
{
|
||||||
|
const std::size_t hardRefChunkSize = eastl::min(maxHardRefRowsPerStatement,
|
||||||
|
hardReferencePairs.size() - hardRefChunkStart);
|
||||||
|
|
||||||
|
eastl::string hardReferencePlaceholders;
|
||||||
|
hardReferencePlaceholders.reserve(hardRefChunkSize * HARDREF_PLACEHOLDER_RESERVE_CHARS_PER_ROW);
|
||||||
|
for (std::size_t i = 0; i < hardRefChunkSize; ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
hardReferencePlaceholders += ", ";
|
||||||
|
}
|
||||||
|
hardReferencePlaceholders += "(?, ?)";
|
||||||
|
}
|
||||||
|
|
||||||
|
const eastl::string hardReferenceSQL = Format(
|
||||||
|
"INSERT INTO AssetHardReference (UUID, HardReference) VALUES {} "
|
||||||
|
"ON CONFLICT(UUID, HardReference) DO NOTHING;",
|
||||||
|
hardReferencePlaceholders);
|
||||||
|
|
||||||
|
BigFile::Request hardReferenceRequest {*this, hardReferenceSQL};
|
||||||
|
std::uint32_t bindIndex = 1;
|
||||||
|
for (std::size_t i = 0; i < hardRefChunkSize; ++i)
|
||||||
|
{
|
||||||
|
const auto& [assetUUID, hardReference] = hardReferencePairs[hardRefChunkStart + i];
|
||||||
|
hardReferenceRequest.Bind(bindIndex++, assetUUID.ToBytes());
|
||||||
|
hardReferenceRequest.Bind(bindIndex++, hardReference.ToBytes());
|
||||||
|
}
|
||||||
|
hardReferenceRequest.Execute();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CommitTransaction();
|
CommitTransaction();
|
||||||
@@ -372,7 +605,7 @@ BigFile::Request::Request(const BigFile& p_bigFile, const eastl::string_view p_r
|
|||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const int result = sqlite3_prepare_v2(m_db,
|
const int result = sqlite3_prepare_v2(m_db,
|
||||||
p_request.data(),
|
p_request.data(),
|
||||||
static_cast<std::uint32_t>(p_request.size()),
|
static_cast<int>(p_request.size()),
|
||||||
&m_statement,
|
&m_statement,
|
||||||
nullptr);
|
nullptr);
|
||||||
CRITICAL_ASSERT(EngineAssertHandler,
|
CRITICAL_ASSERT(EngineAssertHandler,
|
||||||
@@ -386,11 +619,11 @@ BigFile::Request::Request(const BigFile& p_bigFile, const eastl::string_view p_r
|
|||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const std::int32_t p_value)
|
void BigFile::Request::Bind(const std::uint32_t p_index, const std::int32_t p_value)
|
||||||
{
|
{
|
||||||
ASSERT(EngineAssertHandler,
|
ASSERT(EngineAssertHandler,
|
||||||
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
"Invalid index for statement");
|
"Invalid index for statement");
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const int result = sqlite3_bind_int(m_statement, p_index, p_value);
|
const int result = sqlite3_bind_int(m_statement, static_cast<int>(p_index), p_value);
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,11 +632,11 @@ void BigFile::Request::Bind(const std::uint32_t p_index, const std::int32_t p_va
|
|||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint32_t p_value)
|
void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint32_t p_value)
|
||||||
{
|
{
|
||||||
ASSERT(EngineAssertHandler,
|
ASSERT(EngineAssertHandler,
|
||||||
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
"Invalid index for statement");
|
"Invalid index for statement");
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const int result = sqlite3_bind_int(m_statement, p_index, p_value);
|
const int result = sqlite3_bind_int(m_statement, static_cast<int>(p_index), static_cast<int>(p_value));
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,11 +645,11 @@ void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint32_t p_v
|
|||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const std::int64_t p_value)
|
void BigFile::Request::Bind(const std::uint32_t p_index, const std::int64_t p_value)
|
||||||
{
|
{
|
||||||
ASSERT(EngineAssertHandler,
|
ASSERT(EngineAssertHandler,
|
||||||
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
"Invalid index for statement");
|
"Invalid index for statement");
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const int result = sqlite3_bind_int64(m_statement, p_index, p_value);
|
const int result = sqlite3_bind_int64(m_statement, static_cast<int>(p_index), p_value);
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,11 +658,11 @@ void BigFile::Request::Bind(const std::uint32_t p_index, const std::int64_t p_va
|
|||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint64_t p_value)
|
void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint64_t p_value)
|
||||||
{
|
{
|
||||||
ASSERT(EngineAssertHandler,
|
ASSERT(EngineAssertHandler,
|
||||||
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
"Invalid index for statement");
|
"Invalid index for statement");
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const int result = sqlite3_bind_int64(m_statement, p_index, std::bit_cast<std::int64_t>(p_value));
|
const int result = sqlite3_bind_int64(m_statement, static_cast<int>(p_index), std::bit_cast<std::int64_t>(p_value));
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,11 +671,11 @@ void BigFile::Request::Bind(const std::uint32_t p_index, const std::uint64_t p_v
|
|||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const float p_value)
|
void BigFile::Request::Bind(const std::uint32_t p_index, const float p_value)
|
||||||
{
|
{
|
||||||
ASSERT(EngineAssertHandler,
|
ASSERT(EngineAssertHandler,
|
||||||
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
"Invalid index for statement");
|
"Invalid index for statement");
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const int result = sqlite3_bind_double(m_statement, p_index, p_value);
|
const int result = sqlite3_bind_double(m_statement, static_cast<int>(p_index), p_value);
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,11 +684,11 @@ void BigFile::Request::Bind(const std::uint32_t p_index, const float p_value)
|
|||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const double p_value)
|
void BigFile::Request::Bind(const std::uint32_t p_index, const double p_value)
|
||||||
{
|
{
|
||||||
ASSERT(EngineAssertHandler,
|
ASSERT(EngineAssertHandler,
|
||||||
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
"Invalid index for statement");
|
"Invalid index for statement");
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const int result = sqlite3_bind_double(m_statement, p_index, p_value);
|
const int result = sqlite3_bind_double(m_statement, static_cast<int>(p_index), p_value);
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,14 +697,14 @@ void BigFile::Request::Bind(const std::uint32_t p_index, const double p_value)
|
|||||||
void BigFile::Request::Bind(const std::uint32_t p_index, const eastl::string_view p_value, const CopyValue p_copy)
|
void BigFile::Request::Bind(const std::uint32_t p_index, const eastl::string_view p_value, const CopyValue p_copy)
|
||||||
{
|
{
|
||||||
ASSERT(EngineAssertHandler,
|
ASSERT(EngineAssertHandler,
|
||||||
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
"Invalid index for statement");
|
"Invalid index for statement");
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const int result = sqlite3_bind_text(m_statement,
|
const int result = sqlite3_bind_text(m_statement,
|
||||||
p_index,
|
static_cast<int>(p_index),
|
||||||
p_value.data(),
|
p_value.data(),
|
||||||
static_cast<std::uint32_t>(p_value.size()),
|
static_cast<int>(p_value.size()),
|
||||||
p_copy ? SQLITE_TRANSIENT : SQLITE_STATIC);
|
p_copy ? SQLITE_TRANSIENT : SQLITE_STATIC);
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
}
|
}
|
||||||
@@ -483,14 +716,14 @@ void BigFile::Request::Bind(const std::uint32_t p_index,
|
|||||||
const CopyValue p_copy)
|
const CopyValue p_copy)
|
||||||
{
|
{
|
||||||
ASSERT(EngineAssertHandler,
|
ASSERT(EngineAssertHandler,
|
||||||
(p_index >= 1) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
(p_index >= 1U) && (p_index <= static_cast<std::uint32_t>(sqlite3_bind_parameter_count(m_statement))),
|
||||||
"Invalid index for statement");
|
"Invalid index for statement");
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const int result = sqlite3_bind_blob(m_statement,
|
const int result = sqlite3_bind_blob(m_statement,
|
||||||
p_index,
|
static_cast<int>(p_index),
|
||||||
p_value.data(),
|
p_value.data(),
|
||||||
static_cast<std::uint32_t>(p_value.size()),
|
static_cast<int>(p_value.size()),
|
||||||
p_copy ? SQLITE_TRANSIENT : SQLITE_STATIC);
|
p_copy ? SQLITE_TRANSIENT : SQLITE_STATIC);
|
||||||
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
ASSERT(EngineAssertHandler, result == SQLITE_OK, "Failed to bind value for statement: {}", sqlite3_errmsg(m_db));
|
||||||
}
|
}
|
||||||
@@ -531,58 +764,69 @@ BigFile::Request::Column::Column(const Request& p_request, const std::uint32_t p
|
|||||||
|
|
||||||
BigFile::Request::Column::operator std::int32_t() const
|
BigFile::Request::Column::operator std::int32_t() const
|
||||||
{
|
{
|
||||||
return sqlite3_column_int(m_statement, m_index);
|
return sqlite3_column_int(m_statement, static_cast<int>(m_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BigFile::Request::Column::operator std::uint32_t() const
|
BigFile::Request::Column::operator std::uint32_t() const
|
||||||
{
|
{
|
||||||
return sqlite3_column_int(m_statement, m_index);
|
return sqlite3_column_int(m_statement, static_cast<int>(m_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BigFile::Request::Column::operator std::int64_t() const
|
BigFile::Request::Column::operator std::int64_t() const
|
||||||
{
|
{
|
||||||
return sqlite3_column_int64(m_statement, m_index);
|
return sqlite3_column_int64(m_statement, static_cast<int>(m_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BigFile::Request::Column::operator std::uint64_t() const
|
BigFile::Request::Column::operator std::uint64_t() const
|
||||||
{
|
{
|
||||||
return std::bit_cast<std::uint64_t>(sqlite3_column_int64(m_statement, m_index));
|
return std::bit_cast<std::uint64_t>(sqlite3_column_int64(m_statement, static_cast<int>(m_index)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BigFile::Request::Column::operator float() const
|
BigFile::Request::Column::operator float() const
|
||||||
{
|
{
|
||||||
return static_cast<float>(sqlite3_column_double(m_statement, m_index));
|
return static_cast<float>(sqlite3_column_double(m_statement, static_cast<int>(m_index)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BigFile::Request::Column::operator double() const
|
BigFile::Request::Column::operator double() const
|
||||||
{
|
{
|
||||||
return sqlite3_column_double(m_statement, m_index);
|
return sqlite3_column_double(m_statement, static_cast<int>(m_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BigFile::Request::Column::operator eastl::string_view() const
|
BigFile::Request::Column::operator eastl::string_view() const
|
||||||
{
|
{
|
||||||
return eastl::string_view {reinterpret_cast<const char*>(sqlite3_column_text(m_statement, m_index)),
|
return eastl::string_view {
|
||||||
static_cast<std::size_t>(sqlite3_column_bytes(m_statement, m_index))};
|
reinterpret_cast<const char*>(sqlite3_column_text(m_statement, static_cast<int>(m_index))),
|
||||||
|
static_cast<std::size_t>(sqlite3_column_bytes(m_statement, static_cast<int>(m_index)))};
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
BigFile::Request::Column::operator eastl::span<const std::byte>() const
|
BigFile::Request::Column::operator eastl::span<const std::byte>() const
|
||||||
{
|
{
|
||||||
return eastl::span<const std::byte> {static_cast<const std::byte*>(sqlite3_column_blob(m_statement, m_index)),
|
return eastl::span<const std::byte> {
|
||||||
static_cast<std::size_t>(sqlite3_column_bytes(m_statement, m_index))};
|
static_cast<const std::byte*>(sqlite3_column_blob(m_statement, static_cast<int>(m_index))),
|
||||||
|
static_cast<std::size_t>(sqlite3_column_bytes(m_statement, static_cast<int>(m_index)))};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
BigFile::Request::Column::operator std::span<const std::byte>() const
|
||||||
|
{
|
||||||
|
return std::span<const std::byte> {
|
||||||
|
static_cast<const std::byte*>(sqlite3_column_blob(m_statement, static_cast<int>(m_index))),
|
||||||
|
static_cast<std::size_t>(sqlite3_column_bytes(m_statement, static_cast<int>(m_index)))};
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|||||||
@@ -1,27 +1,16 @@
|
|||||||
PRAGMA journal_mode=WAL;
|
PRAGMA journal_mode=WAL;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS AssetMetadata (
|
CREATE TABLE IF NOT EXISTS AssetMetadata (
|
||||||
UUID BLOB NOT NULL,
|
UUID BLOB NOT NULL,
|
||||||
Name TEXT NOT NULL UNIQUE,
|
|
||||||
TypeID INTEGER NOT NULL,
|
|
||||||
TypeName TEXT NOT NULL,
|
|
||||||
|
|
||||||
CreateTime INTEGER NOT NULL DEFAULT(CAST(unixepoch('subsec') * 1000000 AS INTEGER)),
|
CreateTime INTEGER NOT NULL DEFAULT(CAST(unixepoch('subsec') * 1000000 AS INTEGER)),
|
||||||
ModificationTime INTEGER NOT NULL DEFAULT(CAST(unixepoch('subsec') * 1000000 AS INTEGER)),
|
ModificationTime INTEGER NOT NULL DEFAULT(CAST(unixepoch('subsec') * 1000000 AS INTEGER)),
|
||||||
|
|
||||||
PRIMARY KEY(UUID)
|
PRIMARY KEY(UUID)
|
||||||
) WITHOUT ROWID;
|
) WITHOUT ROWID;
|
||||||
|
|
||||||
CREATE TRIGGER IF NOT EXISTS AssetMetadata_UpdateTime
|
|
||||||
AFTER UPDATE OF Name, TypeID, TypeName ON AssetMetadata FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
UPDATE AssetMetadata
|
|
||||||
SET ModificationTime = CAST(unixepoch('subsec') * 1000000 AS INTEGER)
|
|
||||||
WHERE UUID = NEW.UUID;
|
|
||||||
END;
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS Asset (
|
CREATE TABLE IF NOT EXISTS Asset (
|
||||||
UUID BLOB NOT NULL,
|
UUID BLOB NOT NULL,
|
||||||
|
|
||||||
Asset BLOB NOT NULL,
|
Asset BLOB NOT NULL,
|
||||||
|
|
||||||
@@ -36,3 +25,14 @@ BEGIN
|
|||||||
SET ModificationTime = CAST(unixepoch('subsec') * 1000000 AS INTEGER)
|
SET ModificationTime = CAST(unixepoch('subsec') * 1000000 AS INTEGER)
|
||||||
WHERE UUID = NEW.UUID;
|
WHERE UUID = NEW.UUID;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS AssetHardReference (
|
||||||
|
UUID BLOB NOT NULL,
|
||||||
|
HardReference BLOB NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY(UUID, HardReference),
|
||||||
|
FOREIGN KEY(UUID) REFERENCES AssetMetadata(UUID)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS AssetHardReference_ReferencedUUID ON AssetHardReference(HardReference);
|
||||||
@@ -10,7 +10,6 @@ table AssetHeader
|
|||||||
name: string (required, id: 1);
|
name: string (required, id: 1);
|
||||||
type_id: AssetTypeID (required, native_inline, id: 2);
|
type_id: AssetTypeID (required, native_inline, id: 2);
|
||||||
type_name: string (required, id: 3);
|
type_name: string (required, id: 3);
|
||||||
version: uint = 0 (id: 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table Asset
|
table Asset
|
||||||
|
|||||||
@@ -6,39 +6,27 @@
|
|||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#ifndef BIGFOOT_ENGINE_ASSET_ASSET_HPP
|
#ifndef BIGFOOT_ENGINE_ASSET_ASSET_HPP
|
||||||
#define BIGFOOT_ENGINE_ASSET_ASSET_HPP
|
#define BIGFOOT_ENGINE_ASSET_ASSET_HPP
|
||||||
|
#include <Engine/Asset/AssetBase.hpp>
|
||||||
#include <Engine/Asset/AssetConcepts.hpp>
|
#include <Engine/Asset/AssetConcepts.hpp>
|
||||||
|
#include <Engine/Asset/AssetContainer.hpp>
|
||||||
|
#include <Engine/Asset/AssetLibrary.hpp>
|
||||||
#include <Engine/Asset/Asset_generated.hpp>
|
#include <Engine/Asset/Asset_generated.hpp>
|
||||||
#include <Engine/EngineAssertHandler.hpp>
|
#include <Engine/EngineAssertHandler.hpp>
|
||||||
|
|
||||||
#include <EASTL/span.h>
|
#include <EASTL/span.h>
|
||||||
#include <EASTL/vector.h>
|
#include <EASTL/vector.h>
|
||||||
#include <ankerl/unordered_dense.h>
|
#include <ankerl/unordered_dense.h>
|
||||||
#include <flatbuffers/reflection.h>
|
#include <flatbuffers/minireflect.h>
|
||||||
#include <rapidhash.h>
|
#include <rapidhash.h>
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
class AssetBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~AssetBase() = default;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
AssetBase() = default;
|
|
||||||
|
|
||||||
AssetBase(const AssetBase& p_asset) = delete;
|
|
||||||
AssetBase(AssetBase&& p_asset) = default;
|
|
||||||
|
|
||||||
AssetBase& operator=(const AssetBase& p_asset) = delete;
|
|
||||||
AssetBase& operator=(AssetBase&& p_asset) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class ASSET>
|
template<class ASSET>
|
||||||
requires AssetTraits<ASSET>
|
requires AssetTraits<ASSET>
|
||||||
class Asset: public AssetBase
|
class Asset: public AssetBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using FLAT_ASSET = typename ASSET::FLAT;
|
using FLAT_ASSET = ASSET::FLAT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@@ -58,7 +46,7 @@ class Asset: public AssetBase
|
|||||||
* \return The header of the asset
|
* \return The header of the asset
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const ::Flat::Bigfoot::AssetHeaderT& GetHeader() const
|
const ::Flat::Bigfoot::AssetHeaderT& GetHeader() const override
|
||||||
{
|
{
|
||||||
return m_header;
|
return m_header;
|
||||||
}
|
}
|
||||||
@@ -73,23 +61,13 @@ class Asset: public AssetBase
|
|||||||
m_header.name = p_name;
|
m_header.name = p_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the version of the asset
|
|
||||||
*
|
|
||||||
* \param p_name The version of the asset
|
|
||||||
*/
|
|
||||||
void SetVersion(const std::uint32_t p_version)
|
|
||||||
{
|
|
||||||
m_header.version = p_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the asset
|
* Get the asset
|
||||||
*
|
*
|
||||||
* \return The asset
|
* \return The asset
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const typename FLAT_ASSET::NativeTableType& GetAsset() const
|
const FLAT_ASSET::NativeTableType& GetAsset() const
|
||||||
{
|
{
|
||||||
return m_asset;
|
return m_asset;
|
||||||
}
|
}
|
||||||
@@ -100,7 +78,7 @@ class Asset: public AssetBase
|
|||||||
* \return The asset
|
* \return The asset
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
typename FLAT_ASSET::NativeTableType& GetAsset()
|
FLAT_ASSET::NativeTableType& GetAsset()
|
||||||
{
|
{
|
||||||
return m_asset;
|
return m_asset;
|
||||||
}
|
}
|
||||||
@@ -110,20 +88,21 @@ class Asset: public AssetBase
|
|||||||
*
|
*
|
||||||
* \param p_flatbuffer The flatbuffer to unpack
|
* \param p_flatbuffer The flatbuffer to unpack
|
||||||
*/
|
*/
|
||||||
void Unpack(const eastl::span<const std::byte> p_flatbuffer)
|
void Unpack(const eastl::span<const std::byte> p_flatbuffer) override
|
||||||
{
|
{
|
||||||
#ifdef BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
flatbuffers::Verifier verifier {std::bit_cast<std::uint8_t*>(p_flatbuffer.data()), p_flatbuffer.size()};
|
flatbuffers::Verifier verifier {reinterpret_cast<const std::uint8_t*>(p_flatbuffer.data()),
|
||||||
|
p_flatbuffer.size()};
|
||||||
const bool assetVerified = ::Flat::Bigfoot::VerifyAssetBuffer(verifier);
|
const bool assetVerified = ::Flat::Bigfoot::VerifyAssetBuffer(verifier);
|
||||||
CRITICAL_ASSERT(EngineAssertHandler, assetVerified, "Given asset could not be verified!");
|
CRITICAL_ASSERT(EngineAssertHandler, assetVerified, "Given asset could not be verified!");
|
||||||
|
#endif
|
||||||
|
|
||||||
const ::Flat::Bigfoot::Asset* asset = flatbuffers::GetRoot<::Flat::Bigfoot::Asset>(p_flatbuffer.data());
|
const ::Flat::Bigfoot::Asset* asset = flatbuffers::GetRoot<::Flat::Bigfoot::Asset>(p_flatbuffer.data());
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
flatbuffers::Verifier innerAssetVerifier {asset->inner_asset()->data(), asset->inner_asset()->size()};
|
flatbuffers::Verifier innerAssetVerifier {asset->inner_asset()->data(), asset->inner_asset()->size()};
|
||||||
const bool innerAssetVerified = innerAssetVerifier.VerifyBuffer<FLAT_ASSET>();
|
const bool innerAssetVerified = innerAssetVerifier.VerifyBuffer<FLAT_ASSET>();
|
||||||
CRITICAL_ASSERT(EngineAssertHandler, innerAssetVerified, "Given asset could not be verified!");
|
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
|
#endif
|
||||||
|
|
||||||
asset->header()->UnPackTo(&m_header);
|
asset->header()->UnPackTo(&m_header);
|
||||||
@@ -136,7 +115,7 @@ class Asset: public AssetBase
|
|||||||
* \return The packed asset
|
* \return The packed asset
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
eastl::vector<std::byte> Pack() const
|
eastl::vector<std::byte> Pack() const override
|
||||||
{
|
{
|
||||||
flatbuffers::FlatBufferBuilder innerAssetFbb;
|
flatbuffers::FlatBufferBuilder innerAssetFbb;
|
||||||
innerAssetFbb.Finish(FLAT_ASSET::Pack(innerAssetFbb, &m_asset));
|
innerAssetFbb.Finish(FLAT_ASSET::Pack(innerAssetFbb, &m_asset));
|
||||||
@@ -146,8 +125,39 @@ class Asset: public AssetBase
|
|||||||
const auto innerAsset = assetFbb.CreateVector(innerAssetFbb.GetBufferPointer(), innerAssetFbb.GetSize());
|
const auto innerAsset = assetFbb.CreateVector(innerAssetFbb.GetBufferPointer(), innerAssetFbb.GetSize());
|
||||||
assetFbb.Finish(::Flat::Bigfoot::CreateAsset(assetFbb, header, innerAsset));
|
assetFbb.Finish(::Flat::Bigfoot::CreateAsset(assetFbb, header, innerAsset));
|
||||||
|
|
||||||
return eastl::vector<std::byte> {std::bit_cast<std::byte*>(assetFbb.GetBufferPointer()),
|
return eastl::vector<std::byte> {
|
||||||
std::bit_cast<std::byte*>(assetFbb.GetBufferPointer() + assetFbb.GetSize())};
|
reinterpret_cast<std::byte*>(assetFbb.GetBufferPointer()),
|
||||||
|
reinterpret_cast<std::byte*>(assetFbb.GetBufferPointer() + assetFbb.GetSize())};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the HardReferences the flatbuffer has
|
||||||
|
*
|
||||||
|
* \param p_flatbuffer The flatbuffer
|
||||||
|
* \return The UUIDs of the HardReferences
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<UUID> GetHardReferences(const eastl::span<const std::byte> p_flatbuffer) const override
|
||||||
|
{
|
||||||
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
flatbuffers::Verifier verifier {reinterpret_cast<const std::uint8_t*>(p_flatbuffer.data()),
|
||||||
|
p_flatbuffer.size()};
|
||||||
|
const bool assetVerified = ::Flat::Bigfoot::VerifyAssetBuffer(verifier);
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler, assetVerified, "Given asset could not be verified!");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const ::Flat::Bigfoot::Asset* asset = flatbuffers::GetRoot<::Flat::Bigfoot::Asset>(p_flatbuffer.data());
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
flatbuffers::Verifier innerAssetVerifier {asset->inner_asset()->data(), asset->inner_asset()->size()};
|
||||||
|
const bool innerAssetVerified = innerAssetVerifier.VerifyBuffer<FLAT_ASSET>();
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler, innerAssetVerified, "Given asset could not be verified!");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HardReferenceVisitor visitor;
|
||||||
|
|
||||||
|
flatbuffers::IterateFlatBuffer(asset->inner_asset()->data(), FLAT_ASSET::MiniReflectTypeTable(), &visitor);
|
||||||
|
return visitor.GetUUIDs();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,12 +188,30 @@ class Asset: public AssetBase
|
|||||||
/**
|
/**
|
||||||
* The asset
|
* The asset
|
||||||
*/
|
*/
|
||||||
typename FLAT_ASSET::NativeTableType m_asset;
|
FLAT_ASSET::NativeTableType m_asset;
|
||||||
/**
|
/**
|
||||||
* The asset header
|
* The asset header
|
||||||
*/
|
*/
|
||||||
::Flat::Bigfoot::AssetHeaderT m_header;
|
::Flat::Bigfoot::AssetHeaderT m_header;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an asset and insert it into its corresponding AssetContainer
|
||||||
|
*
|
||||||
|
* \tparam ASSET The Asset type
|
||||||
|
* \return The created asset, nullptr if no AssetContainer is registered for ASSET
|
||||||
|
*/
|
||||||
|
template<class ASSET>
|
||||||
|
requires AssetType<ASSET>
|
||||||
|
[[nodiscard]]
|
||||||
|
ASSET* CreateAsset()
|
||||||
|
{
|
||||||
|
AssetContainerBase* container = g_activeAssetLibrary->GetAssetContainer(ASSET::GetTypeID());
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler, container != nullptr, "No AssetContainer registered for this asset type!");
|
||||||
|
|
||||||
|
ContainerHandle* handle = container->Insert();
|
||||||
|
return static_cast<ASSET*>(handle->GetAsset());
|
||||||
|
}
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file AssetBase.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date April 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_ENGINE_ASSET_ASSETBASE_HPP
|
||||||
|
#define BIGFOOT_ENGINE_ASSET_ASSETBASE_HPP
|
||||||
|
#include <Engine/Asset/Asset_generated.hpp>
|
||||||
|
|
||||||
|
#include <System/UUID/UUID.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/span.h>
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
#include <ankerl/unordered_dense.h>
|
||||||
|
#include <flatbuffers/minireflect.h>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
class AssetBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~AssetBase() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the header of the asset
|
||||||
|
*
|
||||||
|
* \return The header of the asset
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual const ::Flat::Bigfoot::AssetHeaderT& GetHeader() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the HardReferences the flatbuffer has
|
||||||
|
*
|
||||||
|
* \param p_flatbuffer The flatbuffer
|
||||||
|
* \return The UUIDs of the HardReferences
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual eastl::vector<UUID> GetHardReferences(const eastl::span<const std::byte> p_flatbuffer) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpack a flatbuffer to the asset
|
||||||
|
*
|
||||||
|
* \param p_flatbuffer The flatbuffer to unpack
|
||||||
|
*/
|
||||||
|
virtual void Unpack(const eastl::span<const std::byte> p_flatbuffer) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pack the asset to a flatbuffer
|
||||||
|
*
|
||||||
|
* \return The packed asset
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual eastl::vector<std::byte> Pack() const = 0;
|
||||||
|
|
||||||
|
AssetBase(const AssetBase& p_asset) = delete;
|
||||||
|
AssetBase& operator=(const AssetBase& p_asset) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AssetBase() = default;
|
||||||
|
|
||||||
|
AssetBase(AssetBase&& p_asset) = default;
|
||||||
|
|
||||||
|
AssetBase& operator=(AssetBase&& p_asset) = default;
|
||||||
|
|
||||||
|
class HardReferenceVisitor: public flatbuffers::IterationVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Field(size_t p_fieldIndex,
|
||||||
|
size_t p_setIndex,
|
||||||
|
const flatbuffers::ElementaryType p_type,
|
||||||
|
const bool p_isVector,
|
||||||
|
const flatbuffers::TypeTable* p_typeTable,
|
||||||
|
const char* p_name,
|
||||||
|
const std::uint8_t* p_val) override;
|
||||||
|
|
||||||
|
void Element(size_t p_index,
|
||||||
|
const flatbuffers::ElementaryType p_type,
|
||||||
|
const flatbuffers::TypeTable* p_typeTable,
|
||||||
|
const std::uint8_t* p_val) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the visited HardReference
|
||||||
|
*
|
||||||
|
* \return The visited HardReferences
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<UUID> GetUUIDs() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Visit an element in the flatbuffer
|
||||||
|
*
|
||||||
|
* \param p_type The element type
|
||||||
|
* \param p_typeTable The element typetable
|
||||||
|
* \param p_val The element
|
||||||
|
*/
|
||||||
|
void Visit(const flatbuffers::ElementaryType p_type,
|
||||||
|
const flatbuffers::TypeTable* p_typeTable,
|
||||||
|
const std::uint8_t* p_val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HardReferences visited so far
|
||||||
|
*/
|
||||||
|
ankerl::unordered_dense::set<UUID> m_uuids;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include <System/UUID/UUID.hpp>
|
#include <System/UUID/UUID.hpp>
|
||||||
|
|
||||||
|
#include <flatbuffers/minireflect.h>
|
||||||
|
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
@@ -25,6 +27,7 @@ concept AssetTraits = requires {
|
|||||||
typename TRAITS::FLAT;
|
typename TRAITS::FLAT;
|
||||||
typename TRAITS::FLAT::NativeTableType;
|
typename TRAITS::FLAT::NativeTableType;
|
||||||
{ TRAITS::FLAT::GetFullyQualifiedName() } -> std::convertible_to<const char*>;
|
{ TRAITS::FLAT::GetFullyQualifiedName() } -> std::convertible_to<const char*>;
|
||||||
|
{ TRAITS::FLAT::MiniReflectTypeTable() } -> std::convertible_to<const flatbuffers::TypeTable*>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#ifndef BIGFOOT_ENGINE_ASSET_ASSETCONTAINER_HPP
|
#ifndef BIGFOOT_ENGINE_ASSET_ASSETCONTAINER_HPP
|
||||||
#define BIGFOOT_ENGINE_ASSET_ASSETCONTAINER_HPP
|
#define BIGFOOT_ENGINE_ASSET_ASSETCONTAINER_HPP
|
||||||
#include <Engine/Asset/Asset.hpp>
|
#include <Engine/Asset/AssetBase.hpp>
|
||||||
#include <Engine/Asset/AssetConcepts.hpp>
|
#include <Engine/Asset/AssetConcepts.hpp>
|
||||||
#include <Engine/EngineAssertHandler.hpp>
|
#include <Engine/EngineAssertHandler.hpp>
|
||||||
|
|
||||||
@@ -18,40 +18,41 @@
|
|||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
|
class AssetContainerBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An indirection that allows References to immediately get the asset, without fetching the actual container
|
* An indirection that allows References to immediately get the asset, without fetching the actual container
|
||||||
*/
|
*/
|
||||||
class ContainerHandle
|
class ContainerHandle
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* \param p_assetContainer The originating assetcontainer
|
||||||
|
* \param p_uuid The UUID of tha asset
|
||||||
|
*/
|
||||||
|
ContainerHandle(AssetContainerBase* p_assetContainer, const UUID p_uuid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the HardRef count
|
* Get the HardRef count
|
||||||
*
|
*
|
||||||
* \return The HardRef count.
|
* \return The HardRef count.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::uint32_t GetHardRefCount() const
|
std::uint32_t GetHardRefCount() const;
|
||||||
{
|
|
||||||
return m_hardRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Increment the HardRef count
|
* Increment the HardRef count
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void IncrementHardRefCount()
|
void IncrementHardRefCount();
|
||||||
{
|
|
||||||
++m_hardRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decrement the HardRef count
|
* Decrement the HardRef count
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void DecrementHardRefCount()
|
void DecrementHardRefCount();
|
||||||
{
|
|
||||||
--m_hardRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the SoftRef count
|
* Get the SoftRef count
|
||||||
@@ -59,28 +60,19 @@ class ContainerHandle
|
|||||||
* \return The SoftRef count.
|
* \return The SoftRef count.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::uint32_t GetSoftRefCount() const
|
std::uint32_t GetSoftRefCount() const;
|
||||||
{
|
|
||||||
return m_softRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Increment the SoftRef count
|
* Increment the SoftRef count
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void IncrementSoftRefCount()
|
void IncrementSoftRefCount();
|
||||||
{
|
|
||||||
++m_softRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decrement the SoftRef count
|
* Decrement the SoftRef count
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void DecrementSoftRefCount()
|
void DecrementSoftRefCount();
|
||||||
{
|
|
||||||
--m_softRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the Asset
|
* Get the Asset
|
||||||
@@ -88,10 +80,7 @@ class ContainerHandle
|
|||||||
* \return The asset, can be nullptr
|
* \return The asset, can be nullptr
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
AssetBase* GetAsset()
|
AssetBase* GetAsset();
|
||||||
{
|
|
||||||
return m_asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the Asset
|
* Get the Asset
|
||||||
@@ -99,20 +88,14 @@ class ContainerHandle
|
|||||||
* \return The asset
|
* \return The asset
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const AssetBase* GetAsset() const
|
const AssetBase* GetAsset() const;
|
||||||
{
|
|
||||||
return m_asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the asset
|
* Set the asset
|
||||||
*
|
*
|
||||||
* \param p_asset The asset
|
* \param p_asset The asset
|
||||||
*/
|
*/
|
||||||
void SetAsset(AssetBase* p_asset)
|
void SetAsset(AssetBase* p_asset);
|
||||||
{
|
|
||||||
m_asset = p_asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
@@ -129,6 +112,16 @@ class ContainerHandle
|
|||||||
* The asset
|
* The asset
|
||||||
*/
|
*/
|
||||||
AssetBase* m_asset = nullptr;
|
AssetBase* m_asset = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The asset container
|
||||||
|
*/
|
||||||
|
AssetContainerBase* m_assetContainer = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UUID of the asset
|
||||||
|
*/
|
||||||
|
UUID m_uuid = UUID::NULL_UUID;
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
@@ -141,6 +134,23 @@ class AssetContainerBase
|
|||||||
public:
|
public:
|
||||||
virtual ~AssetContainerBase() = default;
|
virtual ~AssetContainerBase() = default;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inserts an Asset to the AssetContainer
|
||||||
|
*
|
||||||
|
* \param p_flatbuffer The flatbuffer to unpack to the asset
|
||||||
|
* \return The handle of the inserted asset
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual ContainerHandle* Insert(const eastl::span<const std::byte> p_flatbuffer) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inserts an Asset to the AssetContainer
|
||||||
|
*
|
||||||
|
* \return The handle of the inserted asset
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual ContainerHandle* Insert() = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if an Asset is in the AssetContainer or not
|
* Check if an Asset is in the AssetContainer or not
|
||||||
*
|
*
|
||||||
@@ -148,11 +158,7 @@ class AssetContainerBase
|
|||||||
* \return True if in AssetContainer, false otherwise
|
* \return True if in AssetContainer, false otherwise
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool Has(const UUID& p_uuid) const
|
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
|
* Acquires a ContainerHandle for a given UUID
|
||||||
@@ -162,27 +168,44 @@ class AssetContainerBase
|
|||||||
* \return A ContainerHandle for the UUID
|
* \return A ContainerHandle for the UUID
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ContainerHandle* AcquireContainerHandle(const UUID& p_uuid)
|
ContainerHandle* AcquireContainerHandle(const UUID& p_uuid);
|
||||||
{
|
|
||||||
return GetOrCreateEntry(p_uuid).m_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove an Asset from the AssetContainer
|
* Remove an Asset from the AssetContainer
|
||||||
*
|
*
|
||||||
* \param p_uuid The UUID to remove
|
* \param p_uuid The UUID to remove
|
||||||
*/
|
*/
|
||||||
virtual void Remove(const UUID& p_uuid)
|
void Remove(const UUID& p_uuid);
|
||||||
{
|
|
||||||
if (Entry* entry = FindEntry(p_uuid); entry != nullptr)
|
|
||||||
{
|
|
||||||
m_handles.Remove(entry->m_handleSlotKey);
|
|
||||||
m_uuidToEntry.erase(p_uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an asset to be removed
|
||||||
|
*
|
||||||
|
* \param p_uuid UUID of the asset to remove
|
||||||
|
*/
|
||||||
|
void QueueForRemoval(const UUID& p_uuid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an asset from the pending remove queue
|
||||||
|
*
|
||||||
|
* \param p_uuid UUID of the asset to cancel removal
|
||||||
|
*/
|
||||||
|
void CancelRemoval(const UUID& p_uuid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the assets that have been marked for remove
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ProcessPendingRemovals();
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool IsMarkedForRemove(const UUID& p_uuid);
|
||||||
|
|
||||||
|
AssetContainerBase& operator=(const AssetContainerBase& p_container) = delete;
|
||||||
AssetContainerBase& operator=(AssetContainerBase&& p_container) = delete;
|
AssetContainerBase& operator=(AssetContainerBase&& p_container) = delete;
|
||||||
|
|
||||||
|
AssetContainerBase(const AssetContainerBase& p_container) = delete;
|
||||||
|
AssetContainerBase(AssetContainerBase&& p_container) = delete;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
@@ -204,7 +227,14 @@ class AssetContainerBase
|
|||||||
|
|
||||||
AssetContainerBase() = default;
|
AssetContainerBase() = default;
|
||||||
|
|
||||||
AssetContainerBase(AssetContainerBase&& p_container) = delete;
|
/*
|
||||||
|
* 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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds an entry matching the Asset
|
* Finds an entry matching the Asset
|
||||||
@@ -213,24 +243,7 @@ class AssetContainerBase
|
|||||||
* \return Pointer to an Entry, nullptr otherwise
|
* \return Pointer to an Entry, nullptr otherwise
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Entry* FindEntry(const UUID& p_uuid)
|
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
|
|
||||||
*
|
|
||||||
* \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
|
* Finds an entry matching the Asset
|
||||||
@@ -240,17 +253,14 @@ class AssetContainerBase
|
|||||||
* \return The entry matching the Asset
|
* \return The entry matching the Asset
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Entry& GetOrCreateEntry(const UUID& p_uuid)
|
Entry& GetOrCreateEntry(const UUID& p_uuid);
|
||||||
{
|
|
||||||
auto [it, inserted] = m_uuidToEntry.try_emplace(p_uuid);
|
|
||||||
if (inserted)
|
|
||||||
{
|
|
||||||
it->second.m_handleSlotKey = m_handles.Insert();
|
|
||||||
it->second.m_handle = m_handles.Get(it->second.m_handleSlotKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
return it->second;
|
/*
|
||||||
}
|
* Remove an asset
|
||||||
|
*
|
||||||
|
* \param p_key The key to the asset
|
||||||
|
*/
|
||||||
|
virtual void RemoveAsset(SlotMapKey p_slotKey) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
@@ -262,6 +272,11 @@ class AssetContainerBase
|
|||||||
* Every Asset added to the map
|
* Every Asset added to the map
|
||||||
*/
|
*/
|
||||||
ankerl::unordered_dense::map<UUID, Entry> m_uuidToEntry;
|
ankerl::unordered_dense::map<UUID, Entry> m_uuidToEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assets queued for removal
|
||||||
|
*/
|
||||||
|
eastl::vector<UUID> m_pendingRemovalUuids;
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
@@ -277,16 +292,42 @@ class AssetContainer: public AssetContainerBase
|
|||||||
/*
|
/*
|
||||||
* Inserts an Asset to the AssetContainer
|
* Inserts an Asset to the AssetContainer
|
||||||
*
|
*
|
||||||
* \tparam ARGS Arguments to construct the asset
|
* \param p_flatbuffer The flatbuffer to unpack to the asset
|
||||||
* \param p_args The arguments
|
* \return The handle of the inserted asset
|
||||||
* \return The key to the inserted asset.
|
|
||||||
*/
|
*/
|
||||||
template<class... ARGS>
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
SlotMapKey Insert(ARGS&&... p_args)
|
ContainerHandle* Insert(const eastl::span<const std::byte> p_flatbuffer) override
|
||||||
{
|
{
|
||||||
SlotMapKey slotKey = m_assets.Insert(std::forward<ARGS>(p_args)...);
|
return InsertInternal(&p_flatbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inserts an Asset to the AssetContainer
|
||||||
|
*
|
||||||
|
* \return The handle of the inserted asset
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
ContainerHandle* Insert() override
|
||||||
|
{
|
||||||
|
return InsertInternal(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*
|
||||||
|
* Inserts an Asset to the AssetContainer, unpacking it from a flatbuffer if given one
|
||||||
|
*
|
||||||
|
* \param p_flatbuffer The flatbuffer to unpack to the asset, nullptr to default-construct the asset
|
||||||
|
* \return The handle of the inserted asset
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
ContainerHandle* InsertInternal(const eastl::span<const std::byte>* p_flatbuffer)
|
||||||
|
{
|
||||||
|
SlotMapKey slotKey = m_assets.Insert();
|
||||||
ASSET* asset = m_assets.Get(slotKey);
|
ASSET* asset = m_assets.Get(slotKey);
|
||||||
|
if (p_flatbuffer != nullptr)
|
||||||
|
{
|
||||||
|
asset->Unpack(*p_flatbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
Entry& entry = GetOrCreateEntry(asset->GetHeader().uuid);
|
Entry& entry = GetOrCreateEntry(asset->GetHeader().uuid);
|
||||||
if (entry.m_assetSlotKey.Valid())
|
if (entry.m_assetSlotKey.Valid())
|
||||||
@@ -300,51 +341,19 @@ class AssetContainer: public AssetContainerBase
|
|||||||
entry.m_handle->SetAsset(asset);
|
entry.m_handle->SetAsset(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return slotKey;
|
return entry.m_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the Asset
|
* Remove an asset
|
||||||
*
|
*
|
||||||
* \param p_key The key to the asset
|
* \param p_key The key to the asset
|
||||||
* \return Pointer to the Asset
|
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
void RemoveAsset(SlotMapKey p_key) override
|
||||||
ASSET* Get(const SlotMapKey p_key)
|
|
||||||
{
|
{
|
||||||
return m_assets.Get(p_key);
|
m_assets.Remove(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())
|
|
||||||
{
|
|
||||||
entry->m_handle->SetAsset(nullptr);
|
|
||||||
m_assets.Remove(entry->m_assetSlotKey);
|
|
||||||
entry->m_assetSlotKey = SlotMapKey {};
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetContainerBase::Remove(p_uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/*
|
/*
|
||||||
* The assets
|
* The assets
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -19,6 +19,13 @@
|
|||||||
return AssetType::GetTypeID(); \
|
return AssetType::GetTypeID(); \
|
||||||
} \
|
} \
|
||||||
AssetContainer<AssetType> g_containerFor##AssetName; \
|
AssetContainer<AssetType> g_containerFor##AssetName; \
|
||||||
const bool g_insertedContainerFor##AssetName = g_assetLibrary.Insert(&g_containerFor##AssetName); \
|
const bool g_insertedContainerFor##AssetName = []() \
|
||||||
|
{ \
|
||||||
|
const bool inserted = g_assetLibrary.Insert(&g_containerFor##AssetName); \
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler, \
|
||||||
|
inserted, \
|
||||||
|
"AssetTypeID collision or duplicate registration for asset type '" #AssetName "'"); \
|
||||||
|
return inserted; \
|
||||||
|
}(); \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -52,15 +52,7 @@ class AssetLibrary
|
|||||||
* \return The AssetContainer for the AssetType. Nullptr if not found
|
* \return The AssetContainer for the AssetType. Nullptr if not found
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
AssetContainerBase* GetAssetContainer(const AssetTypeID p_typeID)
|
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
|
* Get the AssetContainer for a given AssetType
|
||||||
@@ -69,19 +61,46 @@ class AssetLibrary
|
|||||||
* \return The AssetContainer for the AssetType. Nullptr if not found
|
* \return The AssetContainer for the AssetType. Nullptr if not found
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const AssetContainerBase* GetAssetContainer(const AssetTypeID p_typeID) const
|
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;
|
/**
|
||||||
}
|
* Get the AssetContainer for a given UUID
|
||||||
|
*
|
||||||
|
* \param p_uuid The asset
|
||||||
|
* \return The AssetContainer for the UUID. Nullptr if not found
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
const AssetContainerBase* GetAssetContainer(const UUID& p_uuid) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the AssetContainer for a given UUID
|
||||||
|
*
|
||||||
|
* \param p_uuid The asset
|
||||||
|
* \return The AssetContainer for the UUID. Nullptr if not found
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
AssetContainerBase* GetAssetContainer(const UUID& p_uuid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an Asset is already loaded in the library
|
||||||
|
*
|
||||||
|
* \param p_uuid The asset to check
|
||||||
|
* \return True if already loaded, false otherwise
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool IsLoaded(const UUID& p_uuid) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop through the AssetContainers to remove the pending assets marked for removal
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ProcessPendingRemovals();
|
||||||
|
|
||||||
AssetLibrary& operator=(const AssetLibrary& p_library) = default;
|
AssetLibrary& operator=(const AssetLibrary& p_library) = default;
|
||||||
AssetLibrary& operator=(AssetLibrary&& p_library) = delete;
|
AssetLibrary& operator=(AssetLibrary&& p_library) = delete;
|
||||||
|
|
||||||
|
~AssetLibrary() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// All the asset containers
|
// All the asset containers
|
||||||
ankerl::unordered_dense::map<AssetTypeID, AssetContainerBase*> m_assetContainers;
|
ankerl::unordered_dense::map<AssetTypeID, AssetContainerBase*> m_assetContainers;
|
||||||
|
|||||||
@@ -15,13 +15,10 @@ using AssetTypeID = std::uint64_t;
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
namespace Flat
|
namespace Flat::Bigfoot
|
||||||
{
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
{
|
||||||
struct AssetTypeID;
|
struct AssetTypeID;
|
||||||
}
|
} // namespace Flat::Bigfoot
|
||||||
} // namespace Flat
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ struct AssetHeaderT : public ::flatbuffers::NativeTable {
|
|||||||
eastl::string name{};
|
eastl::string name{};
|
||||||
::Bigfoot::AssetTypeID type_id{};
|
::Bigfoot::AssetTypeID type_id{};
|
||||||
eastl::string type_name{};
|
eastl::string type_name{};
|
||||||
uint32_t version = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AssetHeader FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
struct AssetHeader FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||||
@@ -70,8 +69,7 @@ struct AssetHeader FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
|||||||
VT_UUID = 4,
|
VT_UUID = 4,
|
||||||
VT_NAME = 6,
|
VT_NAME = 6,
|
||||||
VT_TYPE_ID = 8,
|
VT_TYPE_ID = 8,
|
||||||
VT_TYPE_NAME = 10,
|
VT_TYPE_NAME = 10
|
||||||
VT_VERSION = 12
|
|
||||||
};
|
};
|
||||||
const Flat::Bigfoot::UUID *uuid() const {
|
const Flat::Bigfoot::UUID *uuid() const {
|
||||||
return GetStruct<const Flat::Bigfoot::UUID *>(VT_UUID);
|
return GetStruct<const Flat::Bigfoot::UUID *>(VT_UUID);
|
||||||
@@ -85,9 +83,6 @@ struct AssetHeader FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
|||||||
const ::flatbuffers::String *type_name() const {
|
const ::flatbuffers::String *type_name() const {
|
||||||
return GetPointer<const ::flatbuffers::String *>(VT_TYPE_NAME);
|
return GetPointer<const ::flatbuffers::String *>(VT_TYPE_NAME);
|
||||||
}
|
}
|
||||||
uint32_t version() const {
|
|
||||||
return GetField<uint32_t>(VT_VERSION, 0);
|
|
||||||
}
|
|
||||||
template <bool B = false>
|
template <bool B = false>
|
||||||
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
||||||
return VerifyTableStart(verifier) &&
|
return VerifyTableStart(verifier) &&
|
||||||
@@ -97,7 +92,6 @@ struct AssetHeader FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
|||||||
VerifyFieldRequired<Flat::Bigfoot::AssetTypeID>(verifier, VT_TYPE_ID, 8) &&
|
VerifyFieldRequired<Flat::Bigfoot::AssetTypeID>(verifier, VT_TYPE_ID, 8) &&
|
||||||
VerifyOffsetRequired(verifier, VT_TYPE_NAME) &&
|
VerifyOffsetRequired(verifier, VT_TYPE_NAME) &&
|
||||||
verifier.VerifyString(type_name()) &&
|
verifier.VerifyString(type_name()) &&
|
||||||
VerifyField<uint32_t>(verifier, VT_VERSION, 4) &&
|
|
||||||
verifier.EndTable();
|
verifier.EndTable();
|
||||||
}
|
}
|
||||||
AssetHeaderT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
AssetHeaderT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
|
||||||
@@ -121,9 +115,6 @@ struct AssetHeaderBuilder {
|
|||||||
void add_type_name(::flatbuffers::Offset<::flatbuffers::String> type_name) {
|
void add_type_name(::flatbuffers::Offset<::flatbuffers::String> type_name) {
|
||||||
fbb_.AddOffset(AssetHeader::VT_TYPE_NAME, type_name);
|
fbb_.AddOffset(AssetHeader::VT_TYPE_NAME, type_name);
|
||||||
}
|
}
|
||||||
void add_version(uint32_t version) {
|
|
||||||
fbb_.AddElement<uint32_t>(AssetHeader::VT_VERSION, version, 0);
|
|
||||||
}
|
|
||||||
explicit AssetHeaderBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
|
explicit AssetHeaderBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
|
||||||
: fbb_(_fbb) {
|
: fbb_(_fbb) {
|
||||||
start_ = fbb_.StartTable();
|
start_ = fbb_.StartTable();
|
||||||
@@ -144,10 +135,8 @@ inline ::flatbuffers::Offset<AssetHeader> CreateAssetHeader(
|
|||||||
const Flat::Bigfoot::UUID *uuid = nullptr,
|
const Flat::Bigfoot::UUID *uuid = nullptr,
|
||||||
::flatbuffers::Offset<::flatbuffers::String> name = 0,
|
::flatbuffers::Offset<::flatbuffers::String> name = 0,
|
||||||
const Flat::Bigfoot::AssetTypeID *type_id = nullptr,
|
const Flat::Bigfoot::AssetTypeID *type_id = nullptr,
|
||||||
::flatbuffers::Offset<::flatbuffers::String> type_name = 0,
|
::flatbuffers::Offset<::flatbuffers::String> type_name = 0) {
|
||||||
uint32_t version = 0) {
|
|
||||||
AssetHeaderBuilder builder_(_fbb);
|
AssetHeaderBuilder builder_(_fbb);
|
||||||
builder_.add_version(version);
|
|
||||||
builder_.add_type_name(type_name);
|
builder_.add_type_name(type_name);
|
||||||
builder_.add_type_id(type_id);
|
builder_.add_type_id(type_id);
|
||||||
builder_.add_name(name);
|
builder_.add_name(name);
|
||||||
@@ -262,7 +251,6 @@ inline void AssetHeader::UnPackTo(AssetHeaderT *_o, const ::flatbuffers::resolve
|
|||||||
{ auto _e = name(); if (_e) _o->name = eastl::string(_e->c_str(), _e->size()); }
|
{ 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_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 = type_name(); if (_e) _o->type_name = eastl::string(_e->c_str(), _e->size()); }
|
||||||
{ auto _e = version(); _o->version = _e; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ::flatbuffers::Offset<AssetHeader> CreateAssetHeader(::flatbuffers::FlatBufferBuilder &_fbb, const AssetHeaderT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
|
inline ::flatbuffers::Offset<AssetHeader> CreateAssetHeader(::flatbuffers::FlatBufferBuilder &_fbb, const AssetHeaderT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
|
||||||
@@ -277,14 +265,12 @@ inline ::flatbuffers::Offset<AssetHeader> AssetHeader::Pack(::flatbuffers::FlatB
|
|||||||
auto _name = _fbb.CreateString(_o->name);
|
auto _name = _fbb.CreateString(_o->name);
|
||||||
auto _type_id = ::flatbuffers::Pack(_o->type_id);
|
auto _type_id = ::flatbuffers::Pack(_o->type_id);
|
||||||
auto _type_name = _fbb.CreateString(_o->type_name);
|
auto _type_name = _fbb.CreateString(_o->type_name);
|
||||||
auto _version = _o->version;
|
|
||||||
return Flat::Bigfoot::CreateAssetHeader(
|
return Flat::Bigfoot::CreateAssetHeader(
|
||||||
_fbb,
|
_fbb,
|
||||||
&_uuid,
|
&_uuid,
|
||||||
_name,
|
_name,
|
||||||
&_type_id,
|
&_type_id,
|
||||||
_type_name,
|
_type_name);
|
||||||
_version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline AssetT::AssetT(const AssetT &o)
|
inline AssetT::AssetT(const AssetT &o)
|
||||||
@@ -332,15 +318,14 @@ inline const ::flatbuffers::TypeTable *AssetHeaderTypeTable() {
|
|||||||
{ ::flatbuffers::ET_SEQUENCE, 0, 0 },
|
{ ::flatbuffers::ET_SEQUENCE, 0, 0 },
|
||||||
{ ::flatbuffers::ET_STRING, 0, -1 },
|
{ ::flatbuffers::ET_STRING, 0, -1 },
|
||||||
{ ::flatbuffers::ET_SEQUENCE, 0, 1 },
|
{ ::flatbuffers::ET_SEQUENCE, 0, 1 },
|
||||||
{ ::flatbuffers::ET_STRING, 0, -1 },
|
{ ::flatbuffers::ET_STRING, 0, -1 }
|
||||||
{ ::flatbuffers::ET_UINT, 0, -1 }
|
|
||||||
};
|
};
|
||||||
static const ::flatbuffers::TypeFunction type_refs[] = {
|
static const ::flatbuffers::TypeFunction type_refs[] = {
|
||||||
Flat::Bigfoot::UUIDTypeTable,
|
Flat::Bigfoot::UUIDTypeTable,
|
||||||
Flat::Bigfoot::AssetTypeIDTypeTable
|
Flat::Bigfoot::AssetTypeIDTypeTable
|
||||||
};
|
};
|
||||||
static const ::flatbuffers::TypeTable tt = {
|
static const ::flatbuffers::TypeTable tt = {
|
||||||
::flatbuffers::ST_TABLE, 5, type_codes, type_refs, nullptr, nullptr, nullptr
|
::flatbuffers::ST_TABLE, 4, type_codes, type_refs, nullptr, nullptr, nullptr
|
||||||
};
|
};
|
||||||
return &tt;
|
return &tt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,9 @@ class ReferenceBase
|
|||||||
return m_uuid == p_reference.m_uuid;
|
return m_uuid == p_reference.m_uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
|
friend DERIVED;
|
||||||
|
|
||||||
ReferenceBase() = default;
|
ReferenceBase() = default;
|
||||||
|
|
||||||
ReferenceBase(const UUID& p_uuid):
|
ReferenceBase(const UUID& p_uuid):
|
||||||
@@ -116,7 +118,6 @@ class ReferenceBase
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
/**
|
||||||
* Get the associated handle container for the asset
|
* Get the associated handle container for the asset
|
||||||
* Register the reference inside the handle
|
* Register the reference inside the handle
|
||||||
@@ -152,7 +153,6 @@ class ReferenceBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
/**
|
||||||
* The UUID
|
* The UUID
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,12 +9,17 @@
|
|||||||
#include <Engine/DataAccessor/DataAccessor.hpp>
|
#include <Engine/DataAccessor/DataAccessor.hpp>
|
||||||
|
|
||||||
#include <System/File/File.hpp>
|
#include <System/File/File.hpp>
|
||||||
|
#include <System/Time/Time.hpp>
|
||||||
|
|
||||||
#include <Utils/TaggedType.hpp>
|
#include <Utils/TaggedType.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/optional.h>
|
||||||
#include <EASTL/span.h>
|
#include <EASTL/span.h>
|
||||||
|
#include <EASTL/string_view.h>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
#ifdef BIGFOOT_TOOLMODE
|
#ifdef BIGFOOT_TOOLMODE
|
||||||
@@ -49,15 +54,22 @@ class BigFile: public DataAccessor
|
|||||||
*/
|
*/
|
||||||
void RollbackTransaction();
|
void RollbackTransaction();
|
||||||
|
|
||||||
~BigFile();
|
/**
|
||||||
|
* Clear the BigFile
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
~BigFile() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an Asset flatbuffer
|
* Get an Asset flatbuffer
|
||||||
*
|
*
|
||||||
* \param p_uuid The asset to get the flatbuffer of
|
* \param p_uuid The asset to get the flatbuffer of
|
||||||
* \return The flatbuffer, or nullopt if the asset was not found
|
* \return The flatbuffer, or an empty vector if the asset was not found
|
||||||
*/
|
*/
|
||||||
eastl::optional<eastl::vector<std::byte>> GetAssetFlatbuffer(const UUID& p_uuid) const override;
|
[[nodiscard]]
|
||||||
|
eastl::vector<std::byte> GetAssetFlatbuffer(const UUID& p_uuid) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get several Asset flatbuffers
|
* Get several Asset flatbuffers
|
||||||
@@ -65,40 +77,75 @@ class BigFile: public DataAccessor
|
|||||||
* \param p_uuids The assets to get the flatbuffers of
|
* \param p_uuids The assets to get the flatbuffers of
|
||||||
* \return The flatbuffers that were found
|
* \return The flatbuffers that were found
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
eastl::vector<eastl::vector<std::byte>> GetAssetFlatbuffers(eastl::span<const UUID> p_uuids) const override;
|
eastl::vector<eastl::vector<std::byte>> GetAssetFlatbuffers(eastl::span<const UUID> p_uuids) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an Asset metadata
|
* Get the HardReferences of a given asset
|
||||||
*
|
*
|
||||||
* \param p_uuid The asset to get the metadata of
|
* \param p_uuid The asset to get the HardReferences of
|
||||||
* \return The metadata, or nullopt if the asset was not found
|
* \return The HardReferences of the asset
|
||||||
*/
|
*/
|
||||||
eastl::optional<AssetMetadata> GetAssetMetadata(const UUID& p_uuid) const override;
|
[[nodiscard]]
|
||||||
|
eastl::vector<UUID> GetAssetHardReferences(const UUID& p_uuid) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get several Asset metadatas
|
* Get the HardReferences of given assets
|
||||||
*
|
*
|
||||||
* \param p_uuids The assets to get the metadatas of
|
* \param p_uuids The assets to get the HardReferences of
|
||||||
* \return The metadatas that were found
|
* \return The HardReferences of the assets
|
||||||
*/
|
*/
|
||||||
eastl::vector<AssetMetadata> GetAssetMetadatas(eastl::span<const UUID> p_uuids) const override;
|
[[nodiscard]]
|
||||||
|
eastl::vector<eastl::vector<UUID>> GetAssetsHardReferences(eastl::span<const UUID> p_uuids) const override;
|
||||||
|
|
||||||
|
struct AssetTime
|
||||||
|
{
|
||||||
|
Time m_creationTime;
|
||||||
|
Time m_modificationTime;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
bool operator==(const AssetTime& p_other) const = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the creation and modification time of an asset
|
||||||
|
*
|
||||||
|
* \param p_uuid The asset to get the time of
|
||||||
|
* \return The time of the asset, nullopt if the asset was not found
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::optional<AssetTime> GetAssetTime(const UUID& p_uuid) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the creation and modification time of several assets
|
||||||
|
*
|
||||||
|
* \param p_uuids The assets to get the time of
|
||||||
|
* \return The time of the assets. nullopt for assets not found
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<eastl::optional<AssetTime>> GetAssetsTime(eastl::span<const UUID> p_uuids) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save an asset
|
* Save an asset
|
||||||
*
|
*
|
||||||
* \p_metadata The metadata
|
* \param p_uuid The UUID
|
||||||
* \p_flatbuffer The flatbuffer of the asset
|
* \param p_flatbuffer The flatbuffer of the asset
|
||||||
|
* \param p_hardReferences The HardReferences the asset points to
|
||||||
*/
|
*/
|
||||||
void SaveAssetFlatbuffer(const AssetMetadata& p_metadata, const eastl::span<const std::byte> p_flatbuffer) override;
|
void SaveAssetFlatbuffer(const UUID& p_uuid,
|
||||||
|
const eastl::span<const std::byte> p_flatbuffer,
|
||||||
|
const eastl::span<const UUID> p_hardReferences) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save several assets
|
* Save several assets
|
||||||
*
|
*
|
||||||
* \p_metadatas The metadatas
|
* \param p_uuids The UUIDs
|
||||||
* \p_flatbuffers The flatbuffers of the assets, matching p_metadatas by index
|
* \param p_flatbuffers The flatbuffers of the assets, matching p_metadatas by index
|
||||||
|
* \param p_hardReferences The HardReferences the asset points to
|
||||||
*/
|
*/
|
||||||
void SaveAssetFlatbuffers(eastl::span<const AssetMetadata> p_metadatas,
|
void SaveAssetFlatbuffers(const eastl::span<const UUID> p_uuids,
|
||||||
eastl::span<const eastl::vector<std::byte>> p_flatbuffers) override;
|
const eastl::span<const eastl::vector<std::byte>> p_flatbuffers,
|
||||||
|
const eastl::span<const eastl::vector<UUID>> p_hardReferences) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the Asset exists
|
* Check if the Asset exists
|
||||||
@@ -106,6 +153,7 @@ class BigFile: public DataAccessor
|
|||||||
* \param p_uuid The asset to check
|
* \param p_uuid The asset to check
|
||||||
* \param True if it exists, false otherwise
|
* \param True if it exists, false otherwise
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
bool Has(const UUID& p_uuid) const override;
|
bool Has(const UUID& p_uuid) const override;
|
||||||
|
|
||||||
BigFile& operator=(const BigFile& p_bigFile) = delete;
|
BigFile& operator=(const BigFile& p_bigFile) = delete;
|
||||||
@@ -280,6 +328,13 @@ class BigFile: public DataAccessor
|
|||||||
*/
|
*/
|
||||||
operator eastl::span<const std::byte>() const;
|
operator eastl::span<const std::byte>() const;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get value as a blob
|
||||||
|
*
|
||||||
|
* \return The value
|
||||||
|
*/
|
||||||
|
operator std::span<const std::byte>() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
* The statement
|
* The statement
|
||||||
@@ -314,14 +369,14 @@ class BigFile: public DataAccessor
|
|||||||
/*
|
/*
|
||||||
* The statement
|
* The statement
|
||||||
*/
|
*/
|
||||||
sqlite3_stmt* m_statement;
|
sqlite3_stmt* m_statement = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* The BigFile DB
|
* The BigFile DB
|
||||||
*/
|
*/
|
||||||
sqlite3* m_db;
|
sqlite3* m_db = nullptr;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -11,25 +11,12 @@
|
|||||||
#include <System/Time/Time.hpp>
|
#include <System/Time/Time.hpp>
|
||||||
#include <System/UUID/UUID.hpp>
|
#include <System/UUID/UUID.hpp>
|
||||||
|
|
||||||
#include <EASTL/optional.h>
|
|
||||||
#include <EASTL/span.h>
|
#include <EASTL/span.h>
|
||||||
#include <EASTL/string.h>
|
#include <EASTL/string.h>
|
||||||
#include <EASTL/vector.h>
|
#include <EASTL/vector.h>
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
struct AssetMetadata
|
|
||||||
{
|
|
||||||
UUID m_uuid = UUID::NULL_UUID;
|
|
||||||
eastl::string m_name {};
|
|
||||||
|
|
||||||
AssetTypeID m_typeID = 0;
|
|
||||||
eastl::string m_typeName {};
|
|
||||||
|
|
||||||
Time m_creationTime = 0;
|
|
||||||
Time m_modificationTime = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DataAccessor
|
class DataAccessor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -44,9 +31,10 @@ class DataAccessor
|
|||||||
* Get an Asset flatbuffer
|
* Get an Asset flatbuffer
|
||||||
*
|
*
|
||||||
* \param p_uuid The asset to get the flatbuffer of
|
* \param p_uuid The asset to get the flatbuffer of
|
||||||
* \return The flatbuffer, or nullopt if the asset was not found
|
* \return The flatbuffer, or an empty vector if the asset was not found
|
||||||
*/
|
*/
|
||||||
virtual eastl::optional<eastl::vector<std::byte>> GetAssetFlatbuffer(const UUID& p_uuid) const = 0;
|
[[nodiscard]]
|
||||||
|
virtual eastl::vector<std::byte> GetAssetFlatbuffer(const UUID& p_uuid) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get several Asset flatbuffers
|
* Get several Asset flatbuffers
|
||||||
@@ -54,41 +42,48 @@ class DataAccessor
|
|||||||
* \param p_uuids The assets to get the flatbuffers of
|
* \param p_uuids The assets to get the flatbuffers of
|
||||||
* \return The flatbuffers that were found
|
* \return The flatbuffers that were found
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
virtual eastl::vector<eastl::vector<std::byte>> GetAssetFlatbuffers(eastl::span<const UUID> p_uuids) const = 0;
|
virtual eastl::vector<eastl::vector<std::byte>> GetAssetFlatbuffers(eastl::span<const UUID> p_uuids) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an Asset metadata
|
* Get the HardReferences of a given asset
|
||||||
*
|
*
|
||||||
* \param p_uuid The asset to get the metadata of
|
* \param p_uuid The asset to get the HardReferences of
|
||||||
* \return The metadata, or nullopt if the asset was not found
|
* \return The HardReferences of the asset
|
||||||
*/
|
*/
|
||||||
virtual eastl::optional<AssetMetadata> GetAssetMetadata(const UUID& p_uuid) const = 0;
|
[[nodiscard]]
|
||||||
|
virtual eastl::vector<UUID> GetAssetHardReferences(const UUID& p_uuid) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get several Asset metadatas
|
* Get the HardReferences of given assets
|
||||||
*
|
*
|
||||||
* \param p_uuids The assets to get the metadatas of
|
* \param p_uuids The assets to get the HardReferences of
|
||||||
* \return The metadatas that were found
|
* \return The HardReferences of the assets
|
||||||
*/
|
*/
|
||||||
virtual eastl::vector<AssetMetadata> GetAssetMetadatas(eastl::span<const UUID> p_uuids) const = 0;
|
[[nodiscard]]
|
||||||
|
virtual eastl::vector<eastl::vector<UUID>> GetAssetsHardReferences(eastl::span<const UUID> p_uuids) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save an asset
|
* Save an asset
|
||||||
*
|
*
|
||||||
* \p_metadata The metadata
|
* \param p_uuid The UUID
|
||||||
* \p_flatbuffer The flatbuffer of the asset
|
* \param p_flatbuffer The flatbuffer of the asset
|
||||||
|
* \param p_hardReferences The HardReferences the asset points to
|
||||||
*/
|
*/
|
||||||
virtual void SaveAssetFlatbuffer(const AssetMetadata& p_metadata,
|
virtual void SaveAssetFlatbuffer(const UUID& p_uuid,
|
||||||
const eastl::span<const std::byte> p_flatbuffer) = 0;
|
const eastl::span<const std::byte> p_flatbuffer,
|
||||||
|
const eastl::span<const UUID> p_hardReferences) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save several assets
|
* Save several assets
|
||||||
*
|
*
|
||||||
* \p_metadatas The metadatas
|
* \param p_uuids The UUIDs
|
||||||
* \p_flatbuffers The flatbuffers of the assets, matching p_metadatas by index
|
* \param p_flatbuffers The flatbuffers of the assets, matching p_metadatas by index
|
||||||
|
* \param p_hardReferences The HardReferences the asset points to
|
||||||
*/
|
*/
|
||||||
virtual void SaveAssetFlatbuffers(eastl::span<const AssetMetadata> p_metadatas,
|
virtual void SaveAssetFlatbuffers(const eastl::span<const UUID> p_uuids,
|
||||||
eastl::span<const eastl::vector<std::byte>> p_flatbuffers) = 0;
|
const eastl::span<const eastl::vector<std::byte>> p_flatbuffers,
|
||||||
|
const eastl::span<const eastl::vector<UUID>> p_hardReferences) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the Asset exists
|
* Check if the Asset exists
|
||||||
@@ -96,6 +91,7 @@ class DataAccessor
|
|||||||
* \param p_uuid The asset to check
|
* \param p_uuid The asset to check
|
||||||
* \param True if it exists, false otherwise
|
* \param True if it exists, false otherwise
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
virtual bool Has(const UUID& p_uuid) const = 0;
|
virtual bool Has(const UUID& p_uuid) const = 0;
|
||||||
|
|
||||||
DataAccessor& operator=(const DataAccessor& p_accessor) = default;
|
DataAccessor& operator=(const DataAccessor& p_accessor) = default;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include <Utils/Assert/AssertHandler.hpp>
|
#include <Utils/Assert/AssertHandler.hpp>
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Bigfoot
|
|||||||
/*
|
/*
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
inline Log::LoggerInfo ENGINE_LOGGER {"ENGINE_LOGGER", Flat::LogLevel::Trace};
|
inline Log::LoggerInfo ENGINE_LOGGER { .m_name = "ENGINE_LOGGER", .m_level = Flat::LogLevel::Trace};
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,243 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file Sasquatch.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_ENGINE_SASQUATCH_SASQUATCH_HPP
|
||||||
|
#define BIGFOOT_ENGINE_SASQUATCH_SASQUATCH_HPP
|
||||||
|
#include <Engine/DataAccessor/DataAccessor.hpp>
|
||||||
|
|
||||||
|
#include <System/File/File.hpp>
|
||||||
|
#include <System/File/MemoryMappedFile.hpp>
|
||||||
|
#include <System/UUID/UUID.hpp>
|
||||||
|
|
||||||
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
|
#include <EASTL/span.h>
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
#include <ankerl/unordered_dense.h>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
struct SasquatchHeader
|
||||||
|
{
|
||||||
|
static constexpr std::uint32_t MAGIC = 0x53515443; // 'SQTC'
|
||||||
|
static constexpr std::uint32_t VERSION = 1;
|
||||||
|
|
||||||
|
std::uint32_t m_magic = MAGIC;
|
||||||
|
std::uint32_t m_version = VERSION;
|
||||||
|
std::uint64_t m_assetCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(std::is_trivially_copyable_v<SasquatchHeader>);
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
struct SasquatchEntry
|
||||||
|
{
|
||||||
|
std::array<std::byte, UUID::UUID_BYTE_SIZE> m_uuid {};
|
||||||
|
|
||||||
|
std::size_t m_assetOffset = 0;
|
||||||
|
std::size_t m_assetSize = 0;
|
||||||
|
|
||||||
|
std::size_t m_hardReferencesOffset = 0;
|
||||||
|
std::size_t m_hardReferencesSize = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(std::is_trivially_copyable_v<SasquatchEntry>);
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
#if defined(BIGFOOT_TOOLMODE) || defined(BIGFOOT_BUILD_TESTS) || defined(BIGFOOT_BUILD_BENCHMARKS)
|
||||||
|
class SasquatchWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* Writes the header
|
||||||
|
*
|
||||||
|
* \param p_file The file to write
|
||||||
|
* \param p_assetCount The number of assets that will be written
|
||||||
|
* \param p_totalFlatbufferBytes The sum of the sizes of every flatbuffer that will be written
|
||||||
|
* \param p_totalHardReferencesBytes The sum of the sizes of every asset hardreferences that will be written
|
||||||
|
*/
|
||||||
|
SasquatchWriter(const File& p_file,
|
||||||
|
const std::uint64_t p_assetCount,
|
||||||
|
const std::size_t p_totalFlatbufferBytes,
|
||||||
|
const std::size_t p_totalHardReferencesBytes);
|
||||||
|
|
||||||
|
SasquatchWriter(const SasquatchWriter& p_writer) = delete;
|
||||||
|
SasquatchWriter(SasquatchWriter&& p_writer) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
* Writes the entries
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
~SasquatchWriter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes an asset to the file.
|
||||||
|
*
|
||||||
|
* \param p_uuid The UUID of the asset
|
||||||
|
* \param p_flatbuffer The flatbuffer of the asset
|
||||||
|
*/
|
||||||
|
void WriteAsset(const UUID& p_uuid,
|
||||||
|
eastl::span<const std::byte> p_flatbuffer,
|
||||||
|
eastl::span<const UUID> p_hardReferences);
|
||||||
|
|
||||||
|
SasquatchWriter& operator=(const SasquatchWriter& p_writer) = delete;
|
||||||
|
SasquatchWriter& operator=(SasquatchWriter&& p_writer) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr std::uint64_t PREFETCH_BYTES = 4ULL * 1024 * 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of assets expected
|
||||||
|
*/
|
||||||
|
std::uint64_t m_assetCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How far into m_file has already been prefetched
|
||||||
|
*/
|
||||||
|
std::size_t m_prefetchedUpTo = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current write position in the data region
|
||||||
|
*/
|
||||||
|
std::size_t m_currentDataOffset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Sasquatch file being written, mapped at its final size
|
||||||
|
*/
|
||||||
|
WritableMemoryMappedFile m_file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entries
|
||||||
|
*/
|
||||||
|
eastl::vector<SasquatchEntry> m_entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
class Sasquatch: public DataAccessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* \param p_file The sasquatch file
|
||||||
|
*/
|
||||||
|
Sasquatch(const File& p_file);
|
||||||
|
|
||||||
|
Sasquatch(const Sasquatch& p_sasquatch) = delete;
|
||||||
|
Sasquatch(Sasquatch&& p_sasquatch) = delete;
|
||||||
|
|
||||||
|
~Sasquatch() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the header
|
||||||
|
*
|
||||||
|
* \return The header
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
const SasquatchHeader& GetHeader() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an Asset flatbuffer
|
||||||
|
*
|
||||||
|
* \param p_uuid The asset to get the flatbuffer of
|
||||||
|
* \return The flatbuffer, or an empty vector if the asset was not found
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<std::byte> GetAssetFlatbuffer(const UUID& p_uuid) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get several Asset flatbuffers
|
||||||
|
*
|
||||||
|
* \param p_uuids The assets to get the flatbuffers of
|
||||||
|
* \return The flatbuffers that were found
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<eastl::vector<std::byte>> GetAssetFlatbuffers(eastl::span<const UUID> p_uuids) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the HardReferences of a given asset
|
||||||
|
*
|
||||||
|
* \param p_uuid The asset to get the HardReferences of
|
||||||
|
* \return The HardReferences of the asset
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<UUID> GetAssetHardReferences(const UUID& p_uuid) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the HardReferences of given assets
|
||||||
|
*
|
||||||
|
* \param p_uuids The assets to get the HardReferences of
|
||||||
|
* \return The HardReferences of the assets
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<eastl::vector<UUID>> GetAssetsHardReferences(eastl::span<const UUID> p_uuids) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sasquatch is read-only: this will always fail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void SaveAssetFlatbuffer(const UUID& p_uuid,
|
||||||
|
eastl::span<const std::byte> p_flatbuffer,
|
||||||
|
eastl::span<const UUID> p_hardReferences) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sasquatch is read-only: this will always fail
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void SaveAssetFlatbuffers(const eastl::span<const UUID> p_uuids,
|
||||||
|
eastl::span<const eastl::vector<std::byte>> p_flatbuffers,
|
||||||
|
eastl::span<const eastl::vector<UUID>> p_hardReferences) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the Asset exists
|
||||||
|
*
|
||||||
|
* \param p_uuid The asset to check
|
||||||
|
* \param True if it exists, false otherwise
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool Has(const UUID& p_uuid) const override;
|
||||||
|
|
||||||
|
Sasquatch& operator=(const Sasquatch& p_sasquatch) = delete;
|
||||||
|
Sasquatch& operator=(Sasquatch&& p_sasquatch) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
std::size_t m_assetOffset = 0;
|
||||||
|
std::size_t m_assetSize = 0;
|
||||||
|
|
||||||
|
std::size_t m_hardReferencesOffset = 0;
|
||||||
|
std::size_t m_hardReferencesSize = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Sasquatch file
|
||||||
|
*/
|
||||||
|
MemoryMappedFile m_file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sasquatch header
|
||||||
|
*/
|
||||||
|
SasquatchHeader m_header;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UUID to entry
|
||||||
|
*/
|
||||||
|
ankerl::unordered_dense::map<UUID, Entry> m_entries;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
@AUTO_GENERATED_COMMENT@
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SasquatchInfo.generated.hpp
|
||||||
|
*
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_@SASQUATCH_NAME@_SASQUATCHINFO_GENERATED_HPP
|
||||||
|
#define BIGFOOT_@SASQUATCH_NAME@_SASQUATCHINFO_GENERATED_HPP
|
||||||
|
|
||||||
|
#include <EASTL/string_view.h>
|
||||||
|
|
||||||
|
#if defined BIGFOOT_GAME
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Sasquatch location
|
||||||
|
*/
|
||||||
|
constexpr eastl::string_view SASQUATCH_@SASQUATCH_NAME@_LOCATION {"@SASQUATCH_LOCATION@"};
|
||||||
|
} // namespace Bigfoot
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file SerializationManager.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_ENGINE_SERIALIZATIONMANAGER_SERIALIZATIONMANAGER_HPP
|
||||||
|
#define BIGFOOT_ENGINE_SERIALIZATIONMANAGER_SERIALIZATIONMANAGER_HPP
|
||||||
|
#include <System/UUID/UUID.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/span.h>
|
||||||
|
|
||||||
|
namespace Bigfoot::SerializationManager
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Load an Asset, along with every HardReference it transitively points to
|
||||||
|
* Already loaded assets are skipped. Assets that are part of a cyclic dependency are left unloaded
|
||||||
|
*
|
||||||
|
* \param p_uuid The asset to load
|
||||||
|
*/
|
||||||
|
void LoadAsset(const UUID& p_uuid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load several Assets, along with every HardReference they transitively point to
|
||||||
|
* Already loaded assets are skipped. Assets that are part of a cyclic dependency are left unloaded
|
||||||
|
*
|
||||||
|
* \param p_uuids The assets to load
|
||||||
|
*/
|
||||||
|
void LoadAssets(const eastl::span<const UUID> p_uuids);
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_TOOLMODE
|
||||||
|
/**
|
||||||
|
* Save an Asset
|
||||||
|
* Fails without saving if a cyclic dependency is detected starting from this asset
|
||||||
|
*
|
||||||
|
* \param p_uuid The asset to save
|
||||||
|
* \return True if the asset was saved, false otherwise
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool SaveAsset(const UUID& p_uuid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save several Assets
|
||||||
|
* Fails without saving any of them if a cyclic dependency is detected starting from any of them
|
||||||
|
*
|
||||||
|
* \param p_uuids The assets to save
|
||||||
|
* \return True if the assets were saved, false otherwise
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool SaveAssets(const eastl::span<const UUID> p_uuids);
|
||||||
|
#endif
|
||||||
|
} // namespace Bigfoot::SerializationManager
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file Sasquatch.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Engine/Sasquatch/Sasquatch.hpp>
|
||||||
|
|
||||||
|
#include <Engine/EngineAssertHandler.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
#if defined(BIGFOOT_TOOLMODE) || defined(BIGFOOT_BUILD_TESTS) || defined(BIGFOOT_BUILD_BENCHMARKS)
|
||||||
|
SasquatchWriter::SasquatchWriter(const File& p_file,
|
||||||
|
const std::uint64_t p_assetCount,
|
||||||
|
const std::size_t p_totalFlatbufferBytes,
|
||||||
|
const std::size_t p_totalHardReferencesBytes):
|
||||||
|
m_assetCount(p_assetCount),
|
||||||
|
m_currentDataOffset(sizeof(SasquatchHeader) + (m_assetCount * sizeof(SasquatchEntry))),
|
||||||
|
m_file(p_file,
|
||||||
|
sizeof(SasquatchHeader) + (m_assetCount * sizeof(SasquatchEntry)) + p_totalFlatbufferBytes +
|
||||||
|
p_totalHardReferencesBytes)
|
||||||
|
{
|
||||||
|
m_entries.reserve(m_assetCount);
|
||||||
|
|
||||||
|
SasquatchHeader header;
|
||||||
|
header.m_assetCount = m_assetCount;
|
||||||
|
|
||||||
|
std::memcpy(m_file.GetData().data(), &header, sizeof(SasquatchHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
SasquatchWriter::~SasquatchWriter()
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
m_entries.size() == m_assetCount,
|
||||||
|
"SasquatchWriter expected {} assets, only {} were added",
|
||||||
|
m_assetCount,
|
||||||
|
m_entries.size());
|
||||||
|
|
||||||
|
m_file.Prefetch(sizeof(SasquatchHeader), m_entries.size() * sizeof(SasquatchEntry));
|
||||||
|
|
||||||
|
if (!m_entries.empty())
|
||||||
|
{
|
||||||
|
std::memcpy(m_file.GetData().data() + sizeof(SasquatchHeader),
|
||||||
|
m_entries.data(),
|
||||||
|
m_entries.size() * sizeof(SasquatchEntry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void SasquatchWriter::WriteAsset(const UUID& p_uuid,
|
||||||
|
eastl::span<const std::byte> p_flatbuffer,
|
||||||
|
eastl::span<const UUID> p_hardReferences)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
m_entries.size() < m_assetCount,
|
||||||
|
"SasquatchWriter can only hold {} assets",
|
||||||
|
m_assetCount);
|
||||||
|
|
||||||
|
const std::size_t offset = m_currentDataOffset;
|
||||||
|
|
||||||
|
const eastl::span<std::byte> data = m_file.GetData();
|
||||||
|
ASSERT(EngineAssertHandler,
|
||||||
|
offset + p_flatbuffer.size() + (p_hardReferences.size() * UUID::UUID_BYTE_SIZE) <= data.size(),
|
||||||
|
"SasquatchWriter can only write {} bytes",
|
||||||
|
data.size());
|
||||||
|
|
||||||
|
const std::size_t writeEnd = offset + p_flatbuffer.size() + (p_hardReferences.size() * UUID::UUID_BYTE_SIZE);
|
||||||
|
if (writeEnd > m_prefetchedUpTo)
|
||||||
|
{
|
||||||
|
const std::size_t prefetchEnd = std::min(writeEnd + PREFETCH_BYTES, data.size());
|
||||||
|
m_file.Prefetch(m_prefetchedUpTo, prefetchEnd - m_prefetchedUpTo);
|
||||||
|
m_prefetchedUpTo = prefetchEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
SasquatchEntry entry;
|
||||||
|
std::memcpy(entry.m_uuid.data(), p_uuid.ToBytes().data(), UUID::UUID_BYTE_SIZE);
|
||||||
|
entry.m_assetOffset = offset;
|
||||||
|
entry.m_assetSize = p_flatbuffer.size();
|
||||||
|
entry.m_hardReferencesOffset = entry.m_assetOffset + entry.m_assetSize;
|
||||||
|
entry.m_hardReferencesSize = p_hardReferences.size() * UUID::UUID_BYTE_SIZE;
|
||||||
|
|
||||||
|
std::memcpy(data.data() + entry.m_assetOffset, p_flatbuffer.data(), entry.m_assetSize);
|
||||||
|
|
||||||
|
for (std::uint32_t i = 0; i < p_hardReferences.size(); ++i)
|
||||||
|
{
|
||||||
|
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawUUID = p_hardReferences[i].ToBytes();
|
||||||
|
std::memcpy(data.data() + entry.m_hardReferencesOffset + (static_cast<std::size_t>(i) * UUID::UUID_BYTE_SIZE),
|
||||||
|
rawUUID.data(),
|
||||||
|
UUID::UUID_BYTE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_currentDataOffset += entry.m_assetSize + entry.m_hardReferencesSize;
|
||||||
|
m_entries.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
Sasquatch::Sasquatch(const File& p_file):
|
||||||
|
m_file(p_file)
|
||||||
|
{
|
||||||
|
const eastl::span<const std::byte> data = m_file.GetData();
|
||||||
|
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler,
|
||||||
|
data.size() >= sizeof(SasquatchHeader),
|
||||||
|
"Sasquatch file {} is smaller than its header",
|
||||||
|
p_file.GetPath());
|
||||||
|
|
||||||
|
std::memcpy(&m_header, data.data(), sizeof(SasquatchHeader));
|
||||||
|
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler,
|
||||||
|
m_header.m_magic == SasquatchHeader::MAGIC,
|
||||||
|
"Sasquatch file {} has an invalid magic number (got {} / expected {})",
|
||||||
|
p_file.GetPath(),
|
||||||
|
m_header.m_magic,
|
||||||
|
SasquatchHeader::MAGIC);
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler,
|
||||||
|
m_header.m_version == SasquatchHeader::VERSION,
|
||||||
|
"Sasquatch file {} has an unsupported version (got {} / expected {})",
|
||||||
|
p_file.GetPath(),
|
||||||
|
m_header.m_version,
|
||||||
|
SasquatchHeader::VERSION);
|
||||||
|
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler,
|
||||||
|
data.size() >= sizeof(SasquatchHeader) + (m_header.m_assetCount * sizeof(SasquatchEntry)),
|
||||||
|
"Sasquatch file {} index is truncated (got {} / expected at least {})",
|
||||||
|
p_file.GetPath(),
|
||||||
|
data.size(),
|
||||||
|
sizeof(SasquatchHeader) + (m_header.m_assetCount * sizeof(SasquatchEntry)));
|
||||||
|
|
||||||
|
eastl::vector<SasquatchEntry> entries(m_header.m_assetCount);
|
||||||
|
if (!entries.empty())
|
||||||
|
{
|
||||||
|
std::memcpy(entries.data(), data.data() + sizeof(SasquatchHeader), entries.size() * sizeof(SasquatchEntry));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_entries.reserve(m_header.m_assetCount);
|
||||||
|
for (const SasquatchEntry& entry: entries)
|
||||||
|
{
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler,
|
||||||
|
entry.m_assetOffset + entry.m_assetSize + entry.m_hardReferencesSize <= data.size(),
|
||||||
|
"Sasquatch file {} has an out-of-bounds asset entry",
|
||||||
|
p_file.GetPath());
|
||||||
|
|
||||||
|
m_entries.emplace(UUID {entry.m_uuid},
|
||||||
|
Entry {.m_assetOffset = entry.m_assetOffset,
|
||||||
|
.m_assetSize = entry.m_assetSize,
|
||||||
|
.m_hardReferencesOffset = entry.m_hardReferencesOffset,
|
||||||
|
.m_hardReferencesSize = entry.m_hardReferencesSize});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
const SasquatchHeader& Sasquatch::GetHeader() const
|
||||||
|
{
|
||||||
|
return m_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::vector<std::byte> Sasquatch::GetAssetFlatbuffer(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
const auto entryIt = m_entries.find(p_uuid);
|
||||||
|
if (entryIt == m_entries.end())
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const eastl::span<const std::byte> data = m_file.GetData();
|
||||||
|
const eastl::span<const std::byte> bytes {data.data() + entryIt->second.m_assetOffset,
|
||||||
|
static_cast<std::size_t>(entryIt->second.m_assetSize)};
|
||||||
|
return eastl::vector<std::byte> {bytes.begin(), bytes.end()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::vector<eastl::vector<std::byte>> Sasquatch::GetAssetFlatbuffers(const eastl::span<const UUID> p_uuids) const
|
||||||
|
{
|
||||||
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
|
flatbuffers.reserve(p_uuids.size());
|
||||||
|
|
||||||
|
for (const UUID& uuid: p_uuids)
|
||||||
|
{
|
||||||
|
flatbuffers.push_back(GetAssetFlatbuffer(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
return flatbuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::vector<UUID> Sasquatch::GetAssetHardReferences(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
eastl::vector<UUID> hardReferences;
|
||||||
|
|
||||||
|
const auto entryIt = m_entries.find(p_uuid);
|
||||||
|
if (entryIt == m_entries.end())
|
||||||
|
{
|
||||||
|
return hardReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
const eastl::span<const std::byte> data = m_file.GetData();
|
||||||
|
const eastl::span<const std::byte> bytes {data.data() + entryIt->second.m_hardReferencesOffset,
|
||||||
|
static_cast<std::size_t>(entryIt->second.m_hardReferencesSize)};
|
||||||
|
|
||||||
|
const std::size_t hardReferenceCount = bytes.size() / UUID::UUID_BYTE_SIZE;
|
||||||
|
hardReferences.reserve(hardReferenceCount);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < hardReferenceCount; ++i)
|
||||||
|
{
|
||||||
|
std::array<std::byte, UUID::UUID_BYTE_SIZE> rawUUID;
|
||||||
|
std::memcpy(rawUUID.data(), bytes.data() + (i * UUID::UUID_BYTE_SIZE), UUID::UUID_BYTE_SIZE);
|
||||||
|
hardReferences.emplace_back(rawUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hardReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
eastl::vector<eastl::vector<UUID>> Sasquatch::GetAssetsHardReferences(eastl::span<const UUID> p_uuids) const
|
||||||
|
{
|
||||||
|
eastl::vector<eastl::vector<UUID>> hardReferences;
|
||||||
|
hardReferences.reserve(p_uuids.size());
|
||||||
|
|
||||||
|
for (const UUID& uuid: p_uuids)
|
||||||
|
{
|
||||||
|
hardReferences.push_back(GetAssetHardReferences(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
return hardReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void Sasquatch::SaveAssetFlatbuffer([[maybe_unused]] const UUID& p_uuid,
|
||||||
|
[[maybe_unused]] eastl::span<const std::byte> p_flatbuffer,
|
||||||
|
[[maybe_unused]] eastl::span<const UUID> p_hardReferences)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler, false, "Sasquatch is read-only, it cannot save assets");
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void Sasquatch::SaveAssetFlatbuffers([[maybe_unused]] const eastl::span<const UUID> p_uuids,
|
||||||
|
[[maybe_unused]] eastl::span<const eastl::vector<std::byte>> p_flatbuffers,
|
||||||
|
[[maybe_unused]] eastl::span<const eastl::vector<UUID>> p_hardReferences)
|
||||||
|
{
|
||||||
|
ASSERT(EngineAssertHandler, false, "Sasquatch is read-only, it cannot save assets");
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
bool Sasquatch::Has(const UUID& p_uuid) const
|
||||||
|
{
|
||||||
|
return m_entries.contains(p_uuid);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -0,0 +1,249 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file SerializationManager.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Engine/SerializationManager/SerializationManager.hpp>
|
||||||
|
|
||||||
|
#include <Engine/Asset/AssetLibrary.hpp>
|
||||||
|
#include <Engine/DataAccessor/DataAccessor.hpp>
|
||||||
|
|
||||||
|
#include <Utils/Algorithm/Graph.hpp>
|
||||||
|
|
||||||
|
#include <ankerl/unordered_dense.h>
|
||||||
|
|
||||||
|
namespace Bigfoot::SerializationManager
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Build the transitive HardReference graph reachable from p_roots
|
||||||
|
*
|
||||||
|
* \param p_roots The assets to start the discovery from
|
||||||
|
* \param p_discovered Every discovered asset that isn't already loaded, including p_roots
|
||||||
|
* \return Every asset's HardReferences
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
ankerl::unordered_dense::map<UUID, eastl::vector<UUID>> BuildDependencyGraph(
|
||||||
|
const eastl::span<const UUID> p_roots,
|
||||||
|
ankerl::unordered_dense::set<UUID>& p_discovered)
|
||||||
|
{
|
||||||
|
ankerl::unordered_dense::map<UUID, eastl::vector<UUID>> graph;
|
||||||
|
|
||||||
|
eastl::vector<UUID> toQuery;
|
||||||
|
toQuery.reserve(p_roots.size());
|
||||||
|
for (const UUID& uuid: p_roots)
|
||||||
|
{
|
||||||
|
if (!g_activeAssetLibrary->IsLoaded(uuid) && p_discovered.insert(uuid).second)
|
||||||
|
{
|
||||||
|
toQuery.push_back(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!toQuery.empty())
|
||||||
|
{
|
||||||
|
eastl::vector<eastl::vector<UUID>> hardReferencesBatch = g_dataAccessor->GetAssetsHardReferences(toQuery);
|
||||||
|
|
||||||
|
eastl::vector<UUID> nextToQuery;
|
||||||
|
for (std::size_t i = 0; i < toQuery.size(); ++i)
|
||||||
|
{
|
||||||
|
eastl::vector<UUID>& hardReferences = graph[toQuery[i]];
|
||||||
|
hardReferences = std::move(hardReferencesBatch[i]);
|
||||||
|
|
||||||
|
for (const UUID& hardReference: hardReferences)
|
||||||
|
{
|
||||||
|
if (!g_activeAssetLibrary->IsLoaded(hardReference) && p_discovered.insert(hardReference).second)
|
||||||
|
{
|
||||||
|
nextToQuery.push_back(hardReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toQuery = std::move(nextToQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void LoadAssets(const eastl::span<const UUID> p_uuids)
|
||||||
|
{
|
||||||
|
ankerl::unordered_dense::set<UUID> discovered;
|
||||||
|
const ankerl::unordered_dense::map<UUID, eastl::vector<UUID>> graph = BuildDependencyGraph(p_uuids, discovered);
|
||||||
|
|
||||||
|
// Assets that are part of a cyclic HardReference dependency are left out of waves and simply never loaded.
|
||||||
|
eastl::vector<eastl::vector<UUID>> waves;
|
||||||
|
eastl::vector<UUID> cyclicUuids;
|
||||||
|
std::ignore = LayeredTopologicalSort(graph, discovered, waves, cyclicUuids);
|
||||||
|
BIGFOOT_LOG_ERROR_IF(!cyclicUuids.empty(),
|
||||||
|
ENGINE_LOGGER,
|
||||||
|
"Cyclic HardReference dependency detected while loading assets, involved UUIDs: {}",
|
||||||
|
cyclicUuids);
|
||||||
|
|
||||||
|
// Waves are loaded one after another since a wave's assets may HardReference the previous wave's; within a
|
||||||
|
// wave, every asset is independent of the others, so this is where loading could later be parallelized.
|
||||||
|
for (const eastl::vector<UUID>& wave: waves)
|
||||||
|
{
|
||||||
|
const eastl::vector<eastl::vector<std::byte>> assetFlatbuffers = g_dataAccessor->GetAssetFlatbuffers(wave);
|
||||||
|
for (std::size_t i = 0; i < wave.size(); ++i)
|
||||||
|
{
|
||||||
|
const eastl::vector<std::byte>& flatbuffer = assetFlatbuffers[i];
|
||||||
|
if (flatbuffer.empty())
|
||||||
|
{
|
||||||
|
BIGFOOT_LOG_ERROR(ENGINE_LOGGER, "Asset {} could not be found while loading, skipping it", wave[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
flatbuffers::Verifier verifier {reinterpret_cast<const std::uint8_t*>(flatbuffer.data()),
|
||||||
|
flatbuffer.size()};
|
||||||
|
const bool assetVerified = ::Flat::Bigfoot::VerifyAssetBuffer(verifier);
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler, assetVerified, "Given asset could not be verified!");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const ::Flat::Bigfoot::Asset* asset = flatbuffers::GetRoot<::Flat::Bigfoot::Asset>(flatbuffer.data());
|
||||||
|
|
||||||
|
AssetContainerBase* container = g_activeAssetLibrary->GetAssetContainer(
|
||||||
|
flatbuffers::UnPack(*asset->header()->type_id()));
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler,
|
||||||
|
container != nullptr,
|
||||||
|
"No AssetContainer registered for asset {}",
|
||||||
|
wave[i]);
|
||||||
|
std::ignore = container->Insert(flatbuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void LoadAsset(const UUID& p_uuid)
|
||||||
|
{
|
||||||
|
LoadAssets(eastl::span<const UUID> {&p_uuid, 1});
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_TOOLMODE
|
||||||
|
/*
|
||||||
|
* Finds the cyclic dependencies that may exist in Assets
|
||||||
|
*
|
||||||
|
* \param p_uuids The assets we want to explore
|
||||||
|
* \param p_hardReferences The HardReferences of p_uuids, matching by index
|
||||||
|
* \return Every UUID caught in a cyclic dependency
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
eastl::vector<UUID> FindCyclicDependencies(const eastl::span<const UUID> p_uuids,
|
||||||
|
const eastl::span<const eastl::vector<UUID>> p_hardReferences)
|
||||||
|
{
|
||||||
|
ankerl::unordered_dense::map<UUID, eastl::vector<UUID>> graph;
|
||||||
|
ankerl::unordered_dense::set<UUID> discovered;
|
||||||
|
|
||||||
|
eastl::vector<UUID> toQuery;
|
||||||
|
for (std::size_t i = 0; i < p_uuids.size(); ++i)
|
||||||
|
{
|
||||||
|
discovered.insert(p_uuids[i]);
|
||||||
|
graph[p_uuids[i]] = p_hardReferences[i];
|
||||||
|
}
|
||||||
|
for (const eastl::vector<UUID>& hardReferences: p_hardReferences)
|
||||||
|
{
|
||||||
|
for (const UUID& hardReference: hardReferences)
|
||||||
|
{
|
||||||
|
if (discovered.insert(hardReference).second)
|
||||||
|
{
|
||||||
|
toQuery.push_back(hardReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!toQuery.empty())
|
||||||
|
{
|
||||||
|
eastl::vector<eastl::vector<UUID>> hardReferencesBatch = g_dataAccessor->GetAssetsHardReferences(toQuery);
|
||||||
|
|
||||||
|
eastl::vector<UUID> nextToQuery;
|
||||||
|
for (std::size_t i = 0; i < toQuery.size(); ++i)
|
||||||
|
{
|
||||||
|
eastl::vector<UUID>& hardReferences = graph[toQuery[i]];
|
||||||
|
hardReferences = std::move(hardReferencesBatch[i]);
|
||||||
|
|
||||||
|
for (const UUID& hardReference: hardReferences)
|
||||||
|
{
|
||||||
|
if (discovered.insert(hardReference).second)
|
||||||
|
{
|
||||||
|
nextToQuery.push_back(hardReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toQuery = std::move(nextToQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<eastl::vector<UUID>> waves;
|
||||||
|
eastl::vector<UUID> cyclicUuids;
|
||||||
|
std::ignore = LayeredTopologicalSort(graph, discovered, waves, cyclicUuids);
|
||||||
|
return cyclicUuids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
bool SaveAsset(const UUID& p_uuid)
|
||||||
|
{
|
||||||
|
AssetContainerBase* container = g_activeAssetLibrary->GetAssetContainer(p_uuid);
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler, container != nullptr, "No AssetContainer registered for asset {}", p_uuid);
|
||||||
|
const AssetBase* asset = container->AcquireContainerHandle(p_uuid)->GetAsset();
|
||||||
|
|
||||||
|
const eastl::vector<std::byte> flatbuffer = asset->Pack();
|
||||||
|
const eastl::vector<UUID> hardReferences = asset->GetHardReferences(flatbuffer);
|
||||||
|
|
||||||
|
const eastl::vector<UUID> cyclicUuids = FindCyclicDependencies(
|
||||||
|
eastl::span<const UUID> {&p_uuid, 1},
|
||||||
|
eastl::span<const eastl::vector<UUID>> {&hardReferences, 1});
|
||||||
|
BIGFOOT_LOG_ERROR_IF(!cyclicUuids.empty(),
|
||||||
|
ENGINE_LOGGER,
|
||||||
|
"Cyclic HardReference dependency detected while saving asset {}, involved UUIDs: {}",
|
||||||
|
p_uuid,
|
||||||
|
cyclicUuids);
|
||||||
|
if (!cyclicUuids.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dataAccessor->SaveAssetFlatbuffer(p_uuid, flatbuffer, hardReferences);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
bool SaveAssets(const eastl::span<const UUID> p_uuids)
|
||||||
|
{
|
||||||
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
|
eastl::vector<eastl::vector<UUID>> hardReferences;
|
||||||
|
|
||||||
|
flatbuffers.reserve(p_uuids.size());
|
||||||
|
hardReferences.reserve(p_uuids.size());
|
||||||
|
for (const UUID& uuid: p_uuids)
|
||||||
|
{
|
||||||
|
AssetContainerBase* container = g_activeAssetLibrary->GetAssetContainer(uuid);
|
||||||
|
CRITICAL_ASSERT(EngineAssertHandler, container != nullptr, "No AssetContainer registered for asset {}", uuid);
|
||||||
|
const AssetBase* asset = container->AcquireContainerHandle(uuid)->GetAsset();
|
||||||
|
|
||||||
|
const eastl::vector<std::byte> flatbuffer = asset->Pack();
|
||||||
|
|
||||||
|
flatbuffers.push_back(flatbuffer);
|
||||||
|
hardReferences.push_back(asset->GetHardReferences(flatbuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
const eastl::vector<UUID> cyclicUuids = FindCyclicDependencies(p_uuids, hardReferences);
|
||||||
|
BIGFOOT_LOG_ERROR_IF(!cyclicUuids.empty(),
|
||||||
|
ENGINE_LOGGER,
|
||||||
|
"Cyclic HardReference dependency detected while saving assets, involved UUIDs: {}",
|
||||||
|
cyclicUuids);
|
||||||
|
if (!cyclicUuids.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dataAccessor->SaveAssetFlatbuffers(p_uuids, flatbuffers, hardReferences);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace Bigfoot::SerializationManager
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include <System/SystemAssertHandler.hpp>
|
#include <System/SystemAssertHandler.hpp>
|
||||||
|
|
||||||
#include <bit>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -83,7 +82,7 @@ eastl::vector<std::byte> File::Read(const std::size_t p_offset, const std::size_
|
|||||||
|
|
||||||
eastl::vector<std::byte> data;
|
eastl::vector<std::byte> data;
|
||||||
data.resize(p_size);
|
data.resize(p_size);
|
||||||
file.read(std::bit_cast<char*>(data.data()), static_cast<std::streamsize>(data.size()));
|
file.read(reinterpret_cast<char*>(data.data()), static_cast<std::streamsize>(data.size()));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +99,7 @@ void File::Write(const eastl::span<const std::byte> p_data, const std::size_t p_
|
|||||||
CRITICAL_ASSERT(SystemAssertHandler, file.is_open(), "Failed to open file {} for writing", path);
|
CRITICAL_ASSERT(SystemAssertHandler, file.is_open(), "Failed to open file {} for writing", path);
|
||||||
|
|
||||||
file.seekp(static_cast<std::streamoff>(p_offset), std::ios::beg);
|
file.seekp(static_cast<std::streamoff>(p_offset), std::ios::beg);
|
||||||
file.write(std::bit_cast<const char*>(p_data.data()), static_cast<std::streamsize>(p_data.size()));
|
file.write(reinterpret_cast<const char*>(p_data.data()), static_cast<std::streamsize>(p_data.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
@@ -112,8 +111,8 @@ void File::Delete() const
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
File::File(const std::filesystem::path& p_path):
|
File::File(std::filesystem::path p_path):
|
||||||
m_path(p_path),
|
m_path(std::move(p_path)),
|
||||||
m_pathString(m_path.string().c_str())
|
m_pathString(m_path.string().c_str())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#if defined BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#elif defined BIGFOOT_LINUX
|
#elif defined BIGFOOT_LINUX
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -26,7 +26,7 @@ MemoryMappedFile::MemoryMappedFile(const File& p_file)
|
|||||||
const File absoluteFile = p_file.ToAbsolute();
|
const File absoluteFile = p_file.ToAbsolute();
|
||||||
const eastl::string_view path = absoluteFile.GetPath();
|
const eastl::string_view path = absoluteFile.GetPath();
|
||||||
|
|
||||||
#if defined BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
m_fileHandle = CreateFileA(path.data(),
|
m_fileHandle = CreateFileA(path.data(),
|
||||||
GENERIC_READ,
|
GENERIC_READ,
|
||||||
FILE_SHARE_READ,
|
FILE_SHARE_READ,
|
||||||
@@ -78,7 +78,7 @@ MemoryMappedFile::MemoryMappedFile(const File& p_file)
|
|||||||
|
|
||||||
MemoryMappedFile::~MemoryMappedFile()
|
MemoryMappedFile::~MemoryMappedFile()
|
||||||
{
|
{
|
||||||
#if defined BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
if (m_data != nullptr)
|
if (m_data != nullptr)
|
||||||
{
|
{
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
@@ -133,7 +133,7 @@ WritableMemoryMappedFile::WritableMemoryMappedFile(const File& p_file, const std
|
|||||||
const File absoluteFile = p_file.ToAbsolute();
|
const File absoluteFile = p_file.ToAbsolute();
|
||||||
const eastl::string_view path = absoluteFile.GetPath();
|
const eastl::string_view path = absoluteFile.GetPath();
|
||||||
|
|
||||||
#if defined BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
m_fileHandle =
|
m_fileHandle =
|
||||||
CreateFileA(path.data(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
CreateFileA(path.data(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
CRITICAL_ASSERT(SystemAssertHandler, m_fileHandle != INVALID_HANDLE_VALUE, "Failed to create file {}", path);
|
CRITICAL_ASSERT(SystemAssertHandler, m_fileHandle != INVALID_HANDLE_VALUE, "Failed to create file {}", path);
|
||||||
@@ -169,7 +169,7 @@ WritableMemoryMappedFile::WritableMemoryMappedFile(const File& p_file, const std
|
|||||||
|
|
||||||
WritableMemoryMappedFile::~WritableMemoryMappedFile()
|
WritableMemoryMappedFile::~WritableMemoryMappedFile()
|
||||||
{
|
{
|
||||||
#if defined BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
if (m_data != nullptr)
|
if (m_data != nullptr)
|
||||||
{
|
{
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
@@ -220,7 +220,7 @@ eastl::span<std::byte> WritableMemoryMappedFile::GetData() const
|
|||||||
|
|
||||||
void WritableMemoryMappedFile::Prefetch(const std::size_t p_offset, const std::size_t p_size) const
|
void WritableMemoryMappedFile::Prefetch(const std::size_t p_offset, const std::size_t p_size) const
|
||||||
{
|
{
|
||||||
#if defined BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
WIN32_MEMORY_RANGE_ENTRY range {.VirtualAddress = m_data + p_offset, .NumberOfBytes = p_size};
|
WIN32_MEMORY_RANGE_ENTRY range {.VirtualAddress = m_data + p_offset, .NumberOfBytes = p_size};
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
const BOOL prefetched = PrefetchVirtualMemory(GetCurrentProcess(), 1, &range, 0);
|
const BOOL prefetched = PrefetchVirtualMemory(GetCurrentProcess(), 1, &range, 0);
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ class File
|
|||||||
*
|
*
|
||||||
* \param p_path The path
|
* \param p_path The path
|
||||||
*/
|
*/
|
||||||
File(const std::filesystem::path& p_path);
|
File(std::filesystem::path p_path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The path
|
* The path
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class MemoryMappedFile
|
|||||||
MemoryMappedFile& operator=(MemoryMappedFile&& p_file) = delete;
|
MemoryMappedFile& operator=(MemoryMappedFile&& p_file) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if defined BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
/**
|
/**
|
||||||
* Handle to the file
|
* Handle to the file
|
||||||
*/
|
*/
|
||||||
@@ -118,7 +118,7 @@ class WritableMemoryMappedFile
|
|||||||
WritableMemoryMappedFile& operator=(WritableMemoryMappedFile&& p_file) = delete;
|
WritableMemoryMappedFile& operator=(WritableMemoryMappedFile&& p_file) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if defined BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
/**
|
/**
|
||||||
* Handle to the file
|
* Handle to the file
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include <Utils/Assert/AssertHandler.hpp>
|
#include <Utils/Assert/AssertHandler.hpp>
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Bigfoot
|
|||||||
/*
|
/*
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
inline Log::LoggerInfo SYSTEM_LOGGER {"SYSTEM_LOGGER", Flat::LogLevel::Trace};
|
inline Log::LoggerInfo SYSTEM_LOGGER { .m_name = "SYSTEM_LOGGER", .m_level = Flat::LogLevel::Trace};
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -65,13 +65,10 @@ class Time
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
namespace Flat
|
namespace Flat::Bigfoot
|
||||||
{
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
{
|
||||||
struct Time;
|
struct Time;
|
||||||
}
|
} // namespace Flat::Bigfoot
|
||||||
} // namespace Flat
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#ifndef BIGFOOT_SYSTEM_UUID_UUID_HPP
|
#ifndef BIGFOOT_SYSTEM_UUID_UUID_HPP
|
||||||
#define BIGFOOT_SYSTEM_UUID_UUID_HPP
|
#define BIGFOOT_SYSTEM_UUID_UUID_HPP
|
||||||
|
#include <EASTL/string.h>
|
||||||
#include <ankerl/unordered_dense.h>
|
#include <ankerl/unordered_dense.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <uuid.h>
|
#include <uuid.h>
|
||||||
@@ -52,7 +53,7 @@ class UUID
|
|||||||
* \return A string representing the UUID
|
* \return A string representing the UUID
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::string ToString() const;
|
eastl::string ToString() const;
|
||||||
|
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
|
|
||||||
@@ -120,33 +121,33 @@ struct std::hash<Bigfoot::UUID>
|
|||||||
template<>
|
template<>
|
||||||
struct fmt::formatter<Bigfoot::UUID>
|
struct fmt::formatter<Bigfoot::UUID>
|
||||||
{
|
{
|
||||||
constexpr auto parse(format_parse_context& ctx)
|
static constexpr auto parse(format_parse_context& ctx)
|
||||||
{
|
{
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto format(const Bigfoot::UUID& p_uuid, format_context& ctx) const
|
static auto format(const Bigfoot::UUID& p_uuid, format_context& ctx)
|
||||||
{
|
{
|
||||||
return fmt::format_to(ctx.out(), "{}", p_uuid.ToString());
|
return fmt::format_to(ctx.out(), "{}", p_uuid.ToString().c_str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
#include <quill/DeferredFormatCodec.h>
|
#include <quill/DeferredFormatCodec.h>
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct fmtquill::formatter<Bigfoot::UUID>
|
struct fmtquill::formatter<Bigfoot::UUID>
|
||||||
{
|
{
|
||||||
constexpr auto parse(format_parse_context& ctx)
|
static constexpr auto parse(format_parse_context& ctx)
|
||||||
{
|
{
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto format(const Bigfoot::UUID& p_uuid, format_context& ctx) const
|
static auto format(const Bigfoot::UUID& p_uuid, format_context& ctx)
|
||||||
{
|
{
|
||||||
return fmtquill::format_to(ctx.out(), "{}", p_uuid.ToString());
|
return fmtquill::format_to(ctx.out(), "{}", p_uuid.ToString().c_str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -158,13 +159,10 @@ struct quill::Codec<Bigfoot::UUID>: quill::DeferredFormatCodec<Bigfoot::UUID>
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
namespace Flat
|
namespace Flat::Bigfoot
|
||||||
{
|
|
||||||
namespace Bigfoot
|
|
||||||
{
|
{
|
||||||
struct UUID;
|
struct UUID;
|
||||||
}
|
} // namespace Flat::Bigfoot
|
||||||
} // namespace Flat
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ Time::Time(const std::uint64_t p_epoch):
|
|||||||
|
|
||||||
std::uint32_t Time::GetYear() const
|
std::uint32_t Time::GetYear() const
|
||||||
{
|
{
|
||||||
return m_timeInfo.tm_year + 1900;
|
constexpr std::uint32_t TM_YEAR_EPOCH = 1900;
|
||||||
|
return m_timeInfo.tm_year + TM_YEAR_EPOCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ UUID::UUID(const std::string_view p_string):
|
|||||||
UUID::UUID(const std::span<const std::byte, UUID_BYTE_SIZE> p_raw)
|
UUID::UUID(const std::span<const std::byte, UUID_BYTE_SIZE> p_raw)
|
||||||
{
|
{
|
||||||
const std::span<std::uint8_t, UUID_BYTE_SIZE> raw {
|
const std::span<std::uint8_t, UUID_BYTE_SIZE> raw {
|
||||||
const_cast<std::uint8_t*>(std::bit_cast<const std::uint8_t*>(p_raw.data())),
|
const_cast<std::uint8_t*>(reinterpret_cast<const std::uint8_t*>(p_raw.data())),
|
||||||
UUID_BYTE_SIZE};
|
UUID_BYTE_SIZE};
|
||||||
|
|
||||||
m_uuid = uuids::uuid {raw};
|
m_uuid = uuids::uuid {raw};
|
||||||
@@ -50,9 +50,10 @@ std::span<const std::byte, UUID::UUID_BYTE_SIZE> UUID::ToBytes() const
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
std::string UUID::ToString() const
|
eastl::string UUID::ToString() const
|
||||||
{
|
{
|
||||||
return uuids::to_string(m_uuid);
|
const std::string uuid = uuids::to_string(m_uuid);
|
||||||
|
return eastl::string {uuid.data(), uuid.size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/SasquatchBaker)
|
||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Executables/SasquatchBaker)
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
project(SasquatchBakerCLI)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME})
|
||||||
|
|
||||||
|
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
PRIVATE
|
||||||
|
BigfootCompileAndLinkFlags
|
||||||
|
bfg::lyra
|
||||||
|
$<LINK_LIBRARY:WHOLE_ARCHIVE,SasquatchBaker>)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(${PROJECT_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${_SOURCES}
|
||||||
|
${_HEADERS}
|
||||||
|
)
|
||||||
|
|
||||||
|
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src FILES ${_SOURCES} ${_HEADERS})
|
||||||
|
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Bigfoot/Tools/Executables)
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME SasquatchBaker)
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file main.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <System/File/File.hpp>
|
||||||
|
|
||||||
|
#include <Utils/Log/LogMacros.hpp>
|
||||||
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
|
#include <SasquatchBaker/SasquatchBaker.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/string_view.h>
|
||||||
|
#include <lyra/lyra.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime logLifetime);
|
||||||
|
|
||||||
|
bool showHelp = false;
|
||||||
|
std::string bigFilePath;
|
||||||
|
std::string outputPath;
|
||||||
|
|
||||||
|
const auto& cli = lyra::help(showHelp) |
|
||||||
|
lyra::opt(bigFilePath, "bigfile")["-b"]["--bigfile"]("The BigFile to bake (must exist)")
|
||||||
|
.required() |
|
||||||
|
lyra::opt(outputPath, "output")["-o"]["--output"]("The Sasquatch file to write").required();
|
||||||
|
|
||||||
|
const lyra::parse_result result = cli.parse({argc, argv});
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
std::cerr << result.message() << "\n\n" << cli << '\n';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showHelp)
|
||||||
|
{
|
||||||
|
std::cout << cli << '\n';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Bigfoot::BigFile bigFile {Bigfoot::File {eastl::string_view {bigFilePath.c_str()}}};
|
||||||
|
Bigfoot::Bake(bigFile, Bigfoot::File {eastl::string_view {outputPath.c_str()}});
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
project(${PackageName})
|
||||||
|
|
||||||
|
set(PublicDependencies)
|
||||||
|
set(PrivateDependencies)
|
||||||
|
set(BigfootPublicDependencies
|
||||||
|
Engine)
|
||||||
|
set(BigfootPrivateDependencies
|
||||||
|
Utils)
|
||||||
|
|
||||||
|
bigfoot_create_package_lib(
|
||||||
|
"${PublicDependencies}"
|
||||||
|
"${PrivateDependencies}"
|
||||||
|
"${BigfootPublicDependencies}"
|
||||||
|
"${BigfootPrivateDependencies}"
|
||||||
|
"Tools")
|
||||||
|
|
||||||
|
bigfoot_create_logger()
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file SasquatchBaker.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_TOOLS_SASQUATCHBAKER_SASQUATCHBAKER_HPP
|
||||||
|
#define BIGFOOT_TOOLS_SASQUATCHBAKER_SASQUATCHBAKER_HPP
|
||||||
|
#include <Engine/BigFile/BigFile.hpp>
|
||||||
|
|
||||||
|
#include <System/File/File.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bake every Asset of a BigFile into a Sasquatch file
|
||||||
|
*
|
||||||
|
* \param p_bigFile The BigFile to bake
|
||||||
|
* \param p_outputFile The file to write to
|
||||||
|
*/
|
||||||
|
void Bake(const BigFile& p_bigFile, const File& p_outputFile);
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file SasquatchBakerAssertHandler.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_TOOLS_SASQUATCHBAKER_SASQUATCHBAKERASSERTHANDLER_HPP
|
||||||
|
#define BIGFOOT_TOOLS_SASQUATCHBAKER_SASQUATCHBAKERASSERTHANDLER_HPP
|
||||||
|
#include <Utils/Assert/AssertHandler.hpp>
|
||||||
|
|
||||||
|
#include <SasquatchBaker/SasquatchBakerLogger_generated.hpp>
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
using SasquatchBakerAssertHandler = AssertHandler<SASQUATCHBAKER_LOGGER>;
|
||||||
|
} // namespace Bigfoot
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
// AUTO-GENERATED DO NOT TOUCH
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* \file SasquatchBakerLogger.generated.hpp
|
||||||
|
*
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_SASQUATCHBAKERLOGGER_GENERATED_HPP
|
||||||
|
#define BIGFOOT_SASQUATCHBAKERLOGGER_GENERATED_HPP
|
||||||
|
#include <Utils/Log/LogMacros.hpp>
|
||||||
|
|
||||||
|
#if defined BIGFOOT_NOT_OPTIMIZED
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Logger
|
||||||
|
*/
|
||||||
|
inline Log::LoggerInfo SASQUATCHBAKER_LOGGER { .m_name = "SASQUATCHBAKER_LOGGER", .m_level = Flat::LogLevel::Trace};
|
||||||
|
} // namespace Bigfoot
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file SasquatchBaker.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <SasquatchBaker/SasquatchBaker.hpp>
|
||||||
|
|
||||||
|
#include <Engine/Sasquatch/Sasquatch.hpp>
|
||||||
|
|
||||||
|
#include <SasquatchBaker/SasquatchBakerAssertHandler.hpp>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
void Bake(const BigFile& p_bigFile, const File& p_outputFile)
|
||||||
|
{
|
||||||
|
std::uint64_t assetCount = 0;
|
||||||
|
{
|
||||||
|
BigFile::Request countRequest {p_bigFile, "SELECT COUNT(*) FROM Asset;"};
|
||||||
|
[[maybe_unused]]
|
||||||
|
const bool hasCount = countRequest.Step();
|
||||||
|
ASSERT(SasquatchBakerAssertHandler, hasCount, "Failed to count the assets of the BigFile");
|
||||||
|
assetCount = countRequest.Get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t totalFlatbufferBytes = 0;
|
||||||
|
{
|
||||||
|
BigFile::Request sizeRequest {p_bigFile, "SELECT COALESCE(SUM(LENGTH(Asset)), 0) FROM Asset;"};
|
||||||
|
[[maybe_unused]]
|
||||||
|
const bool hasSize = sizeRequest.Step();
|
||||||
|
ASSERT(SasquatchBakerAssertHandler, hasSize, "Failed to sum the asset sizes of the BigFile");
|
||||||
|
totalFlatbufferBytes = sizeRequest.Get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t totalHardReferencesBytes = 0;
|
||||||
|
{
|
||||||
|
BigFile::Request sizeRequest {p_bigFile,
|
||||||
|
"SELECT COALESCE(SUM(LENGTH(HardReference)), 0) FROM AssetHardReference;"};
|
||||||
|
[[maybe_unused]]
|
||||||
|
const bool hasSize = sizeRequest.Step();
|
||||||
|
ASSERT(SasquatchBakerAssertHandler, hasSize, "Failed to sum the hardreferences sizes of the BigFile");
|
||||||
|
totalHardReferencesBytes = sizeRequest.Get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SasquatchWriter writer {p_outputFile, assetCount, totalFlatbufferBytes, totalHardReferencesBytes};
|
||||||
|
|
||||||
|
BigFile::Request request {p_bigFile, "SELECT UUID FROM Asset;"};
|
||||||
|
while (request.Step())
|
||||||
|
{
|
||||||
|
const std::span<const std::byte> rawUUID = request.Get(0);
|
||||||
|
|
||||||
|
ASSERT(SasquatchBakerAssertHandler,
|
||||||
|
rawUUID.size() == UUID::UUID_BYTE_SIZE,
|
||||||
|
"Unexpected UUID blob size in BigFile (got {} / expected {})",
|
||||||
|
rawUUID.size(),
|
||||||
|
UUID::UUID_BYTE_SIZE);
|
||||||
|
|
||||||
|
const UUID uuid {std::span<const std::byte, UUID::UUID_BYTE_SIZE> {rawUUID.data(), UUID::UUID_BYTE_SIZE}};
|
||||||
|
const eastl::vector<std::byte> flatbuffer = p_bigFile.GetAssetFlatbuffer(uuid);
|
||||||
|
const eastl::vector<UUID> hardReferences = p_bigFile.GetAssetHardReferences(uuid);
|
||||||
|
|
||||||
|
writer.WriteAsset(uuid, flatbuffer, hardReferences);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file Graph.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_UTILS_ALGORITHM_GRAPH_HPP
|
||||||
|
#define BIGFOOT_UTILS_ALGORITHM_GRAPH_HPP
|
||||||
|
#include <Utils/UtilsAssertHandler.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
#include <ankerl/unordered_dense.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Kahn's algorithm
|
||||||
|
*
|
||||||
|
* \param p_graph Every discovered node's outgoing edges (eg: its dependencies)
|
||||||
|
* \param p_nodes The set of nodes to sort
|
||||||
|
* \param p_waves The sorted nodes
|
||||||
|
* \param p_cyclicNodes Nodes that could not be sorted (ie: part of a cycle)
|
||||||
|
* \return True if a cycle was found
|
||||||
|
*/
|
||||||
|
template<class NODE_TYPE>
|
||||||
|
[[nodiscard]]
|
||||||
|
bool LayeredTopologicalSort(const ankerl::unordered_dense::map<NODE_TYPE, eastl::vector<NODE_TYPE>>& p_graph,
|
||||||
|
const ankerl::unordered_dense::set<NODE_TYPE>& p_nodes,
|
||||||
|
eastl::vector<eastl::vector<NODE_TYPE>>& p_waves,
|
||||||
|
eastl::vector<NODE_TYPE>& p_cyclicNodes)
|
||||||
|
{
|
||||||
|
ASSERT(UtilsAssertHandler, p_waves.empty(), "p_waves must be empty");
|
||||||
|
ASSERT(UtilsAssertHandler, p_cyclicNodes.empty(), "p_cyclicNodes must be empty");
|
||||||
|
ASSERT(UtilsAssertHandler,
|
||||||
|
p_nodes.size() <= std::numeric_limits<std::uint32_t>::max(),
|
||||||
|
"Can't sort more than {} nodes",
|
||||||
|
std::numeric_limits<std::uint32_t>::max());
|
||||||
|
|
||||||
|
const auto nodeCount = static_cast<std::uint32_t>(p_nodes.size());
|
||||||
|
|
||||||
|
ankerl::unordered_dense::map<NODE_TYPE, std::uint32_t> nodeToIndex;
|
||||||
|
nodeToIndex.reserve(nodeCount);
|
||||||
|
eastl::vector<NODE_TYPE> indexToNode;
|
||||||
|
indexToNode.reserve(nodeCount);
|
||||||
|
for (const NODE_TYPE& node: p_nodes)
|
||||||
|
{
|
||||||
|
nodeToIndex.emplace(node, static_cast<std::uint32_t>(indexToNode.size()));
|
||||||
|
indexToNode.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 1: Compute in-degree for each node
|
||||||
|
eastl::vector<std::uint32_t> inDegree(nodeCount, 0);
|
||||||
|
|
||||||
|
// Reverse adjacency (which nodes depend on each node) stored as CSR: adjacencyOffsets[i]..adjacencyOffsets[i + 1]
|
||||||
|
// is node i's slice of adjacency. Built in two passes (count listeners per node, then fill) so the whole
|
||||||
|
// structure is a couple of flat allocations instead of one per node.
|
||||||
|
eastl::vector<std::uint32_t> adjacencyOffsets(nodeCount + 1, 0);
|
||||||
|
|
||||||
|
// Initialize queue with nodes having in-degree 0
|
||||||
|
eastl::vector<std::uint32_t> queue;
|
||||||
|
queue.reserve(nodeCount);
|
||||||
|
for (std::uint32_t index = 0; index < nodeCount; ++index)
|
||||||
|
{
|
||||||
|
std::uint32_t degree = 0;
|
||||||
|
for (const NODE_TYPE& edge: p_graph.at(indexToNode[index]))
|
||||||
|
{
|
||||||
|
const auto nodeIt = nodeToIndex.find(edge);
|
||||||
|
if (nodeIt != nodeToIndex.end())
|
||||||
|
{
|
||||||
|
++degree;
|
||||||
|
++adjacencyOffsets[nodeIt->second + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inDegree[index] = degree;
|
||||||
|
if (degree == 0)
|
||||||
|
{
|
||||||
|
queue.push_back(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::uint32_t index = 0; index < nodeCount; ++index)
|
||||||
|
{
|
||||||
|
adjacencyOffsets[index + 1] += adjacencyOffsets[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<std::uint32_t> adjacency(adjacencyOffsets.back());
|
||||||
|
eastl::vector<std::uint32_t> cursor(adjacencyOffsets.begin(), adjacencyOffsets.end() - 1);
|
||||||
|
for (std::uint32_t index = 0; index < nodeCount; ++index)
|
||||||
|
{
|
||||||
|
for (const NODE_TYPE& edge: p_graph.at(indexToNode[index]))
|
||||||
|
{
|
||||||
|
const auto nodeIt = nodeToIndex.find(edge);
|
||||||
|
if (nodeIt != nodeToIndex.end())
|
||||||
|
{
|
||||||
|
adjacency[cursor[nodeIt->second]++] = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Process nodes
|
||||||
|
std::size_t resolvedCount = 0;
|
||||||
|
eastl::vector<std::uint32_t> nextQueue;
|
||||||
|
nextQueue.reserve(nodeCount);
|
||||||
|
while (!queue.empty())
|
||||||
|
{
|
||||||
|
resolvedCount += queue.size();
|
||||||
|
|
||||||
|
// Reduce in-degree for neighbors
|
||||||
|
nextQueue.clear();
|
||||||
|
for (const std::uint32_t index: queue)
|
||||||
|
{
|
||||||
|
for (std::uint32_t i = adjacencyOffsets[index]; i < adjacencyOffsets[index + 1]; ++i)
|
||||||
|
{
|
||||||
|
const std::uint32_t next = adjacency[i];
|
||||||
|
if (--inDegree[next] == 0)
|
||||||
|
{
|
||||||
|
nextQueue.push_back(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eastl::vector<NODE_TYPE> waveNodes;
|
||||||
|
waveNodes.reserve(queue.size());
|
||||||
|
for (const std::uint32_t index: queue)
|
||||||
|
{
|
||||||
|
waveNodes.push_back(indexToNode[index]);
|
||||||
|
}
|
||||||
|
p_waves.push_back(std::move(waveNodes));
|
||||||
|
|
||||||
|
queue.swap(nextQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3 & 4: Check for valid topological order
|
||||||
|
if (resolvedCount != nodeCount)
|
||||||
|
{
|
||||||
|
p_cyclicNodes.reserve(nodeCount - resolvedCount);
|
||||||
|
for (std::uint32_t index = 0; index < nodeCount; ++index)
|
||||||
|
{
|
||||||
|
if (inDegree[index] != 0)
|
||||||
|
{
|
||||||
|
p_cyclicNodes.push_back(indexToNode[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedCount != nodeCount;
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,26 +7,23 @@
|
|||||||
#ifndef BIGFOOT_UTILS_ASSERT_HPP
|
#ifndef BIGFOOT_UTILS_ASSERT_HPP
|
||||||
#define BIGFOOT_UTILS_ASSERT_HPP
|
#define BIGFOOT_UTILS_ASSERT_HPP
|
||||||
#include <Utils/Log/LogMacros.hpp>
|
#include <Utils/Log/LogMacros.hpp>
|
||||||
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
|
||||||
|
#include <Utils/Format.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/fixed_function.h>
|
||||||
|
#include <EASTL/string.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#if defined BIGFOOT_LINUX
|
#ifdef BIGFOOT_LINUX
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BIGFOOT_FLUSH_LOG \
|
#ifdef BIGFOOT_WINDOWS
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
if (Bigfoot::Singleton<Bigfoot::Log>::HasInstance()) \
|
|
||||||
{ \
|
|
||||||
Bigfoot::Singleton<Bigfoot::Log>::GetInstance().Flush(); \
|
|
||||||
} \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#if defined BIGFOOT_WINDOWS
|
|
||||||
#define BREAK \
|
#define BREAK \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
@@ -42,39 +39,68 @@
|
|||||||
} while (false)
|
} while (false)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Assert then break
|
||||||
|
*
|
||||||
|
* \param p_condition The condition to check
|
||||||
|
* \param p_message A function that will return the formatting string describing the issue
|
||||||
|
* \param p_location The location the assert originates from
|
||||||
|
*/
|
||||||
|
template<typename HANDLER>
|
||||||
|
BIGFOOT_ALWAYS_INLINE void AssertCheck(const bool p_condition,
|
||||||
|
const eastl::fixed_function<32, eastl::string()>& p_messageFn,
|
||||||
|
const std::source_location p_location = std::source_location::current())
|
||||||
|
{
|
||||||
|
if (!p_condition) [[unlikely]]
|
||||||
|
{
|
||||||
|
HANDLER::Handle(p_location, p_messageFn());
|
||||||
|
BREAK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert then break then kill
|
||||||
|
*
|
||||||
|
* \param p_condition The condition to check
|
||||||
|
* \param p_message A function that will return the formatting string describing the issue
|
||||||
|
* \param p_location The location the assert originates from
|
||||||
|
*/
|
||||||
|
template<typename HANDLER>
|
||||||
|
BIGFOOT_ALWAYS_INLINE void CriticalAssertCheck(const bool p_condition,
|
||||||
|
const eastl::fixed_function<32, eastl::string()>& p_messageFn,
|
||||||
|
const std::source_location p_location = std::source_location::current())
|
||||||
|
{
|
||||||
|
if (!p_condition) [[unlikely]]
|
||||||
|
{
|
||||||
|
HANDLER::Handle(p_location, p_messageFn());
|
||||||
|
BREAK;
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
|
|
||||||
#define ASSERT(HANDLER, p_assert, p_message, ...) \
|
#define ASSERT(HANDLER, p_assert, p_message, ...) \
|
||||||
do \
|
::Bigfoot::AssertCheck<HANDLER>((p_assert), \
|
||||||
{ \
|
[&] \
|
||||||
constexpr std::source_location location = std::source_location::current(); \
|
{ \
|
||||||
if (!(p_assert)) [[unlikely]] \
|
return ::Bigfoot::Format(p_message __VA_OPT__(, ) __VA_ARGS__); \
|
||||||
{ \
|
})
|
||||||
HANDLER::Handle(location, p_message __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
BREAK; \
|
|
||||||
} \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define SOFT_ASSERT(HANDLER, p_assert, p_message, ...) \
|
#define SOFT_ASSERT(HANDLER, p_assert, p_message, ...) \
|
||||||
do \
|
::Bigfoot::AssertCheck<HANDLER>((p_assert), \
|
||||||
{ \
|
[&] \
|
||||||
constexpr std::source_location location = std::source_location::current(); \
|
{ \
|
||||||
if (!(p_assert)) [[unlikely]] \
|
return ::Bigfoot::Format(p_message __VA_OPT__(, ) __VA_ARGS__); \
|
||||||
{ \
|
})
|
||||||
HANDLER::Handle(location, p_message __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
BREAK; \
|
|
||||||
} \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define CRITICAL_ASSERT(HANDLER, p_assert, p_message, ...) \
|
#define CRITICAL_ASSERT(HANDLER, p_assert, p_message, ...) \
|
||||||
do \
|
::Bigfoot::CriticalAssertCheck<HANDLER>((p_assert), \
|
||||||
{ \
|
[&] \
|
||||||
constexpr std::source_location location = std::source_location::current(); \
|
{ \
|
||||||
if (!(p_assert)) [[unlikely]] \
|
return ::Bigfoot::Format(p_message __VA_OPT__(, ) __VA_ARGS__); \
|
||||||
{ \
|
})
|
||||||
HANDLER::Handle(location, p_message __VA_OPT__(, ) __VA_ARGS__); \
|
|
||||||
BREAK; \
|
|
||||||
std::abort(); \
|
|
||||||
} \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define ASSERT(HANDLER, p_assert, p_message, ...)
|
#define ASSERT(HANDLER, p_assert, p_message, ...)
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
#include <Utils/Assert/Assert.hpp>
|
#include <Utils/Assert/Assert.hpp>
|
||||||
#include <Utils/Log/Log.hpp>
|
#include <Utils/Log/Log.hpp>
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <EASTL/string.h>
|
||||||
|
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
|
|
||||||
@@ -32,15 +32,13 @@ class AssertHandler
|
|||||||
* Handle an assertion.
|
* Handle an assertion.
|
||||||
*
|
*
|
||||||
* \param p_location Location of the assertion.
|
* \param p_location Location of the assertion.
|
||||||
* \param p_format Format string for the assertion message.
|
* \param p_message Message describing the assertion failure.
|
||||||
* \param p_args Arguments for the format string.
|
|
||||||
*/
|
*/
|
||||||
template<typename... ARGS>
|
static void Handle(const std::source_location& p_location, const eastl::string& p_message)
|
||||||
static void Handle(const std::source_location& p_location, fmt::format_string<ARGS...> p_format, ARGS&&... p_args)
|
|
||||||
{
|
{
|
||||||
BIGFOOT_LOG_FATAL(LOGGER,
|
BIGFOOT_LOG_FATAL(LOGGER,
|
||||||
"Assert: {} (File:{}, Line:{}, Function:{}\n",
|
"Assert: {} (File:{}, Line:{}, Function:{}\n",
|
||||||
fmt::format(p_format, std::forward<ARGS>(p_args)...),
|
p_message,
|
||||||
p_location.file_name(),
|
p_location.file_name(),
|
||||||
p_location.line(),
|
p_location.line(),
|
||||||
p_location.function_name());
|
p_location.function_name());
|
||||||
|
|||||||
@@ -6,37 +6,33 @@
|
|||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#ifndef BIGFOOT_UTILS_CASTER_HPP
|
#ifndef BIGFOOT_UTILS_CASTER_HPP
|
||||||
#define BIGFOOT_UTILS_CASTER_HPP
|
#define BIGFOOT_UTILS_CASTER_HPP
|
||||||
#include <EASTL/type_traits.h>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
template<class TO,
|
template<class TO, class FROM>
|
||||||
class FROM,
|
requires(std::is_base_of_v<FROM, TO> || std::is_base_of_v<TO, FROM>)
|
||||||
eastl::enable_if_t<eastl::is_base_of_v<FROM, TO> || eastl::is_base_of_v<TO, FROM>, bool> = true>
|
|
||||||
constexpr TO* Cast(FROM* p_object)
|
constexpr TO* Cast(FROM* p_object)
|
||||||
{
|
{
|
||||||
return static_cast<TO*>(p_object);
|
return static_cast<TO*>(p_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class TO,
|
template<class TO, class FROM>
|
||||||
class FROM,
|
requires(std::is_base_of_v<FROM, TO> || std::is_base_of_v<TO, FROM>)
|
||||||
eastl::enable_if_t<eastl::is_base_of_v<FROM, TO> || eastl::is_base_of_v<TO, FROM>, bool> = true>
|
|
||||||
constexpr const TO* Cast(const FROM* p_object)
|
constexpr const TO* Cast(const FROM* p_object)
|
||||||
{
|
{
|
||||||
return static_cast<const TO*>(p_object);
|
return static_cast<const TO*>(p_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class TO,
|
template<class TO, class FROM>
|
||||||
class FROM,
|
requires(std::is_base_of_v<FROM, TO> || std::is_base_of_v<TO, FROM>)
|
||||||
eastl::enable_if_t<eastl::is_base_of_v<FROM, TO> || eastl::is_base_of_v<TO, FROM>, bool> = true>
|
|
||||||
constexpr TO& Cast(FROM& p_object)
|
constexpr TO& Cast(FROM& p_object)
|
||||||
{
|
{
|
||||||
return static_cast<TO&>(p_object);
|
return static_cast<TO&>(p_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class TO,
|
template<class TO, class FROM>
|
||||||
class FROM,
|
requires(std::is_base_of_v<FROM, TO> || std::is_base_of_v<TO, FROM>)
|
||||||
eastl::enable_if_t<eastl::is_base_of_v<FROM, TO> || eastl::is_base_of_v<TO, FROM>, bool> = true>
|
|
||||||
constexpr const TO& Cast(const FROM& p_object)
|
constexpr const TO& Cast(const FROM& p_object)
|
||||||
{
|
{
|
||||||
return static_cast<const TO&>(p_object);
|
return static_cast<const TO&>(p_object);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class SlotMapKey
|
|||||||
private:
|
private:
|
||||||
static constexpr std::uint32_t VERSION_BIT_COUNT = sizeof(VersionType) * std::numeric_limits<unsigned char>::digits;
|
static constexpr std::uint32_t VERSION_BIT_COUNT = sizeof(VersionType) * std::numeric_limits<unsigned char>::digits;
|
||||||
static constexpr std::uint32_t INDEX_BIT_COUNT = sizeof(IndexType) * std::numeric_limits<unsigned char>::digits;
|
static constexpr std::uint32_t INDEX_BIT_COUNT = sizeof(IndexType) * std::numeric_limits<unsigned char>::digits;
|
||||||
static_assert(VERSION_BIT_COUNT + INDEX_BIT_COUNT <= 64,
|
static_assert(VERSION_BIT_COUNT + INDEX_BIT_COUNT <= std::numeric_limits<std::uint64_t>::digits,
|
||||||
"We cant construct a 64 bit key from the given Version and Index types!");
|
"We cant construct a 64 bit key from the given Version and Index types!");
|
||||||
|
|
||||||
static constexpr std::uint64_t INDEX_MASK = (static_cast<std::uint64_t>(1) << INDEX_BIT_COUNT) - 1;
|
static constexpr std::uint64_t INDEX_MASK = (static_cast<std::uint64_t>(1) << INDEX_BIT_COUNT) - 1;
|
||||||
@@ -115,10 +115,10 @@ class DenseSlotMap
|
|||||||
public:
|
public:
|
||||||
using SlotMapKey = SLOT_MAP_KEY_TYPE;
|
using SlotMapKey = SLOT_MAP_KEY_TYPE;
|
||||||
|
|
||||||
using iterator = typename eastl::vector<T>::iterator;
|
using iterator = eastl::vector<T>::iterator;
|
||||||
using const_iterator = typename eastl::vector<T>::const_iterator;
|
using const_iterator = eastl::vector<T>::const_iterator;
|
||||||
using reverse_iterator = typename eastl::vector<T>::reverse_iterator;
|
using reverse_iterator = eastl::vector<T>::reverse_iterator;
|
||||||
using const_reverse_iterator = typename eastl::vector<T>::const_reverse_iterator;
|
using const_reverse_iterator = eastl::vector<T>::const_reverse_iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the map has the key
|
* Check if the map has the key
|
||||||
@@ -402,7 +402,6 @@ class DenseSlotMap
|
|||||||
m_freeListHead = p_key.GetIndex();
|
m_freeListHead = p_key.GetIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
/**
|
||||||
* The actual storage for our data
|
* The actual storage for our data
|
||||||
*/
|
*/
|
||||||
@@ -431,12 +430,13 @@ class DenseSlotMap
|
|||||||
template<class T, class SLOT_MAP_KEY_TYPE = SlotMapKey<>>
|
template<class T, class SLOT_MAP_KEY_TYPE = SlotMapKey<>>
|
||||||
class StableSlotMap
|
class StableSlotMap
|
||||||
{
|
{
|
||||||
private:
|
public:
|
||||||
static constexpr std::size_t PAGE_SIZE = 64;
|
static constexpr std::size_t PAGE_SIZE = 64;
|
||||||
|
|
||||||
|
private:
|
||||||
struct AlignedSlot
|
struct AlignedSlot
|
||||||
{
|
{
|
||||||
alignas(T) std::byte m_bytes[sizeof(T)];
|
alignas(T) eastl::array<std::byte, sizeof(T)> m_bytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Page
|
struct Page
|
||||||
@@ -467,7 +467,8 @@ class StableSlotMap
|
|||||||
T* Get(const std::size_t p_offset)
|
T* Get(const std::size_t p_offset)
|
||||||
{
|
{
|
||||||
ASSERT(UtilsAssertHandler, m_occupied[p_offset], "Requesting a dead data!");
|
ASSERT(UtilsAssertHandler, m_occupied[p_offset], "Requesting a dead data!");
|
||||||
return std::launder(reinterpret_cast<T*>(m_data[p_offset].m_bytes));
|
void* const bytes = m_data[p_offset].m_bytes.data();
|
||||||
|
return std::launder(static_cast<T*>(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -479,7 +480,8 @@ class StableSlotMap
|
|||||||
const T* Get(const std::size_t p_offset) const
|
const T* Get(const std::size_t p_offset) const
|
||||||
{
|
{
|
||||||
ASSERT(UtilsAssertHandler, m_occupied[p_offset], "Requesting a dead data!");
|
ASSERT(UtilsAssertHandler, m_occupied[p_offset], "Requesting a dead data!");
|
||||||
return std::launder(reinterpret_cast<const T*>(m_data[p_offset].m_bytes));
|
const void* const bytes = m_data[p_offset].m_bytes.data();
|
||||||
|
return std::launder(static_cast<const T*>(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -527,7 +529,8 @@ class StableSlotMap
|
|||||||
IteratorImpl() = default;
|
IteratorImpl() = default;
|
||||||
|
|
||||||
// Allows an iterator to be implicitly used as a const_iterator.
|
// Allows an iterator to be implicitly used as a const_iterator.
|
||||||
template<class OTHER_VALUE_TYPE, class = std::enable_if_t<std::is_same_v<VALUE_TYPE, const OTHER_VALUE_TYPE>>>
|
template<class OTHER_VALUE_TYPE>
|
||||||
|
requires std::is_same_v<VALUE_TYPE, const OTHER_VALUE_TYPE>
|
||||||
IteratorImpl(const IteratorImpl<OTHER_VALUE_TYPE>& p_other):
|
IteratorImpl(const IteratorImpl<OTHER_VALUE_TYPE>& p_other):
|
||||||
m_map(p_other.m_map),
|
m_map(p_other.m_map),
|
||||||
m_pageIt(p_other.m_pageIt),
|
m_pageIt(p_other.m_pageIt),
|
||||||
@@ -777,7 +780,7 @@ class StableSlotMap
|
|||||||
|
|
||||||
Page* const page = GetPageAt(pageIndex);
|
Page* const page = GetPageAt(pageIndex);
|
||||||
const std::size_t offsetInPage = GetDataOffset(key);
|
const std::size_t offsetInPage = GetDataOffset(key);
|
||||||
new (page->m_data[offsetInPage].m_bytes) T(std::forward<ARGS>(p_args)...);
|
new (page->m_data[offsetInPage].m_bytes.data()) T(std::forward<ARGS>(p_args)...);
|
||||||
page->m_occupied.set(offsetInPage);
|
page->m_occupied.set(offsetInPage);
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
@@ -835,7 +838,7 @@ class StableSlotMap
|
|||||||
{
|
{
|
||||||
std::destroy_at(page->Get(offset));
|
std::destroy_at(page->Get(offset));
|
||||||
|
|
||||||
const std::size_t keyIndex = pageIndex * PAGE_SIZE + offset;
|
const std::size_t keyIndex = (pageIndex * PAGE_SIZE) + offset;
|
||||||
RecycleKey(SlotMapKey {m_keys[keyIndex].GetVersion(), static_cast<SlotMapKey::IndexType>(keyIndex)});
|
RecycleKey(SlotMapKey {m_keys[keyIndex].GetVersion(), static_cast<SlotMapKey::IndexType>(keyIndex)});
|
||||||
}
|
}
|
||||||
page->m_occupied.reset();
|
page->m_occupied.reset();
|
||||||
@@ -870,9 +873,9 @@ class StableSlotMap
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
iterator begin()
|
iterator begin()
|
||||||
{
|
{
|
||||||
iterator it {this};
|
iterator result {this};
|
||||||
it.SeekFirstFrom(m_pages.begin());
|
result.SeekFirstFrom(m_pages.begin());
|
||||||
return it;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -884,9 +887,9 @@ class StableSlotMap
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const_iterator begin() const
|
const_iterator begin() const
|
||||||
{
|
{
|
||||||
const_iterator it {this};
|
const_iterator result {this};
|
||||||
it.SeekFirstFrom(m_pages.begin());
|
result.SeekFirstFrom(m_pages.begin());
|
||||||
return it;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -1024,7 +1027,6 @@ class StableSlotMap
|
|||||||
return m_pages[p_pageIndex].get();
|
return m_pages[p_pageIndex].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
/**
|
||||||
* The pages
|
* The pages
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file Format.hpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date September 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#ifndef BIGFOOT_UTILS_FORMAT_HPP
|
||||||
|
#define BIGFOOT_UTILS_FORMAT_HPP
|
||||||
|
#include <EASTL/string.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Format a string, like fmt::format, but returning an eastl::string instead of a std::string.
|
||||||
|
*
|
||||||
|
* \param p_format The format string
|
||||||
|
* \param p_args The arguments for the format string
|
||||||
|
* \return The formatted eastl::string
|
||||||
|
*/
|
||||||
|
template<typename... ARGS>
|
||||||
|
eastl::string Format(fmt::format_string<ARGS...> p_format, ARGS&&... p_args)
|
||||||
|
{
|
||||||
|
fmt::memory_buffer buffer;
|
||||||
|
fmt::format_to(std::back_inserter(buffer), p_format, std::forward<ARGS>(p_args)...);
|
||||||
|
return eastl::string {buffer.data(), buffer.size()};
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
|
#endif
|
||||||
@@ -8,40 +8,43 @@
|
|||||||
#define BIGFOOT_UTILS_LOG_EASTLFORMATTERS_HPP
|
#define BIGFOOT_UTILS_LOG_EASTLFORMATTERS_HPP
|
||||||
#include <Utils/TargetMacros.h>
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
#if defined(BIGFOOT_NOT_OPTIMIZED)
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
#include <quill/core/Codec.h>
|
#include <quill/core/Codec.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <EASTL/string.h>
|
#include <EASTL/string.h>
|
||||||
#include <EASTL/string_view.h>
|
#include <EASTL/string_view.h>
|
||||||
|
#include <EASTL/vector.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
// STRING
|
// STRING
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct fmt::formatter<eastl::string>
|
struct fmt::formatter<eastl::string>
|
||||||
{
|
{
|
||||||
constexpr auto parse(format_parse_context& ctx)
|
static constexpr auto parse(format_parse_context& ctx)
|
||||||
{
|
{
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto format(const eastl::string& p_string, format_context& ctx) const
|
static auto format(const eastl::string& p_string, format_context& ctx)
|
||||||
{
|
{
|
||||||
return fmt::format_to(ctx.out(), "{}", p_string.c_str());
|
return fmt::format_to(ctx.out(), "{}", p_string.c_str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
template<>
|
template<>
|
||||||
struct fmtquill::formatter<eastl::string>
|
struct fmtquill::formatter<eastl::string>
|
||||||
{
|
{
|
||||||
constexpr auto parse(format_parse_context& ctx)
|
static constexpr auto parse(format_parse_context& ctx)
|
||||||
{
|
{
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto format(const eastl::string& p_string, format_context& ctx) const
|
static auto format(const eastl::string& p_string, format_context& ctx)
|
||||||
{
|
{
|
||||||
return fmtquill::format_to(ctx.out(), "{}", p_string.c_str());
|
return fmtquill::format_to(ctx.out(), "{}", p_string.c_str());
|
||||||
}
|
}
|
||||||
@@ -53,27 +56,27 @@ struct fmtquill::formatter<eastl::string>
|
|||||||
template<>
|
template<>
|
||||||
struct fmt::formatter<eastl::string_view>
|
struct fmt::formatter<eastl::string_view>
|
||||||
{
|
{
|
||||||
constexpr auto parse(format_parse_context& ctx)
|
static constexpr auto parse(format_parse_context& ctx)
|
||||||
{
|
{
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto format(const eastl::string_view& p_stringView, format_context& ctx) const
|
static auto format(const eastl::string_view& p_stringView, format_context& ctx)
|
||||||
{
|
{
|
||||||
return fmt::format_to(ctx.out(), "{}", p_stringView.data());
|
return fmt::format_to(ctx.out(), "{}", p_stringView.data());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
template<>
|
template<>
|
||||||
struct fmtquill::formatter<eastl::string_view>
|
struct fmtquill::formatter<eastl::string_view>
|
||||||
{
|
{
|
||||||
constexpr auto parse(format_parse_context& ctx)
|
static constexpr auto parse(format_parse_context& ctx)
|
||||||
{
|
{
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto format(const eastl::string_view& p_stringView, format_context& ctx) const
|
static auto format(const eastl::string_view& p_stringView, format_context& ctx)
|
||||||
{
|
{
|
||||||
return fmtquill::format_to(ctx.out(), "{}", p_stringView.data());
|
return fmtquill::format_to(ctx.out(), "{}", p_stringView.data());
|
||||||
}
|
}
|
||||||
@@ -100,7 +103,7 @@ struct string_view: quill::Codec<std::string_view>
|
|||||||
Base::encode(p_buffer, p_cache, p_cacheIndex, std::string_view {p_arg.data(), p_arg.size()});
|
Base::encode(p_buffer, p_cache, p_cacheIndex, std::string_view {p_arg.data(), p_arg.size()});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace Bigfoot::Codec
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct quill::Codec<eastl::string>: Bigfoot::Codec::string_view<eastl::string>
|
struct quill::Codec<eastl::string>: Bigfoot::Codec::string_view<eastl::string>
|
||||||
@@ -112,4 +115,61 @@ struct quill::Codec<eastl::string_view>: Bigfoot::Codec::string_view<eastl::stri
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// VECTOR
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct fmt::formatter<eastl::vector<T>>
|
||||||
|
{
|
||||||
|
constexpr auto parse(format_parse_context& ctx)
|
||||||
|
{
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto format(const eastl::vector<T>& p_vector, format_context& ctx) const
|
||||||
|
{
|
||||||
|
auto out = fmt::format_to(ctx.out(), "[");
|
||||||
|
for (std::size_t i = 0; i < p_vector.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
out = fmt::format_to(out, ", ");
|
||||||
|
}
|
||||||
|
out = fmt::format_to(out, "{}", p_vector[i]);
|
||||||
|
}
|
||||||
|
return fmt::format_to(out, "]");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
#include <quill/DeferredFormatCodec.h>
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct fmtquill::formatter<eastl::vector<T>>
|
||||||
|
{
|
||||||
|
constexpr auto parse(format_parse_context& ctx)
|
||||||
|
{
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto format(const eastl::vector<T>& p_vector, format_context& ctx) const
|
||||||
|
{
|
||||||
|
auto out = fmtquill::format_to(ctx.out(), "[");
|
||||||
|
for (std::size_t i = 0; i < p_vector.size(); ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
out = fmtquill::format_to(out, ", ");
|
||||||
|
}
|
||||||
|
out = fmtquill::format_to(out, "{}", p_vector[i]);
|
||||||
|
}
|
||||||
|
return fmtquill::format_to(out, "]");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct quill::Codec<eastl::vector<T>>: quill::DeferredFormatCodec<eastl::vector<T>>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ namespace Bigfoot.Flat;
|
|||||||
|
|
||||||
enum LogSinkType: byte
|
enum LogSinkType: byte
|
||||||
{
|
{
|
||||||
Console
|
Console,
|
||||||
|
File
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LogLevel: byte
|
enum LogLevel: byte
|
||||||
|
|||||||
@@ -8,10 +8,11 @@
|
|||||||
#define BIGFOOT_UTILS_LOG_LOG_HPP
|
#define BIGFOOT_UTILS_LOG_LOG_HPP
|
||||||
#include <Utils/Log/EASTLFormatters.hpp>
|
#include <Utils/Log/EASTLFormatters.hpp>
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
#include <Utils/Log/Log_generated.hpp>
|
#include <Utils/Log/Log_generated.hpp>
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
#include <EASTL/string_view.h>
|
||||||
|
|
||||||
#ifdef BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
#pragma warning(disable: 4702)
|
#pragma warning(disable: 4702)
|
||||||
@@ -21,7 +22,8 @@
|
|||||||
#include <quill/LogMacros.h>
|
#include <quill/LogMacros.h>
|
||||||
#include <quill/Logger.h>
|
#include <quill/Logger.h>
|
||||||
#include <quill/sinks/ConsoleSink.h>
|
#include <quill/sinks/ConsoleSink.h>
|
||||||
#if defined BIGFOOT_WINDOWS
|
#include <quill/sinks/FileSink.h>
|
||||||
|
#ifdef BIGFOOT_WINDOWS
|
||||||
#pragma warning(default: 4702)
|
#pragma warning(default: 4702)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -36,6 +38,11 @@ class Log
|
|||||||
Flat::LogLevel m_level;
|
Flat::LogLevel m_level;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path of the file the File sink writes to
|
||||||
|
*/
|
||||||
|
static constexpr eastl::string_view FILE_SINK_PATH = "Bigfoot.log";
|
||||||
|
|
||||||
Log();
|
Log();
|
||||||
|
|
||||||
Log(const Log& p_logger) = delete;
|
Log(const Log& p_logger) = delete;
|
||||||
@@ -95,7 +102,7 @@ class Log
|
|||||||
/*
|
/*
|
||||||
* The sinks
|
* The sinks
|
||||||
*/
|
*/
|
||||||
eastl::array<std::shared_ptr<quill::Sink>, 1> m_sinks;
|
eastl::array<std::shared_ptr<quill::Sink>, 2> m_sinks;
|
||||||
};
|
};
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,7 +9,16 @@
|
|||||||
#include <Utils/Log/Log.hpp>
|
#include <Utils/Log/Log.hpp>
|
||||||
#include <Utils/Singleton.hpp>
|
#include <Utils/Singleton.hpp>
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
#define BIGFOOT_FLUSH_LOG \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (Bigfoot::Singleton<Bigfoot::Log>::HasInstance()) \
|
||||||
|
{ \
|
||||||
|
Bigfoot::Singleton<Bigfoot::Log>::GetInstance().Flush(); \
|
||||||
|
} \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
#define BIGFOOT_LOG_DEBUG(loggerName, fmt, ...) \
|
#define BIGFOOT_LOG_DEBUG(loggerName, fmt, ...) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
@@ -101,4 +110,67 @@
|
|||||||
#define BIGFOOT_LOG_ERROR(loggerName, fmt, ...)
|
#define BIGFOOT_LOG_ERROR(loggerName, fmt, ...)
|
||||||
#define BIGFOOT_LOG_FATAL(loggerName, fmt, ...)
|
#define BIGFOOT_LOG_FATAL(loggerName, fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
#define BIGFOOT_LOG_DEBUG_IF(condition, loggerName, fmt, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (condition) \
|
||||||
|
{ \
|
||||||
|
BIGFOOT_LOG_DEBUG(loggerName, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define BIGFOOT_LOG_TRACE_IF(condition, loggerName, fmt, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (condition) \
|
||||||
|
{ \
|
||||||
|
BIGFOOT_LOG_TRACE(loggerName, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define BIGFOOT_LOG_INFO_IF(condition, loggerName, fmt, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (condition) \
|
||||||
|
{ \
|
||||||
|
BIGFOOT_LOG_INFO(loggerName, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define BIGFOOT_LOG_WARN_IF(condition, loggerName, fmt, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (condition) \
|
||||||
|
{ \
|
||||||
|
BIGFOOT_LOG_WARN(loggerName, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define BIGFOOT_LOG_ERROR_IF(condition, loggerName, fmt, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (condition) \
|
||||||
|
{ \
|
||||||
|
BIGFOOT_LOG_ERROR(loggerName, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define BIGFOOT_LOG_FATAL_IF(condition, loggerName, fmt, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (condition) \
|
||||||
|
{ \
|
||||||
|
BIGFOOT_LOG_FATAL(loggerName, fmt __VA_OPT__(, ) __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define BIGFOOT_LOG_DEBUG_IF(condition, loggerName, fmt, ...)
|
||||||
|
#define BIGFOOT_LOG_TRACE_IF(condition, loggerName, fmt, ...)
|
||||||
|
#define BIGFOOT_LOG_INFO_IF(condition, loggerName, fmt, ...)
|
||||||
|
#define BIGFOOT_LOG_WARN_IF(condition, loggerName, fmt, ...)
|
||||||
|
#define BIGFOOT_LOG_ERROR_IF(condition, loggerName, fmt, ...)
|
||||||
|
#define BIGFOOT_LOG_FATAL_IF(condition, loggerName, fmt, ...)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -29,27 +29,30 @@ namespace Flat {
|
|||||||
|
|
||||||
enum class LogSinkType : int8_t {
|
enum class LogSinkType : int8_t {
|
||||||
Console = 0,
|
Console = 0,
|
||||||
|
File = 1,
|
||||||
MIN = Console,
|
MIN = Console,
|
||||||
MAX = Console
|
MAX = File
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const LogSinkType (&EnumValuesLogSinkType())[1] {
|
inline const LogSinkType (&EnumValuesLogSinkType())[2] {
|
||||||
static const LogSinkType values[] = {
|
static const LogSinkType values[] = {
|
||||||
LogSinkType::Console
|
LogSinkType::Console,
|
||||||
|
LogSinkType::File
|
||||||
};
|
};
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char * const *EnumNamesLogSinkType() {
|
inline const char * const *EnumNamesLogSinkType() {
|
||||||
static const char * const names[2] = {
|
static const char * const names[3] = {
|
||||||
"Console",
|
"Console",
|
||||||
|
"File",
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char *EnumNameLogSinkType(LogSinkType e) {
|
inline const char *EnumNameLogSinkType(LogSinkType e) {
|
||||||
if (::flatbuffers::IsOutRange(e, LogSinkType::Console, LogSinkType::Console)) return "";
|
if (::flatbuffers::IsOutRange(e, LogSinkType::Console, LogSinkType::File)) return "";
|
||||||
const size_t index = static_cast<size_t>(e);
|
const size_t index = static_cast<size_t>(e);
|
||||||
return EnumNamesLogSinkType()[index];
|
return EnumNamesLogSinkType()[index];
|
||||||
}
|
}
|
||||||
@@ -98,13 +101,14 @@ inline const char *EnumNameLogLevel(LogLevel e) {
|
|||||||
|
|
||||||
inline const ::flatbuffers::TypeTable *LogSinkTypeTypeTable() {
|
inline const ::flatbuffers::TypeTable *LogSinkTypeTypeTable() {
|
||||||
static const ::flatbuffers::TypeCode type_codes[] = {
|
static const ::flatbuffers::TypeCode type_codes[] = {
|
||||||
|
{ ::flatbuffers::ET_CHAR, 0, 0 },
|
||||||
{ ::flatbuffers::ET_CHAR, 0, 0 }
|
{ ::flatbuffers::ET_CHAR, 0, 0 }
|
||||||
};
|
};
|
||||||
static const ::flatbuffers::TypeFunction type_refs[] = {
|
static const ::flatbuffers::TypeFunction type_refs[] = {
|
||||||
Bigfoot::Flat::LogSinkTypeTypeTable
|
Bigfoot::Flat::LogSinkTypeTypeTable
|
||||||
};
|
};
|
||||||
static const ::flatbuffers::TypeTable tt = {
|
static const ::flatbuffers::TypeTable tt = {
|
||||||
::flatbuffers::ST_ENUM, 1, type_codes, type_refs, nullptr, nullptr, nullptr
|
::flatbuffers::ST_ENUM, 2, type_codes, type_refs, nullptr, nullptr, nullptr
|
||||||
};
|
};
|
||||||
return &tt;
|
return &tt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Bigfoot
|
|||||||
/*
|
/*
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
inline Log::LoggerInfo @LOGGER_NAME@ {"@LOGGER_NAME@", Flat::LogLevel::Trace};
|
inline Log::LoggerInfo @LOGGER_NAME@ { .m_name = "@LOGGER_NAME@", .m_level = Flat::LogLevel::Trace};
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -33,6 +33,7 @@ class TaggedType
|
|||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
constexpr TYPE Get() const
|
constexpr TYPE Get() const
|
||||||
{
|
{
|
||||||
return m_value;
|
return m_value;
|
||||||
|
|||||||
@@ -7,33 +7,39 @@
|
|||||||
#ifndef BIGFOOT_UTILS_TARGETMACROS_H
|
#ifndef BIGFOOT_UTILS_TARGETMACROS_H
|
||||||
#define BIGFOOT_UTILS_TARGETMACROS_H
|
#define BIGFOOT_UTILS_TARGETMACROS_H
|
||||||
|
|
||||||
#if defined BIGFOOT_WINDOWS
|
#ifdef BIGFOOT_WINDOWS
|
||||||
#define BIGFOOT_WINDOWS_OR_LINUX(p_windows, p_linux) p_windows
|
#define BIGFOOT_WINDOWS_OR_LINUX(p_windows, p_linux) p_windows
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined BIGFOOT_LINUX
|
#ifdef BIGFOOT_LINUX
|
||||||
#define BIGFOOT_WINDOWS_OR_LINUX(p_windows, p_linux) p_linux
|
#define BIGFOOT_WINDOWS_OR_LINUX(p_windows, p_linux) p_linux
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined BIGFOOT_OPTIMIZED
|
#ifdef BIGFOOT_WINDOWS
|
||||||
|
#define BIGFOOT_ALWAYS_INLINE [[msvc::forceinline]]
|
||||||
|
#elif defined BIGFOOT_LINUX
|
||||||
|
#define BIGFOOT_ALWAYS_INLINE [[gnu::always_inline]] inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BIGFOOT_OPTIMIZED
|
||||||
#define BIGFOOT_OPTIMIZED_ONLY(...) __VA_ARGS__
|
#define BIGFOOT_OPTIMIZED_ONLY(...) __VA_ARGS__
|
||||||
#define BIGFOOT_NOT_OPTIMIZED_ONLY(...)
|
#define BIGFOOT_NOT_OPTIMIZED_ONLY(...)
|
||||||
#define BIGFOOT_OPTIMIZED_OR_NOT(p_optimized, p_notOptimized) p_optimized
|
#define BIGFOOT_OPTIMIZED_OR_NOT(p_optimized, p_notOptimized) p_optimized
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
#define BIGFOOT_OPTIMIZED_ONLY(...)
|
#define BIGFOOT_OPTIMIZED_ONLY(...)
|
||||||
#define BIGFOOT_NOT_OPTIMIZED_ONLY(...) __VA_ARGS__
|
#define BIGFOOT_NOT_OPTIMIZED_ONLY(...) __VA_ARGS__
|
||||||
#define BIGFOOT_OPTIMIZED_OR_NOT(p_optimized, p_notOptimized) p_notOptimized
|
#define BIGFOOT_OPTIMIZED_OR_NOT(p_optimized, p_notOptimized) p_notOptimized
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined BIGFOOT_TOOLMODE
|
#ifdef BIGFOOT_TOOLMODE
|
||||||
#define BIGFOOT_TOOLMODE_ONLY(...) __VA_ARGS__
|
#define BIGFOOT_TOOLMODE_ONLY(...) __VA_ARGS__
|
||||||
#define BIGFOOT_GAME_ONLY(...)
|
#define BIGFOOT_GAME_ONLY(...)
|
||||||
#define BIGFOOT_GAME_OR_TOOLMODE(p_game, p_toolmode) p_toolmode
|
#define BIGFOOT_GAME_OR_TOOLMODE(p_game, p_toolmode) p_toolmode
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined BIGFOOT_GAME
|
#ifdef BIGFOOT_GAME
|
||||||
#define BIGFOOT_TOOLMODE_ONLY(...)
|
#define BIGFOOT_TOOLMODE_ONLY(...)
|
||||||
#define BIGFOOT_GAME_ONLY(...) __VA_ARGS__
|
#define BIGFOOT_GAME_ONLY(...) __VA_ARGS__
|
||||||
#define BIGFOOT_GAME_OR_TOOLMODE(p_game, p_toolmode) p_game
|
#define BIGFOOT_GAME_OR_TOOLMODE(p_game, p_toolmode) p_game
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <Utils/Assert/AssertHandler.hpp>
|
#include <Utils/Assert/AssertHandler.hpp>
|
||||||
#include <Utils/UtilsLogger_generated.hpp>
|
#include <Utils/UtilsLogger_generated.hpp>
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Bigfoot
|
|||||||
/*
|
/*
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
inline Log::LoggerInfo UTILS_LOGGER {"UTILS_LOGGER", Flat::LogLevel::Trace};
|
inline Log::LoggerInfo UTILS_LOGGER { .m_name = "UTILS_LOGGER", .m_level = Flat::LogLevel::Trace};
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,17 +7,22 @@
|
|||||||
#ifndef BIGFOOT_UTILS_VERSION_HPP
|
#ifndef BIGFOOT_UTILS_VERSION_HPP
|
||||||
#define BIGFOOT_UTILS_VERSION_HPP
|
#define BIGFOOT_UTILS_VERSION_HPP
|
||||||
#include <Utils/Caster.hpp>
|
#include <Utils/Caster.hpp>
|
||||||
|
#include <Utils/Format.hpp>
|
||||||
#include <Utils/TargetMacros.h>
|
#include <Utils/TargetMacros.h>
|
||||||
|
|
||||||
|
#include <EASTL/string.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
class Version
|
class Version
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
static constexpr std::uint32_t MAJOR_SHIFT = 16;
|
||||||
|
static constexpr std::uint32_t MINOR_SHIFT = 8;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Version() = default;
|
Version() = default;
|
||||||
|
|
||||||
@@ -39,7 +44,7 @@ class Version
|
|||||||
* \param p_patch Patch
|
* \param p_patch Patch
|
||||||
*/
|
*/
|
||||||
constexpr Version(const std::uint8_t p_major, const std::uint8_t p_minor, const std::uint8_t p_patch):
|
constexpr Version(const std::uint8_t p_major, const std::uint8_t p_minor, const std::uint8_t p_patch):
|
||||||
m_combined((p_major << 16) | (p_minor << 8) | p_patch)
|
m_combined((p_major << MAJOR_SHIFT) | (p_minor << MINOR_SHIFT) | p_patch)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +104,7 @@ class Version
|
|||||||
* \return The string
|
* \return The string
|
||||||
*/
|
*/
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::string ToString() const;
|
eastl::string ToString() const;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr auto operator<=>(const Version& p_version) const = default;
|
constexpr auto operator<=>(const Version& p_version) const = default;
|
||||||
@@ -114,7 +119,6 @@ class Version
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
|
||||||
template<>
|
template<>
|
||||||
struct fmt::formatter<Bigfoot::Version>
|
struct fmt::formatter<Bigfoot::Version>
|
||||||
{
|
{
|
||||||
@@ -127,8 +131,7 @@ struct fmt::formatter<Bigfoot::Version>
|
|||||||
template<typename FormatContext>
|
template<typename FormatContext>
|
||||||
auto format(const Bigfoot::Version& p_version, FormatContext& p_context) const
|
auto format(const Bigfoot::Version& p_version, FormatContext& p_context) const
|
||||||
{
|
{
|
||||||
return fmt::format_to(p_context.out(), "{}", p_version.ToString());
|
return fmt::format_to(p_context.out(), "{}", p_version.ToString().c_str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#include <Utils/Log/Log.hpp>
|
#include <Utils/Log/Log.hpp>
|
||||||
|
|
||||||
#if defined BIGFOOT_NOT_OPTIMIZED
|
#ifdef BIGFOOT_NOT_OPTIMIZED
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
@@ -17,6 +17,12 @@ Log::Log()
|
|||||||
m_sinks[static_cast<std::size_t>(Flat::LogSinkType::Console)] =
|
m_sinks[static_cast<std::size_t>(Flat::LogSinkType::Console)] =
|
||||||
quill::Frontend::create_or_get_sink<quill::ConsoleSink>(
|
quill::Frontend::create_or_get_sink<quill::ConsoleSink>(
|
||||||
std::string {Flat::EnumNameLogSinkType(Flat::LogSinkType::Console)});
|
std::string {Flat::EnumNameLogSinkType(Flat::LogSinkType::Console)});
|
||||||
|
|
||||||
|
quill::FileSinkConfig fileSinkConfig;
|
||||||
|
fileSinkConfig.set_open_mode('w');
|
||||||
|
m_sinks[static_cast<std::size_t>(Flat::LogSinkType::File)] = quill::Frontend::create_or_get_sink<quill::FileSink>(
|
||||||
|
std::string {FILE_SINK_PATH.data()},
|
||||||
|
fileSinkConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
@@ -25,7 +31,8 @@ quill::Logger* Log::RegisterLogger(const LoggerInfo& p_loggerInfo)
|
|||||||
{
|
{
|
||||||
quill::Logger* logger = quill::Frontend::create_or_get_logger(
|
quill::Logger* logger = quill::Frontend::create_or_get_logger(
|
||||||
p_loggerInfo.m_name,
|
p_loggerInfo.m_name,
|
||||||
m_sinks[static_cast<std::size_t>(Flat::LogSinkType::Console)]);
|
{m_sinks[static_cast<std::size_t>(Flat::LogSinkType::Console)],
|
||||||
|
m_sinks[static_cast<std::size_t>(Flat::LogSinkType::File)]});
|
||||||
SetLoggerLevel(p_loggerInfo);
|
SetLoggerLevel(p_loggerInfo);
|
||||||
|
|
||||||
return logger;
|
return logger;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* \author Romain BOULLARD
|
* \author Romain BOULLARD
|
||||||
* \date October 2025
|
* \date October 2025
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
// NOLINTBEGIN
|
||||||
#include <Utils/Profiler.hpp>
|
#include <Utils/Profiler.hpp>
|
||||||
|
|
||||||
#if defined BIGFOOT_WINDOWS
|
#if defined BIGFOOT_WINDOWS
|
||||||
@@ -96,3 +97,4 @@
|
|||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
// NOLINTEND
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
std::string Version::ToString() const
|
eastl::string Version::ToString() const
|
||||||
{
|
{
|
||||||
return fmt::format("{}.{}.{}", GetMajor(), GetMinor(), GetPatch());
|
return Format("{}.{}.{}", GetMajor(), GetMinor(), GetPatch());
|
||||||
}
|
}
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
InheritParentConfig: true
|
||||||
|
Checks: >
|
||||||
|
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||||
|
-cppcoreguidelines-avoid-magic-numbers,
|
||||||
|
-readability-magic-numbers
|
||||||
@@ -3,3 +3,6 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Misc)
|
|||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System)
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
|
||||||
|
if(${TOOLMODE})
|
||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Tools)
|
||||||
|
endif()
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <AssetsForTesting/Asset/AssetB.hpp>
|
#include <AssetsForTesting/Asset/AssetB.hpp>
|
||||||
#include <AssetsForTesting/Asset/AssetC.hpp>
|
#include <AssetsForTesting/Asset/AssetC.hpp>
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
@@ -17,43 +18,66 @@ namespace Bigfoot
|
|||||||
class AssetFixture: public ::testing::Test
|
class AssetFixture: public ::testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
AssetA m_asset;
|
void SetUp() override
|
||||||
|
{
|
||||||
|
SetActiveAssetLibrary(&m_library);
|
||||||
|
std::ignore = m_library.Insert(&m_containerA);
|
||||||
|
std::ignore = m_library.Insert(&m_containerB);
|
||||||
|
|
||||||
|
const UUID uuidA = m_assetA.GetHeader().uuid;
|
||||||
|
const UUID uuidB = m_assetB.GetHeader().uuid;
|
||||||
|
|
||||||
|
m_assetA.GetAsset().ref_a = SoftReference<AssetA> {uuidA};
|
||||||
|
|
||||||
|
m_assetB.GetAsset().ref_a = HardReference<AssetA> {uuidA};
|
||||||
|
m_assetB.GetAsset().refs_a.push_back(SoftReference<AssetA> {uuidA});
|
||||||
|
|
||||||
|
m_assetC.GetAsset().inner_table->asset_a_ref = HardReference<AssetA> {uuidA};
|
||||||
|
m_assetC.GetAsset().inner_table->asset_a_refs.push_back(HardReference<AssetA> {uuidA});
|
||||||
|
m_assetC.GetAsset().inner_table->asset_a_refs.push_back(HardReference<AssetA> {uuidA});
|
||||||
|
m_assetC.GetAsset().asset_b_ref = HardReference<AssetB> {uuidB};
|
||||||
|
m_assetC.GetAsset().asset_b_refs.push_back(SoftReference<AssetB> {uuidB});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override
|
||||||
|
{
|
||||||
|
SetActiveAssetLibrary(&g_assetLibrary);
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetLibrary m_library;
|
||||||
|
AssetContainer<AssetA> m_containerA;
|
||||||
|
AssetContainer<AssetB> m_containerB;
|
||||||
|
|
||||||
|
AssetA m_assetA;
|
||||||
|
AssetB m_assetB;
|
||||||
|
AssetC m_assetC;
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(AssetFixture, Constructor_ShouldInitializeHeaderTypeIdAndTypeName)
|
TEST_F(AssetFixture, Constructor_ShouldInitializeHeaderTypeIdAndTypeName)
|
||||||
{
|
{
|
||||||
EXPECT_EQ(m_asset.GetHeader().type_id, AssetA::GetTypeID());
|
EXPECT_EQ(m_assetA.GetHeader().type_id, AssetA::GetTypeID());
|
||||||
EXPECT_EQ(m_asset.GetHeader().type_name, eastl::string {AssetA::GetTypeName()});
|
EXPECT_EQ(m_assetA.GetHeader().type_name, eastl::string {AssetA::GetTypeName()});
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(AssetFixture, SetName_ShouldSetTheName)
|
TEST_F(AssetFixture, SetName_ShouldSetTheName)
|
||||||
{
|
{
|
||||||
m_asset.SetName("MyAsset");
|
m_assetA.SetName("MyAsset");
|
||||||
|
|
||||||
EXPECT_STREQ(m_asset.GetHeader().name.c_str(), "MyAsset");
|
EXPECT_STREQ(m_assetA.GetHeader().name.c_str(), "MyAsset");
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(AssetFixture, SetVersion_ShouldSetTheVersion)
|
|
||||||
{
|
|
||||||
m_asset.SetVersion(5);
|
|
||||||
|
|
||||||
EXPECT_EQ(m_asset.GetHeader().version, 5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(AssetFixture, GetAsset_ShouldReturnAMutableReferenceToTheUnderlyingAsset)
|
TEST_F(AssetFixture, GetAsset_ShouldReturnAMutableReferenceToTheUnderlyingAsset)
|
||||||
{
|
{
|
||||||
m_asset.GetAsset().health = 10;
|
m_assetA.GetAsset().health = 10;
|
||||||
|
|
||||||
EXPECT_EQ(m_asset.GetAsset().health, 10);
|
EXPECT_EQ(m_assetA.GetAsset().health, 10);
|
||||||
EXPECT_EQ(std::as_const(m_asset).GetAsset().health, 10);
|
EXPECT_EQ(std::as_const(m_assetA).GetAsset().health, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
@@ -83,20 +107,68 @@ TEST_F(AssetFixture, GetTypeName_ShouldReturnTheFlatbufferFullyQualifiedName)
|
|||||||
|
|
||||||
TEST_F(AssetFixture, PackThenUnpack_ShouldRoundTripTheHeaderAndTheAsset)
|
TEST_F(AssetFixture, PackThenUnpack_ShouldRoundTripTheHeaderAndTheAsset)
|
||||||
{
|
{
|
||||||
m_asset.SetName("MyAsset");
|
m_assetA.SetName("MyAsset");
|
||||||
m_asset.SetVersion(3);
|
m_assetA.GetAsset().health = 42;
|
||||||
m_asset.GetAsset().health = 42;
|
m_assetA.GetAsset().mana = 7;
|
||||||
m_asset.GetAsset().mana = 7;
|
|
||||||
|
|
||||||
AssetA unpacked;
|
AssetA unpacked;
|
||||||
unpacked.Unpack(m_asset.Pack());
|
unpacked.Unpack(m_assetA.Pack());
|
||||||
|
|
||||||
EXPECT_EQ(unpacked.GetHeader().uuid, m_asset.GetHeader().uuid);
|
EXPECT_EQ(unpacked.GetHeader().uuid, m_assetA.GetHeader().uuid);
|
||||||
EXPECT_STREQ(unpacked.GetHeader().name.c_str(), m_asset.GetHeader().name.c_str());
|
EXPECT_STREQ(unpacked.GetHeader().name.c_str(), m_assetA.GetHeader().name.c_str());
|
||||||
EXPECT_EQ(unpacked.GetHeader().version, m_asset.GetHeader().version);
|
EXPECT_EQ(unpacked.GetHeader().type_id, m_assetA.GetHeader().type_id);
|
||||||
EXPECT_EQ(unpacked.GetHeader().type_id, m_asset.GetHeader().type_id);
|
EXPECT_STREQ(unpacked.GetHeader().type_name.c_str(), m_assetA.GetHeader().type_name.c_str());
|
||||||
EXPECT_STREQ(unpacked.GetHeader().type_name.c_str(), m_asset.GetHeader().type_name.c_str());
|
EXPECT_EQ(unpacked.GetAsset().health, m_assetA.GetAsset().health);
|
||||||
EXPECT_EQ(unpacked.GetAsset().health, m_asset.GetAsset().health);
|
EXPECT_EQ(unpacked.GetAsset().mana, m_assetA.GetAsset().mana);
|
||||||
EXPECT_EQ(unpacked.GetAsset().mana, m_asset.GetAsset().mana);
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetFixture, GetHardReferences_ShouldReturnTheHardReferencesOfTheAsset)
|
||||||
|
{
|
||||||
|
const eastl::vector<UUID> hardReferences = m_assetC.GetHardReferences(m_assetC.Pack());
|
||||||
|
|
||||||
|
EXPECT_THAT(hardReferences, ::testing::UnorderedElementsAre(m_assetA.GetHeader().uuid, m_assetB.GetHeader().uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetFixture, CreateAsset_ShouldReturnTheCreatedAsset)
|
||||||
|
{
|
||||||
|
EXPECT_NE(CreateAsset<AssetA>(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetFixture, CreateAsset_ShouldCreateUniqueAssets)
|
||||||
|
{
|
||||||
|
const AssetA* first = CreateAsset<AssetA>();
|
||||||
|
const AssetA* second = CreateAsset<AssetA>();
|
||||||
|
|
||||||
|
EXPECT_NE(first->GetHeader().uuid, second->GetHeader().uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetFixture, CreateAsset_ShouldReturnTheSameAssetAsItsContainerHandle)
|
||||||
|
{
|
||||||
|
const AssetA* asset = CreateAsset<AssetA>();
|
||||||
|
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(asset->GetHeader().uuid);
|
||||||
|
|
||||||
|
EXPECT_EQ(handle->GetAsset(), asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetFixture, CreateAsset_ShouldInsertTheAssetIntoItsCorrespondingContainer)
|
||||||
|
{
|
||||||
|
const AssetA* assetA = CreateAsset<AssetA>();
|
||||||
|
const AssetB* assetB = CreateAsset<AssetB>();
|
||||||
|
|
||||||
|
EXPECT_TRUE(m_containerA.Has(assetA->GetHeader().uuid));
|
||||||
|
EXPECT_FALSE(m_containerB.Has(assetA->GetHeader().uuid));
|
||||||
|
|
||||||
|
EXPECT_TRUE(m_containerB.Has(assetB->GetHeader().uuid));
|
||||||
|
EXPECT_FALSE(m_containerA.Has(assetB->GetHeader().uuid));
|
||||||
}
|
}
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -17,18 +17,14 @@ class ContainerHandleFixture: public ::testing::Test
|
|||||||
protected:
|
protected:
|
||||||
void SetUp() override
|
void SetUp() override
|
||||||
{
|
{
|
||||||
const auto key = m_containerA.Insert();
|
m_handle = m_containerA.Insert();
|
||||||
|
m_uuid = m_handle->GetAsset()->GetHeader().uuid;
|
||||||
m_uuid = m_containerA.Get(key)->GetHeader().uuid;
|
|
||||||
|
|
||||||
m_handle = m_containerA.AcquireContainerHandle(m_uuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetContainer<AssetA> m_containerA;
|
AssetContainer<AssetA> m_containerA;
|
||||||
|
|
||||||
UUID m_uuid;
|
UUID m_uuid;
|
||||||
|
ContainerHandle* m_handle = nullptr;
|
||||||
ContainerHandle* m_handle;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
@@ -88,6 +84,40 @@ TEST_F(ContainerHandleFixture, DecrementSoftRefCount_ShouldDecrementTheSoftRefCo
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(ContainerHandleFixture, DecrementHardRefCount_ShouldQueueTheAssetForRemovalWhenItReachesZero)
|
||||||
|
{
|
||||||
|
m_handle->IncrementHardRefCount();
|
||||||
|
m_handle->DecrementHardRefCount();
|
||||||
|
|
||||||
|
EXPECT_TRUE(m_containerA.IsMarkedForRemove(m_uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(ContainerHandleFixture, DecrementHardRefCount_ShouldNotQueueTheAssetForRemovalIfItDoesNotReachZero)
|
||||||
|
{
|
||||||
|
m_handle->IncrementHardRefCount();
|
||||||
|
m_handle->IncrementHardRefCount();
|
||||||
|
m_handle->DecrementHardRefCount();
|
||||||
|
|
||||||
|
EXPECT_FALSE(m_containerA.IsMarkedForRemove(m_uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(ContainerHandleFixture, IncrementHardRefCount_ShouldCancelAPendingRemovalWhenGoingFromZero)
|
||||||
|
{
|
||||||
|
m_handle->IncrementHardRefCount();
|
||||||
|
m_handle->DecrementHardRefCount();
|
||||||
|
ASSERT_TRUE(m_containerA.IsMarkedForRemove(m_uuid));
|
||||||
|
|
||||||
|
m_handle->IncrementHardRefCount();
|
||||||
|
|
||||||
|
EXPECT_FALSE(m_containerA.IsMarkedForRemove(m_uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
class AssetContainerFixture: public ::testing::Test
|
class AssetContainerFixture: public ::testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@@ -98,8 +128,8 @@ class AssetContainerFixture: public ::testing::Test
|
|||||||
|
|
||||||
TEST_F(AssetContainerFixture, Has_ShouldReturnTrueIfTheContainerHasTheAsset)
|
TEST_F(AssetContainerFixture, Has_ShouldReturnTrueIfTheContainerHasTheAsset)
|
||||||
{
|
{
|
||||||
const auto key = m_containerA.Insert();
|
const ContainerHandle* handle = m_containerA.Insert();
|
||||||
EXPECT_TRUE(m_containerA.Has(m_containerA.Get(key)->GetHeader().uuid));
|
EXPECT_TRUE(m_containerA.Has(handle->GetAsset()->GetHeader().uuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
@@ -113,11 +143,10 @@ TEST_F(AssetContainerFixture, Has_ShouldReturnFalseIfTheContainerDoesNotHaveTheA
|
|||||||
|
|
||||||
TEST_F(AssetContainerFixture, AcquireHandle_ShouldReturnTheAssociatedContainerHandle)
|
TEST_F(AssetContainerFixture, AcquireHandle_ShouldReturnTheAssociatedContainerHandle)
|
||||||
{
|
{
|
||||||
const auto key = m_containerA.Insert();
|
const ContainerHandle* handle = m_containerA.Insert();
|
||||||
|
const UUID uuid = handle->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(m_containerA.Get(key)->GetHeader().uuid);
|
EXPECT_EQ(m_containerA.AcquireContainerHandle(uuid), handle);
|
||||||
EXPECT_EQ(static_cast<const AssetA*>(handle->GetAsset())->GetHeader().uuid,
|
|
||||||
m_containerA.Get(key)->GetHeader().uuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
@@ -130,53 +159,111 @@ TEST_F(AssetContainerFixture, AcquireHandle_ShouldCreateTheAssociatedContainerHa
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(AssetContainerFixture, Insert_ShouldReturnValidAndUniqueSlotKeyOnInsert)
|
TEST_F(AssetContainerFixture, Insert_ShouldReturnAHandleWithTheInsertedAsset)
|
||||||
{
|
{
|
||||||
const SlotMapKey slotKey = m_containerA.Insert();
|
const ContainerHandle* handle = m_containerA.Insert();
|
||||||
EXPECT_TRUE(slotKey.Valid());
|
EXPECT_NE(handle, nullptr);
|
||||||
EXPECT_NE(slotKey, m_containerA.Insert());
|
EXPECT_NE(handle->GetAsset(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(AssetContainerFixture, Insert_ShouldReturnTheSameSlotKeyInCaseOfDuplicatedUUID)
|
TEST_F(AssetContainerFixture, Insert_ShouldReuseTheExistingHandleWhenInsertingAnAssetWithAnAlreadyExistingUUID)
|
||||||
{
|
{
|
||||||
const SlotMapKey slotKey = m_containerA.Insert();
|
ContainerHandle* const firstHandle = m_containerA.Insert();
|
||||||
|
const AssetBase* const firstAsset = firstHandle->GetAsset();
|
||||||
|
const eastl::vector<std::byte> packed = firstAsset->Pack();
|
||||||
|
|
||||||
AssetA duplicate;
|
ContainerHandle* const secondHandle = m_containerA.Insert(packed);
|
||||||
duplicate.Unpack(m_containerA.Get(slotKey)->Pack());
|
|
||||||
|
|
||||||
EXPECT_EQ(slotKey, m_containerA.Insert(std::move(duplicate)));
|
EXPECT_EQ(secondHandle, firstHandle);
|
||||||
}
|
EXPECT_EQ(secondHandle->GetAsset(), firstAsset);
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(AssetContainerFixture, Get_ShouldReturnTheAssetWithTheSlotKey)
|
|
||||||
{
|
|
||||||
const SlotMapKey slotKey = m_containerA.Insert();
|
|
||||||
|
|
||||||
EXPECT_NE(m_containerA.Get(slotKey), nullptr);
|
|
||||||
EXPECT_NE(std::as_const(m_containerA).Get(slotKey), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(AssetContainerFixture, Get_ShouldReturnNullptrIfSlotKeyNotInContainer)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(m_containerA.Get(SlotMapKey<> {1, 0}), nullptr);
|
|
||||||
EXPECT_EQ(std::as_const(m_containerA).Get(SlotMapKey<> {1, 0}), nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(AssetContainerFixture, Remove_ShouldRemoveTheAsset)
|
TEST_F(AssetContainerFixture, Remove_ShouldRemoveTheAsset)
|
||||||
{
|
{
|
||||||
const SlotMapKey slotKey = m_containerA.Insert();
|
const ContainerHandle* handle = m_containerA.Insert();
|
||||||
const UUID uuid = m_containerA.Get(slotKey)->GetHeader().uuid;
|
const UUID uuid = handle->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
m_containerA.Remove(uuid);
|
m_containerA.Remove(uuid);
|
||||||
|
|
||||||
EXPECT_EQ(m_containerA.Get(slotKey), nullptr);
|
EXPECT_EQ(handle->GetAsset(), nullptr);
|
||||||
EXPECT_FALSE(m_containerA.Has(uuid));
|
EXPECT_FALSE(m_containerA.Has(uuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetContainerFixture, IsMarkedForRemove_ShouldReturnTrueIfTheAssetIsMarkedForDelete)
|
||||||
|
{
|
||||||
|
const ContainerHandle* handle = m_containerA.Insert();
|
||||||
|
const UUID uuid = handle->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
|
m_containerA.QueueForRemoval(uuid);
|
||||||
|
|
||||||
|
EXPECT_TRUE(m_containerA.IsMarkedForRemove(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetContainerFixture, IsMarkedForRemove_ShouldReturnFalseIfTheAssetIsNotMarkedForDelete)
|
||||||
|
{
|
||||||
|
const ContainerHandle* handle = m_containerA.Insert();
|
||||||
|
const UUID uuid = handle->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
|
EXPECT_FALSE(m_containerA.IsMarkedForRemove(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetContainerFixture, QueueForRemoval_ShouldMarkTheAssetForRemoval)
|
||||||
|
{
|
||||||
|
const ContainerHandle* handle = m_containerA.Insert();
|
||||||
|
const UUID uuid = handle->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
|
m_containerA.QueueForRemoval(uuid);
|
||||||
|
|
||||||
|
EXPECT_TRUE(m_containerA.IsMarkedForRemove(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetContainerFixture, CancelRemoval_ShouldUnmarkAQueuedAsset)
|
||||||
|
{
|
||||||
|
const ContainerHandle* handle = m_containerA.Insert();
|
||||||
|
const UUID uuid = handle->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
|
m_containerA.QueueForRemoval(uuid);
|
||||||
|
m_containerA.CancelRemoval(uuid);
|
||||||
|
|
||||||
|
EXPECT_FALSE(m_containerA.IsMarkedForRemove(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetContainerFixture, ProcessPendingRemovals_ShouldRemoveQueuedAssets)
|
||||||
|
{
|
||||||
|
const ContainerHandle* handle = m_containerA.Insert();
|
||||||
|
const UUID uuid = handle->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
|
m_containerA.QueueForRemoval(uuid);
|
||||||
|
m_containerA.ProcessPendingRemovals();
|
||||||
|
|
||||||
|
EXPECT_EQ(handle->GetAsset(), nullptr);
|
||||||
|
EXPECT_FALSE(m_containerA.Has(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetContainerFixture, ProcessPendingRemovals_ShouldNotRemoveAssetsThatAreNotQueued)
|
||||||
|
{
|
||||||
|
const ContainerHandle* handle = m_containerA.Insert();
|
||||||
|
const UUID uuid = handle->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
|
m_containerA.ProcessPendingRemovals();
|
||||||
|
|
||||||
|
EXPECT_NE(handle->GetAsset(), nullptr);
|
||||||
|
EXPECT_TRUE(m_containerA.Has(uuid));
|
||||||
|
}
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -73,6 +73,173 @@ TEST_F(AssetLibraryFixture, GetAssetContainer_ShouldReturnNullptrIfTheContainerD
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetLibraryFixture, GetAssetContainer_ShouldReturnTheContainerThatHasTheAsset)
|
||||||
|
{
|
||||||
|
std::ignore = m_library.Insert(&m_containerA);
|
||||||
|
std::ignore = m_library.Insert(&m_containerB);
|
||||||
|
|
||||||
|
const UUID uuid = m_containerB.Insert()->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
|
EXPECT_EQ(m_library.GetAssetContainer(uuid), &m_containerB);
|
||||||
|
EXPECT_EQ(std::as_const(m_library).GetAssetContainer(uuid), &m_containerB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetLibraryFixture, GetAssetContainer_ShouldReturnNullptrIfNoContainerHasTheAsset)
|
||||||
|
{
|
||||||
|
std::ignore = m_library.Insert(&m_containerA);
|
||||||
|
std::ignore = m_library.Insert(&m_containerB);
|
||||||
|
|
||||||
|
const UUID uuid;
|
||||||
|
|
||||||
|
EXPECT_EQ(m_library.GetAssetContainer(uuid), nullptr);
|
||||||
|
EXPECT_EQ(std::as_const(m_library).GetAssetContainer(uuid), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetLibraryFixture, IsLoaded_ShouldReturnTrueIfTheAssetIsLoaded)
|
||||||
|
{
|
||||||
|
std::ignore = m_library.Insert(&m_containerA);
|
||||||
|
std::ignore = m_library.Insert(&m_containerB);
|
||||||
|
|
||||||
|
const UUID uuid = m_containerB.Insert()->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
|
EXPECT_TRUE(m_library.IsLoaded(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetLibraryFixture, IsLoaded_ShouldReturnFalseIfTheAssetIsNotLoaded)
|
||||||
|
{
|
||||||
|
std::ignore = m_library.Insert(&m_containerA);
|
||||||
|
std::ignore = m_library.Insert(&m_containerB);
|
||||||
|
|
||||||
|
const UUID uuid;
|
||||||
|
|
||||||
|
EXPECT_FALSE(m_library.IsLoaded(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetLibraryFixture, IsLoaded_ShouldReturnFalseIfTheAssetWasRemovedFromItsContainer)
|
||||||
|
{
|
||||||
|
std::ignore = m_library.Insert(&m_containerA);
|
||||||
|
std::ignore = m_library.Insert(&m_containerB);
|
||||||
|
|
||||||
|
const UUID uuid = m_containerB.Insert()->GetAsset()->GetHeader().uuid;
|
||||||
|
ASSERT_TRUE(m_library.IsLoaded(uuid));
|
||||||
|
|
||||||
|
m_containerB.Remove(uuid);
|
||||||
|
|
||||||
|
EXPECT_FALSE(m_library.IsLoaded(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetLibraryFixture, ProcessPendingRemovals_ShouldProcessRemovalsOnEveryContainer)
|
||||||
|
{
|
||||||
|
std::ignore = m_library.Insert(&m_containerA);
|
||||||
|
std::ignore = m_library.Insert(&m_containerB);
|
||||||
|
|
||||||
|
const UUID uuidA = m_containerA.Insert()->GetAsset()->GetHeader().uuid;
|
||||||
|
const UUID uuidB = m_containerB.Insert()->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
|
m_containerA.QueueForRemoval(uuidA);
|
||||||
|
m_containerB.QueueForRemoval(uuidB);
|
||||||
|
|
||||||
|
m_library.ProcessPendingRemovals();
|
||||||
|
|
||||||
|
EXPECT_FALSE(m_containerA.Has(uuidA));
|
||||||
|
EXPECT_FALSE(m_containerB.Has(uuidB));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetLibraryFixture, ProcessPendingRemovals_ShouldNotRemoveAssetsThatAreNotQueued)
|
||||||
|
{
|
||||||
|
std::ignore = m_library.Insert(&m_containerA);
|
||||||
|
|
||||||
|
const UUID uuid = m_containerA.Insert()->GetAsset()->GetHeader().uuid;
|
||||||
|
|
||||||
|
m_library.ProcessPendingRemovals();
|
||||||
|
|
||||||
|
EXPECT_TRUE(m_containerA.Has(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(AssetLibraryFixture, ProcessPendingRemovals_ShouldCascadeThroughHardReferencedAssetsOneLevelPerCall)
|
||||||
|
{
|
||||||
|
const ScopedActiveAssetLibrary activeAssetLibraryScoped {&m_library};
|
||||||
|
|
||||||
|
std::ignore = m_library.Insert(&m_containerA);
|
||||||
|
std::ignore = m_library.Insert(&m_containerB);
|
||||||
|
std::ignore = m_library.Insert(&m_containerC);
|
||||||
|
|
||||||
|
UUID leafUUID;
|
||||||
|
UUID middleUUID;
|
||||||
|
UUID rootUUID;
|
||||||
|
|
||||||
|
{
|
||||||
|
// leaf
|
||||||
|
AssetA* leaf = CreateAsset<AssetA>();
|
||||||
|
leafUUID = leaf->GetHeader().uuid;
|
||||||
|
|
||||||
|
// middle --> leaf
|
||||||
|
AssetB* middle = CreateAsset<AssetB>();
|
||||||
|
middle->GetAsset().ref_a = HardReference<AssetA> {leafUUID};
|
||||||
|
middleUUID = middle->GetHeader().uuid;
|
||||||
|
|
||||||
|
// root
|
||||||
|
// / \
|
||||||
|
// v v
|
||||||
|
// middle --> leaf
|
||||||
|
AssetC* root = CreateAsset<AssetC>();
|
||||||
|
root->GetAsset().asset_b_ref = HardReference<AssetB> {middleUUID};
|
||||||
|
root->GetAsset().inner_table->asset_a_ref = HardReference<AssetA> {leafUUID};
|
||||||
|
rootUUID = root->GetHeader().uuid;
|
||||||
|
|
||||||
|
const HardReference<AssetC> rootRef {rootUUID};
|
||||||
|
const HardReference<AssetB> middleRef {middleUUID};
|
||||||
|
const HardReference<AssetA> leafRef {leafUUID};
|
||||||
|
|
||||||
|
ASSERT_NE(rootRef.Get(), nullptr);
|
||||||
|
ASSERT_NE(middleRef.Get(), nullptr);
|
||||||
|
ASSERT_NE(leafRef.Get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Releasing the outer HardReferences only drops root's count to zero: middle and leaf are
|
||||||
|
// still kept alive by root's own internal HardReferences to them.
|
||||||
|
EXPECT_TRUE(m_containerC.IsMarkedForRemove(rootUUID));
|
||||||
|
EXPECT_FALSE(m_containerB.IsMarkedForRemove(middleUUID));
|
||||||
|
EXPECT_FALSE(m_containerA.IsMarkedForRemove(leafUUID));
|
||||||
|
EXPECT_TRUE(m_library.IsLoaded(rootUUID));
|
||||||
|
EXPECT_TRUE(m_library.IsLoaded(middleUUID));
|
||||||
|
EXPECT_TRUE(m_library.IsLoaded(leafUUID));
|
||||||
|
|
||||||
|
// 1st pass: removing root destroys its HardReference to middle, dropping middle's count to
|
||||||
|
// zero; leaf is still held alive by middle's own HardReference to it.
|
||||||
|
m_library.ProcessPendingRemovals();
|
||||||
|
EXPECT_FALSE(m_library.IsLoaded(rootUUID));
|
||||||
|
EXPECT_TRUE(m_containerB.IsMarkedForRemove(middleUUID));
|
||||||
|
EXPECT_TRUE(m_library.IsLoaded(middleUUID));
|
||||||
|
EXPECT_TRUE(m_library.IsLoaded(leafUUID));
|
||||||
|
|
||||||
|
// 2nd pass: removing middle destroys its HardReference to leaf, dropping leaf's count to zero.
|
||||||
|
m_library.ProcessPendingRemovals();
|
||||||
|
EXPECT_FALSE(m_library.IsLoaded(middleUUID));
|
||||||
|
EXPECT_TRUE(m_containerA.IsMarkedForRemove(leafUUID));
|
||||||
|
EXPECT_TRUE(m_library.IsLoaded(leafUUID));
|
||||||
|
|
||||||
|
// 3rd pass: nothing references leaf anymore, it finally gets removed.
|
||||||
|
m_library.ProcessPendingRemovals();
|
||||||
|
EXPECT_FALSE(m_library.IsLoaded(leafUUID));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(AssetLibraryFixture, SetActiveAssetLibrary_ShouldSetTheActiveAssetLibraryToTheGivenLibrary)
|
TEST_F(AssetLibraryFixture, SetActiveAssetLibrary_ShouldSetTheActiveAssetLibraryToTheGivenLibrary)
|
||||||
{
|
{
|
||||||
SetActiveAssetLibrary(&m_library);
|
SetActiveAssetLibrary(&m_library);
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*********************************************************************
|
||||||
|
* \file AssetTypeID.cpp
|
||||||
|
*
|
||||||
|
* \author Romain BOULLARD
|
||||||
|
* \date August 2026
|
||||||
|
*********************************************************************/
|
||||||
|
#include <Engine/Asset/AssetTypeID.hpp>
|
||||||
|
|
||||||
|
#include <Engine/Asset/AssetTypeID_generated.hpp>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace Bigfoot
|
||||||
|
{
|
||||||
|
TEST(AssetTypeID, Pack_ShouldGiveAFlatAssetTypeIDWithTheSameValue)
|
||||||
|
{
|
||||||
|
constexpr AssetTypeID assetTypeID = 42;
|
||||||
|
|
||||||
|
const ::Flat::Bigfoot::AssetTypeID flatAssetTypeID = flatbuffers::Pack(assetTypeID);
|
||||||
|
EXPECT_EQ(flatAssetTypeID.value(), assetTypeID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST(AssetTypeID, UnPack_ShouldGiveBackTheOriginalValue)
|
||||||
|
{
|
||||||
|
constexpr AssetTypeID assetTypeID = 42;
|
||||||
|
|
||||||
|
const ::Flat::Bigfoot::AssetTypeID flatAssetTypeID = flatbuffers::Pack(assetTypeID);
|
||||||
|
EXPECT_EQ(flatbuffers::UnPack(flatAssetTypeID), assetTypeID);
|
||||||
|
}
|
||||||
|
} // namespace Bigfoot
|
||||||
@@ -1,26 +1,49 @@
|
|||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* \file AssetLibrary.cpp
|
* \file Reference.cpp
|
||||||
*
|
*
|
||||||
* \author Romain BOULLARD
|
* \author Romain BOULLARD
|
||||||
* \date July 2026
|
* \date August 2026
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
#include <Engine/Asset/Reference.hpp>
|
||||||
|
|
||||||
#include <Engine/Asset/AssetLibrary.hpp>
|
#include <Engine/Asset/AssetLibrary.hpp>
|
||||||
|
|
||||||
#include <AssetsForTesting/Asset/AssetA.hpp>
|
#include <AssetsForTesting/Asset/AssetA.hpp>
|
||||||
#include <AssetsForTesting/Asset/AssetB.hpp>
|
|
||||||
#include <AssetsForTesting/Asset/AssetC.hpp>
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
{
|
{
|
||||||
class HardReferenceFixture: public ::testing::Test
|
template<class REFERENCE>
|
||||||
|
struct RefCountTraits;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct RefCountTraits<HardReference<AssetA>>
|
||||||
|
{
|
||||||
|
[[nodiscard]]
|
||||||
|
static std::uint32_t Get(const ContainerHandle* p_handle)
|
||||||
|
{
|
||||||
|
return p_handle->GetHardRefCount();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct RefCountTraits<SoftReference<AssetA>>
|
||||||
|
{
|
||||||
|
[[nodiscard]]
|
||||||
|
static std::uint32_t Get(const ContainerHandle* p_handle)
|
||||||
|
{
|
||||||
|
return p_handle->GetSoftRefCount();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class REFERENCE>
|
||||||
|
class ReferenceFixture: public ::testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override
|
void SetUp() override
|
||||||
{
|
{
|
||||||
SetActiveAssetLibrary(&m_library);
|
SetActiveAssetLibrary(&m_library);
|
||||||
|
|
||||||
std::ignore = m_library.Insert(&m_containerA);
|
std::ignore = m_library.Insert(&m_containerA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,452 +52,244 @@ class HardReferenceFixture: public ::testing::Test
|
|||||||
SetActiveAssetLibrary(&g_assetLibrary);
|
SetActiveAssetLibrary(&g_assetLibrary);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetContainer<AssetA> m_containerA;
|
[[nodiscard]]
|
||||||
|
static std::uint32_t GetRefCount(const ContainerHandle* p_handle)
|
||||||
AssetLibrary m_library;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, GetUUID_ShouldReturnTheUUID)
|
|
||||||
{
|
|
||||||
UUID uuid;
|
|
||||||
HardReference<AssetA> hardRef {uuid};
|
|
||||||
|
|
||||||
EXPECT_EQ(hardRef.GetUUID(), uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, Get_ShouldReturnTheAsset)
|
|
||||||
{
|
|
||||||
const auto key = m_containerA.Insert();
|
|
||||||
const UUID uuid = m_containerA.Get(key)->GetHeader().uuid;
|
|
||||||
|
|
||||||
HardReference<AssetA> hardRef {uuid};
|
|
||||||
|
|
||||||
EXPECT_EQ(hardRef.Get(), m_containerA.Get(key));
|
|
||||||
EXPECT_EQ(std::as_const(hardRef).Get(), std::as_const(m_containerA).Get(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, Get_ShouldReturnNullptrIfTheAssetDoesNotExist)
|
|
||||||
{
|
|
||||||
UUID uuid;
|
|
||||||
HardReference<AssetA> hardRef {uuid};
|
|
||||||
|
|
||||||
EXPECT_EQ(hardRef.Get(), nullptr);
|
|
||||||
EXPECT_EQ(std::as_const(hardRef).Get(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, Get_ShouldReturnNullptrAfterTheAssetIsRemovedFromTheContainer)
|
|
||||||
{
|
|
||||||
const auto key = m_containerA.Insert();
|
|
||||||
const UUID uuid = m_containerA.Get(key)->GetHeader().uuid;
|
|
||||||
|
|
||||||
HardReference<AssetA> hardRef {uuid};
|
|
||||||
|
|
||||||
m_containerA.Remove(uuid);
|
|
||||||
|
|
||||||
EXPECT_EQ(hardRef.Get(), nullptr);
|
|
||||||
EXPECT_EQ(std::as_const(hardRef).Get(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, ShouldTouchTheHardRefCountOfTheHandle)
|
|
||||||
{
|
|
||||||
UUID uuid;
|
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(uuid);
|
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 0);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
HardReference<AssetA> hardRef1 {uuid};
|
return RefCountTraits<REFERENCE>::Get(p_handle);
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 1);
|
|
||||||
{
|
|
||||||
HardReference<AssetA> hardRef2 {uuid};
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 2);
|
|
||||||
}
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, CopyConstructor_ShouldIncrementTheHardRefCountAndCopyTheState)
|
|
||||||
{
|
|
||||||
const auto key = m_containerA.Insert();
|
|
||||||
const UUID uuid = m_containerA.Get(key)->GetHeader().uuid;
|
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(uuid);
|
|
||||||
|
|
||||||
HardReference<AssetA> hardRef1 {uuid};
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 1);
|
|
||||||
|
|
||||||
HardReference<AssetA> hardRef2 {hardRef1};
|
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 2);
|
|
||||||
EXPECT_EQ(hardRef2.GetUUID(), uuid);
|
|
||||||
EXPECT_EQ(hardRef2.Get(), m_containerA.Get(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, MoveConstructor_ShouldTransferTheStateWithoutChangingTheHardRefCount)
|
|
||||||
{
|
|
||||||
const auto key = m_containerA.Insert();
|
|
||||||
const UUID uuid = m_containerA.Get(key)->GetHeader().uuid;
|
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(uuid);
|
|
||||||
|
|
||||||
HardReference<AssetA> hardRef1 {uuid};
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 1);
|
|
||||||
|
|
||||||
HardReference<AssetA> hardRef2 {std::move(hardRef1)};
|
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 1);
|
|
||||||
EXPECT_EQ(hardRef2.GetUUID(), uuid);
|
|
||||||
EXPECT_EQ(hardRef2.Get(), m_containerA.Get(key));
|
|
||||||
EXPECT_EQ(hardRef1.GetUUID(), UUID::NULL_UUID);
|
|
||||||
EXPECT_EQ(hardRef1.Get(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, CopyAssignment_ShouldReleaseThePreviousHandleAndAcquireTheNewOne)
|
|
||||||
{
|
|
||||||
UUID uuidA;
|
|
||||||
UUID uuidB;
|
|
||||||
const ContainerHandle* handleA = m_containerA.AcquireContainerHandle(uuidA);
|
|
||||||
const ContainerHandle* handleB = m_containerA.AcquireContainerHandle(uuidB);
|
|
||||||
|
|
||||||
HardReference<AssetA> hardRefA {uuidA};
|
|
||||||
HardReference<AssetA> hardRefB {uuidB};
|
|
||||||
EXPECT_EQ(handleA->GetHardRefCount(), 1);
|
|
||||||
EXPECT_EQ(handleB->GetHardRefCount(), 1);
|
|
||||||
|
|
||||||
hardRefB = hardRefA;
|
|
||||||
|
|
||||||
EXPECT_EQ(handleA->GetHardRefCount(), 2);
|
|
||||||
EXPECT_EQ(handleB->GetHardRefCount(), 0);
|
|
||||||
EXPECT_EQ(hardRefB.GetUUID(), uuidA);
|
|
||||||
EXPECT_EQ(hardRefB.Get(), hardRefA.Get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, CopyAssignment_SelfAssignment_ShouldNotChangeTheHardRefCount)
|
|
||||||
{
|
|
||||||
UUID uuid;
|
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(uuid);
|
|
||||||
|
|
||||||
HardReference<AssetA> hardRef {uuid};
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 1);
|
|
||||||
|
|
||||||
HardReference<AssetA>* selfPtr = &hardRef;
|
|
||||||
hardRef = *selfPtr;
|
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 1);
|
|
||||||
EXPECT_EQ(hardRef.GetUUID(), uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, MoveAssignment_ShouldReleaseThePreviousHandleAndTransferTheNewOne)
|
|
||||||
{
|
|
||||||
UUID uuidA;
|
|
||||||
UUID uuidB;
|
|
||||||
const ContainerHandle* handleA = m_containerA.AcquireContainerHandle(uuidA);
|
|
||||||
const ContainerHandle* handleB = m_containerA.AcquireContainerHandle(uuidB);
|
|
||||||
|
|
||||||
HardReference<AssetA> hardRefA {uuidA};
|
|
||||||
HardReference<AssetA> hardRefB {uuidB};
|
|
||||||
EXPECT_EQ(handleA->GetHardRefCount(), 1);
|
|
||||||
EXPECT_EQ(handleB->GetHardRefCount(), 1);
|
|
||||||
|
|
||||||
hardRefB = std::move(hardRefA);
|
|
||||||
|
|
||||||
EXPECT_EQ(handleA->GetHardRefCount(), 1);
|
|
||||||
EXPECT_EQ(handleB->GetHardRefCount(), 0);
|
|
||||||
EXPECT_EQ(hardRefB.GetUUID(), uuidA);
|
|
||||||
EXPECT_EQ(hardRefA.GetUUID(), UUID::NULL_UUID);
|
|
||||||
EXPECT_EQ(hardRefA.Get(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, MoveAssignment_SelfAssignment_ShouldNotChangeTheHardRefCount)
|
|
||||||
{
|
|
||||||
UUID uuid;
|
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(uuid);
|
|
||||||
|
|
||||||
HardReference<AssetA> hardRef {uuid};
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 1);
|
|
||||||
|
|
||||||
HardReference<AssetA>* selfPtr = &hardRef;
|
|
||||||
hardRef = std::move(*selfPtr);
|
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetHardRefCount(), 1);
|
|
||||||
EXPECT_EQ(hardRef.GetUUID(), uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, EqualityOperator_ShouldReturnTrueForReferencesWithTheSameUUID)
|
|
||||||
{
|
|
||||||
UUID uuid;
|
|
||||||
HardReference<AssetA> hardRef1 {uuid};
|
|
||||||
HardReference<AssetA> hardRef2 {uuid};
|
|
||||||
|
|
||||||
EXPECT_EQ(hardRef1, hardRef2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(HardReferenceFixture, EqualityOperator_ShouldReturnFalseForReferencesWithDifferentUUIDs)
|
|
||||||
{
|
|
||||||
UUID uuid1;
|
|
||||||
UUID uuid2;
|
|
||||||
HardReference<AssetA> hardRef1 {uuid1};
|
|
||||||
HardReference<AssetA> hardRef2 {uuid2};
|
|
||||||
|
|
||||||
EXPECT_NE(hardRef1, hardRef2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
class SoftReferenceFixture: public ::testing::Test
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
void SetUp() override
|
|
||||||
{
|
|
||||||
SetActiveAssetLibrary(&m_library);
|
|
||||||
|
|
||||||
std::ignore = m_library.Insert(&m_containerA);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown() override
|
|
||||||
{
|
|
||||||
SetActiveAssetLibrary(&g_assetLibrary);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetContainer<AssetA> m_containerA;
|
AssetContainer<AssetA> m_containerA;
|
||||||
|
|
||||||
AssetLibrary m_library;
|
AssetLibrary m_library;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ReferenceTypeNameGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
static std::string GetName([[maybe_unused]] int p_index)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<T, HardReference<AssetA>>)
|
||||||
|
{
|
||||||
|
return "HardReference";
|
||||||
|
}
|
||||||
|
if constexpr (std::is_same_v<T, SoftReference<AssetA>>)
|
||||||
|
{
|
||||||
|
return "SoftReference";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using ReferenceTypes = ::testing::Types<HardReference<AssetA>, SoftReference<AssetA>>;
|
||||||
|
TYPED_TEST_SUITE(ReferenceFixture, ReferenceTypes, ReferenceTypeNameGenerator);
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, GetUUID_ShouldReturnTheUUID)
|
TYPED_TEST(ReferenceFixture, GetUUID_ShouldReturnTheUUID)
|
||||||
{
|
{
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
SoftReference<AssetA> hardRef {uuid};
|
TypeParam ref {uuid};
|
||||||
|
|
||||||
EXPECT_EQ(hardRef.GetUUID(), uuid);
|
EXPECT_EQ(ref.GetUUID(), uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, Get_ShouldReturnTheAsset)
|
TYPED_TEST(ReferenceFixture, Get_ShouldReturnTheAsset)
|
||||||
{
|
{
|
||||||
const auto key = m_containerA.Insert();
|
const AssetA* inserted = CreateAsset<AssetA>();
|
||||||
const UUID uuid = m_containerA.Get(key)->GetHeader().uuid;
|
const UUID uuid = inserted->GetHeader().uuid;
|
||||||
|
|
||||||
SoftReference<AssetA> hardRef {uuid};
|
TypeParam ref {uuid};
|
||||||
|
|
||||||
EXPECT_EQ(hardRef.Get(), m_containerA.Get(key));
|
EXPECT_EQ(ref.Get(), inserted);
|
||||||
EXPECT_EQ(std::as_const(hardRef).Get(), std::as_const(m_containerA).Get(key));
|
EXPECT_EQ(std::as_const(ref).Get(), inserted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, Get_ShouldReturnNullptrIfTheAssetDoesNotExist)
|
TYPED_TEST(ReferenceFixture, Get_ShouldReturnNullptrIfTheAssetDoesNotExist)
|
||||||
{
|
{
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
SoftReference<AssetA> hardRef {uuid};
|
TypeParam ref {uuid};
|
||||||
|
|
||||||
EXPECT_EQ(hardRef.Get(), nullptr);
|
EXPECT_EQ(ref.Get(), nullptr);
|
||||||
EXPECT_EQ(std::as_const(hardRef).Get(), nullptr);
|
EXPECT_EQ(std::as_const(ref).Get(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, Get_ShouldReturnNullptrAfterTheAssetIsRemovedFromTheContainer)
|
TYPED_TEST(ReferenceFixture, Get_ShouldReturnNullptrAfterTheAssetIsRemovedFromTheContainer)
|
||||||
{
|
{
|
||||||
const auto key = m_containerA.Insert();
|
const AssetA* inserted = CreateAsset<AssetA>();
|
||||||
const UUID uuid = m_containerA.Get(key)->GetHeader().uuid;
|
const UUID uuid = inserted->GetHeader().uuid;
|
||||||
|
|
||||||
SoftReference<AssetA> hardRef {uuid};
|
TypeParam ref {uuid};
|
||||||
|
|
||||||
m_containerA.Remove(uuid);
|
this->m_containerA.Remove(uuid);
|
||||||
|
|
||||||
EXPECT_EQ(hardRef.Get(), nullptr);
|
EXPECT_EQ(ref.Get(), nullptr);
|
||||||
EXPECT_EQ(std::as_const(hardRef).Get(), nullptr);
|
EXPECT_EQ(std::as_const(ref).Get(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, ShouldTouchTheSoftRefCountOfTheHandle)
|
TYPED_TEST(ReferenceFixture, ShouldTouchTheRefCountOfTheHandle)
|
||||||
{
|
{
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(uuid);
|
const ContainerHandle* handle = this->m_containerA.AcquireContainerHandle(uuid);
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 0);
|
EXPECT_EQ(this->GetRefCount(handle), 0);
|
||||||
|
|
||||||
{
|
{
|
||||||
SoftReference<AssetA> softRef1 {uuid};
|
TypeParam ref1 {uuid};
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handle), 1);
|
||||||
{
|
{
|
||||||
SoftReference<AssetA> softRef2 {uuid};
|
TypeParam ref2 {uuid};
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 2);
|
EXPECT_EQ(this->GetRefCount(handle), 2);
|
||||||
}
|
}
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handle), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 0);
|
EXPECT_EQ(this->GetRefCount(handle), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, CopyConstructor_ShouldIncrementTheSoftRefCountAndCopyTheState)
|
TYPED_TEST(ReferenceFixture, CopyConstructor_ShouldIncrementTheRefCountAndCopyTheState)
|
||||||
{
|
{
|
||||||
const auto key = m_containerA.Insert();
|
const AssetA* inserted = CreateAsset<AssetA>();
|
||||||
const UUID uuid = m_containerA.Get(key)->GetHeader().uuid;
|
const UUID uuid = inserted->GetHeader().uuid;
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(uuid);
|
const ContainerHandle* handle = this->m_containerA.AcquireContainerHandle(uuid);
|
||||||
|
|
||||||
SoftReference<AssetA> softRef1 {uuid};
|
TypeParam ref1 {uuid};
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handle), 1);
|
||||||
|
|
||||||
SoftReference<AssetA> softRef2 {softRef1};
|
TypeParam ref2 {ref1};
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 2);
|
EXPECT_EQ(this->GetRefCount(handle), 2);
|
||||||
EXPECT_EQ(softRef2.GetUUID(), uuid);
|
EXPECT_EQ(ref2.GetUUID(), uuid);
|
||||||
EXPECT_EQ(softRef2.Get(), m_containerA.Get(key));
|
EXPECT_EQ(ref2.Get(), inserted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, MoveConstructor_ShouldTransferTheStateWithoutChangingTheSoftRefCount)
|
TYPED_TEST(ReferenceFixture, MoveConstructor_ShouldTransferTheStateWithoutChangingTheRefCount)
|
||||||
{
|
{
|
||||||
const auto key = m_containerA.Insert();
|
const AssetA* inserted = CreateAsset<AssetA>();
|
||||||
const UUID uuid = m_containerA.Get(key)->GetHeader().uuid;
|
const UUID uuid = inserted->GetHeader().uuid;
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(uuid);
|
const ContainerHandle* handle = this->m_containerA.AcquireContainerHandle(uuid);
|
||||||
|
|
||||||
SoftReference<AssetA> softRef1 {uuid};
|
TypeParam ref1 {uuid};
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handle), 1);
|
||||||
|
|
||||||
SoftReference<AssetA> softRef2 {std::move(softRef1)};
|
TypeParam ref2 {std::move(ref1)};
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handle), 1);
|
||||||
EXPECT_EQ(softRef2.GetUUID(), uuid);
|
EXPECT_EQ(ref2.GetUUID(), uuid);
|
||||||
EXPECT_EQ(softRef2.Get(), m_containerA.Get(key));
|
EXPECT_EQ(ref2.Get(), inserted);
|
||||||
EXPECT_EQ(softRef1.GetUUID(), UUID::NULL_UUID);
|
EXPECT_EQ(ref1.GetUUID(), UUID::NULL_UUID);
|
||||||
EXPECT_EQ(softRef1.Get(), nullptr);
|
EXPECT_EQ(ref1.Get(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, CopyAssignment_ShouldReleaseThePreviousHandleAndAcquireTheNewOne)
|
TYPED_TEST(ReferenceFixture, CopyAssignment_ShouldReleaseThePreviousHandleAndAcquireTheNewOne)
|
||||||
{
|
{
|
||||||
UUID uuidA;
|
UUID uuidA;
|
||||||
UUID uuidB;
|
UUID uuidB;
|
||||||
const ContainerHandle* handleA = m_containerA.AcquireContainerHandle(uuidA);
|
const ContainerHandle* handleA = this->m_containerA.AcquireContainerHandle(uuidA);
|
||||||
const ContainerHandle* handleB = m_containerA.AcquireContainerHandle(uuidB);
|
const ContainerHandle* handleB = this->m_containerA.AcquireContainerHandle(uuidB);
|
||||||
|
|
||||||
SoftReference<AssetA> softRefA {uuidA};
|
TypeParam refA {uuidA};
|
||||||
SoftReference<AssetA> softRefB {uuidB};
|
TypeParam refB {uuidB};
|
||||||
EXPECT_EQ(handleA->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handleA), 1);
|
||||||
EXPECT_EQ(handleB->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handleB), 1);
|
||||||
|
|
||||||
softRefB = softRefA;
|
refB = refA;
|
||||||
|
|
||||||
EXPECT_EQ(handleA->GetSoftRefCount(), 2);
|
EXPECT_EQ(this->GetRefCount(handleA), 2);
|
||||||
EXPECT_EQ(handleB->GetSoftRefCount(), 0);
|
EXPECT_EQ(this->GetRefCount(handleB), 0);
|
||||||
EXPECT_EQ(softRefB.GetUUID(), uuidA);
|
EXPECT_EQ(refB.GetUUID(), uuidA);
|
||||||
EXPECT_EQ(softRefB.Get(), softRefA.Get());
|
EXPECT_EQ(refB.Get(), refA.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, CopyAssignment_SelfAssignment_ShouldNotChangeTheSoftRefCount)
|
TYPED_TEST(ReferenceFixture, CopyAssignment_SelfAssignment_ShouldNotChangeTheRefCount)
|
||||||
{
|
{
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(uuid);
|
const ContainerHandle* handle = this->m_containerA.AcquireContainerHandle(uuid);
|
||||||
|
|
||||||
SoftReference<AssetA> softRef {uuid};
|
TypeParam ref {uuid};
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handle), 1);
|
||||||
|
|
||||||
SoftReference<AssetA>* selfPtr = &softRef;
|
TypeParam* selfPtr = &ref;
|
||||||
softRef = *selfPtr;
|
ref = *selfPtr;
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handle), 1);
|
||||||
EXPECT_EQ(softRef.GetUUID(), uuid);
|
EXPECT_EQ(ref.GetUUID(), uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, MoveAssignment_ShouldReleaseThePreviousHandleAndTransferTheNewOne)
|
TYPED_TEST(ReferenceFixture, MoveAssignment_ShouldReleaseThePreviousHandleAndTransferTheNewOne)
|
||||||
{
|
{
|
||||||
UUID uuidA;
|
UUID uuidA;
|
||||||
UUID uuidB;
|
UUID uuidB;
|
||||||
const ContainerHandle* handleA = m_containerA.AcquireContainerHandle(uuidA);
|
const ContainerHandle* handleA = this->m_containerA.AcquireContainerHandle(uuidA);
|
||||||
const ContainerHandle* handleB = m_containerA.AcquireContainerHandle(uuidB);
|
const ContainerHandle* handleB = this->m_containerA.AcquireContainerHandle(uuidB);
|
||||||
|
|
||||||
SoftReference<AssetA> softRefA {uuidA};
|
TypeParam refA {uuidA};
|
||||||
SoftReference<AssetA> softRefB {uuidB};
|
TypeParam refB {uuidB};
|
||||||
EXPECT_EQ(handleA->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handleA), 1);
|
||||||
EXPECT_EQ(handleB->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handleB), 1);
|
||||||
|
|
||||||
softRefB = std::move(softRefA);
|
refB = std::move(refA);
|
||||||
|
|
||||||
EXPECT_EQ(handleA->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handleA), 1);
|
||||||
EXPECT_EQ(handleB->GetSoftRefCount(), 0);
|
EXPECT_EQ(this->GetRefCount(handleB), 0);
|
||||||
EXPECT_EQ(softRefB.GetUUID(), uuidA);
|
EXPECT_EQ(refB.GetUUID(), uuidA);
|
||||||
EXPECT_EQ(softRefA.GetUUID(), UUID::NULL_UUID);
|
EXPECT_EQ(refA.GetUUID(), UUID::NULL_UUID);
|
||||||
EXPECT_EQ(softRefA.Get(), nullptr);
|
EXPECT_EQ(refA.Get(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, MoveAssignment_SelfAssignment_ShouldNotChangeTheSoftRefCount)
|
TYPED_TEST(ReferenceFixture, MoveAssignment_SelfAssignment_ShouldNotChangeTheRefCount)
|
||||||
{
|
{
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
const ContainerHandle* handle = m_containerA.AcquireContainerHandle(uuid);
|
const ContainerHandle* handle = this->m_containerA.AcquireContainerHandle(uuid);
|
||||||
|
|
||||||
SoftReference<AssetA> softRef {uuid};
|
TypeParam ref {uuid};
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handle), 1);
|
||||||
|
|
||||||
SoftReference<AssetA>* selfPtr = &softRef;
|
TypeParam* selfPtr = &ref;
|
||||||
softRef = std::move(*selfPtr);
|
ref = std::move(*selfPtr);
|
||||||
|
|
||||||
EXPECT_EQ(handle->GetSoftRefCount(), 1);
|
EXPECT_EQ(this->GetRefCount(handle), 1);
|
||||||
EXPECT_EQ(softRef.GetUUID(), uuid);
|
EXPECT_EQ(ref.GetUUID(), uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, EqualityOperator_ShouldReturnTrueForReferencesWithTheSameUUID)
|
TYPED_TEST(ReferenceFixture, EqualityOperator_ShouldReturnTrueForReferencesWithTheSameUUID)
|
||||||
{
|
{
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
SoftReference<AssetA> softRef1 {uuid};
|
TypeParam ref1 {uuid};
|
||||||
SoftReference<AssetA> softRef2 {uuid};
|
TypeParam ref2 {uuid};
|
||||||
|
|
||||||
EXPECT_EQ(softRef1, softRef2);
|
EXPECT_EQ(ref1, ref2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(SoftReferenceFixture, EqualityOperator_ShouldReturnFalseForReferencesWithDifferentUUIDs)
|
TYPED_TEST(ReferenceFixture, EqualityOperator_ShouldReturnFalseForReferencesWithDifferentUUIDs)
|
||||||
{
|
{
|
||||||
UUID uuid1;
|
UUID uuid1;
|
||||||
UUID uuid2;
|
UUID uuid2;
|
||||||
SoftReference<AssetA> softRef1 {uuid1};
|
TypeParam ref1 {uuid1};
|
||||||
SoftReference<AssetA> softRef2 {uuid2};
|
TypeParam ref2 {uuid2};
|
||||||
|
|
||||||
EXPECT_NE(softRef1, softRef2);
|
EXPECT_NE(ref1, ref2);
|
||||||
}
|
}
|
||||||
} // namespace Bigfoot
|
} // namespace Bigfoot
|
||||||
|
|||||||
@@ -11,7 +11,11 @@
|
|||||||
#include <EngineTests/BigFileInfo_generated.hpp>
|
#include <EngineTests/BigFileInfo_generated.hpp>
|
||||||
|
|
||||||
#include <AssetsForTesting/Asset/AssetA.hpp>
|
#include <AssetsForTesting/Asset/AssetA.hpp>
|
||||||
|
#include <AssetsForTesting/Asset/AssetB.hpp>
|
||||||
|
#include <AssetsForTesting/Asset/AssetC.hpp>
|
||||||
|
|
||||||
|
#include <EASTL/array.h>
|
||||||
|
#include <gmock/gmock.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -25,8 +29,49 @@ class BigFileFixture: public ::testing::Test
|
|||||||
protected:
|
protected:
|
||||||
void SetUp() override
|
void SetUp() override
|
||||||
{
|
{
|
||||||
BigFile::Request {m_bigFile, "DELETE FROM Asset;"}.Execute();
|
m_bigFile.Clear();
|
||||||
BigFile::Request {m_bigFile, "DELETE FROM AssetMetadata;"}.Execute();
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs an asset and saves it to the BigFile
|
||||||
|
*
|
||||||
|
* \param p_asset The asset to save
|
||||||
|
* \return The UUID the asset was saved under
|
||||||
|
*/
|
||||||
|
template<class ASSET>
|
||||||
|
UUID SaveAsset(ASSET& p_asset)
|
||||||
|
{
|
||||||
|
const eastl::vector<std::byte> flatbuffer = p_asset.Pack();
|
||||||
|
|
||||||
|
m_bigFile.SaveAssetFlatbuffer(p_asset.GetHeader().uuid, flatbuffer, p_asset.GetHardReferences(flatbuffer));
|
||||||
|
|
||||||
|
return p_asset.GetHeader().uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs and saves several assets to the BigFile in a single SaveAssetFlatbuffers
|
||||||
|
*
|
||||||
|
* \param p_assets The assets to save
|
||||||
|
*/
|
||||||
|
void SaveAssets(const eastl::vector<AssetBase*>& p_assets)
|
||||||
|
{
|
||||||
|
eastl::vector<UUID> uuids;
|
||||||
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
||||||
|
eastl::vector<eastl::vector<UUID>> hardReferences;
|
||||||
|
|
||||||
|
uuids.reserve(p_assets.size());
|
||||||
|
flatbuffers.reserve(p_assets.size());
|
||||||
|
hardReferences.reserve(p_assets.size());
|
||||||
|
|
||||||
|
for (AssetBase* const asset: p_assets)
|
||||||
|
{
|
||||||
|
eastl::vector<std::byte> flatbuffer = asset->Pack();
|
||||||
|
hardReferences.push_back(asset->GetHardReferences(flatbuffer));
|
||||||
|
uuids.push_back(asset->GetHeader().uuid);
|
||||||
|
flatbuffers.push_back(std::move(flatbuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bigFile.SaveAssetFlatbuffers(uuids, flatbuffers, hardReferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
BigFile m_bigFile {File {BIGFILE_ENGINETESTS_LOCATION}};
|
BigFile m_bigFile {File {BIGFILE_ENGINETESTS_LOCATION}};
|
||||||
@@ -34,11 +79,39 @@ class BigFileFixture: public ::testing::Test
|
|||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(BigFileFixture, GetAssetFlatbuffer_ShouldReturnNulloptForNonExistentUUID)
|
TEST_F(BigFileFixture, Clear_ShouldRemoveAllAssetsMetadataAndHardReferences)
|
||||||
|
{
|
||||||
|
AssetA referencedAsset;
|
||||||
|
referencedAsset.SetName("referenced");
|
||||||
|
SaveAsset(referencedAsset);
|
||||||
|
|
||||||
|
AssetB asset;
|
||||||
|
asset.SetName("hello");
|
||||||
|
asset.GetAsset().ref_a = HardReference<AssetA> {referencedAsset.GetHeader().uuid};
|
||||||
|
SaveAsset(asset);
|
||||||
|
|
||||||
|
ASSERT_TRUE(m_bigFile.Has(referencedAsset.GetHeader().uuid));
|
||||||
|
ASSERT_TRUE(m_bigFile.Has(asset.GetHeader().uuid));
|
||||||
|
ASSERT_FALSE(m_bigFile.GetAssetHardReferences(asset.GetHeader().uuid).empty());
|
||||||
|
|
||||||
|
m_bigFile.Clear();
|
||||||
|
|
||||||
|
EXPECT_FALSE(m_bigFile.Has(referencedAsset.GetHeader().uuid));
|
||||||
|
EXPECT_FALSE(m_bigFile.Has(asset.GetHeader().uuid));
|
||||||
|
|
||||||
|
EXPECT_TRUE(m_bigFile.GetAssetFlatbuffer(referencedAsset.GetHeader().uuid).empty());
|
||||||
|
EXPECT_TRUE(m_bigFile.GetAssetFlatbuffer(asset.GetHeader().uuid).empty());
|
||||||
|
|
||||||
|
EXPECT_TRUE(m_bigFile.GetAssetHardReferences(asset.GetHeader().uuid).empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, GetAssetFlatbuffer_ShouldReturnEmptyForNonExistentUUID)
|
||||||
{
|
{
|
||||||
const UUID uuid;
|
const UUID uuid;
|
||||||
|
|
||||||
EXPECT_FALSE(m_bigFile.GetAssetFlatbuffer(uuid).has_value());
|
EXPECT_TRUE(m_bigFile.GetAssetFlatbuffer(uuid).empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
@@ -49,294 +122,422 @@ TEST_F(BigFileFixture, GetAssetFlatbuffer_ShouldGetTheAssetFlatbuffer)
|
|||||||
asset.SetName("hello");
|
asset.SetName("hello");
|
||||||
asset.GetAsset().health = 42;
|
asset.GetAsset().health = 42;
|
||||||
asset.GetAsset().mana = 7;
|
asset.GetAsset().mana = 7;
|
||||||
const eastl::vector<std::byte> flatbuffer = asset.Pack();
|
SaveAsset(asset);
|
||||||
|
|
||||||
const AssetMetadata metadata {.m_uuid = asset.GetHeader().uuid,
|
const eastl::vector<std::byte> savedFlatbuffer = m_bigFile.GetAssetFlatbuffer(asset.GetHeader().uuid);
|
||||||
.m_name = asset.GetHeader().name,
|
EXPECT_EQ(savedFlatbuffer, asset.Pack());
|
||||||
.m_typeID = asset.GetHeader().type_id,
|
|
||||||
.m_typeName = asset.GetHeader().type_name};
|
|
||||||
|
|
||||||
m_bigFile.SaveAssetFlatbuffer(metadata, flatbuffer);
|
|
||||||
|
|
||||||
const eastl::optional<eastl::vector<std::byte>> savedFlatbuffer = m_bigFile.GetAssetFlatbuffer(
|
|
||||||
asset.GetHeader().uuid);
|
|
||||||
ASSERT_TRUE(savedFlatbuffer.has_value());
|
|
||||||
EXPECT_EQ(*savedFlatbuffer, flatbuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(BigFileFixture, GetAssetFlatbuffers_ShouldOmitUUIDsThatDoNotExist)
|
TEST_F(BigFileFixture, GetAssetFlatbuffers_ShouldReturnEmptyForUUIDsThatDoNotExist)
|
||||||
{
|
{
|
||||||
AssetA assetA;
|
AssetA assetA;
|
||||||
assetA.SetName("hello");
|
assetA.SetName("hello");
|
||||||
const eastl::vector<std::byte> flatbufferA = assetA.Pack();
|
SaveAsset(assetA);
|
||||||
m_bigFile.SaveAssetFlatbuffer(AssetMetadata {.m_uuid = assetA.GetHeader().uuid,
|
|
||||||
.m_name = assetA.GetHeader().name,
|
|
||||||
.m_typeID = assetA.GetHeader().type_id,
|
|
||||||
.m_typeName = assetA.GetHeader().type_name},
|
|
||||||
flatbufferA);
|
|
||||||
|
|
||||||
AssetA assetB;
|
AssetA assetB;
|
||||||
assetB.SetName("world");
|
assetB.SetName("world");
|
||||||
const eastl::vector<std::byte> flatbufferB = assetB.Pack();
|
SaveAsset(assetB);
|
||||||
m_bigFile.SaveAssetFlatbuffer(AssetMetadata {.m_uuid = assetB.GetHeader().uuid,
|
|
||||||
.m_name = assetB.GetHeader().name,
|
|
||||||
.m_typeID = assetB.GetHeader().type_id,
|
|
||||||
.m_typeName = assetB.GetHeader().type_name},
|
|
||||||
flatbufferB);
|
|
||||||
|
|
||||||
const eastl::vector<UUID> uuids {assetA.GetHeader().uuid, UUID {}, assetB.GetHeader().uuid};
|
const eastl::array<UUID, 3> uuids {assetA.GetHeader().uuid, UUID {}, assetB.GetHeader().uuid};
|
||||||
|
|
||||||
const eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile.GetAssetFlatbuffers(uuids);
|
const eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile.GetAssetFlatbuffers(uuids);
|
||||||
|
|
||||||
ASSERT_EQ(flatbuffers.size(), 2);
|
ASSERT_EQ(flatbuffers.size(), 3);
|
||||||
EXPECT_TRUE((flatbuffers[0] == flatbufferA && flatbuffers[1] == flatbufferB) ||
|
EXPECT_EQ(flatbuffers[0], assetA.Pack());
|
||||||
(flatbuffers[0] == flatbufferB && flatbuffers[1] == flatbufferA));
|
EXPECT_TRUE(flatbuffers[1].empty());
|
||||||
|
EXPECT_EQ(flatbuffers[2], assetB.Pack());
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(BigFileFixture, GetAssetFlatbuffers_ShouldNotDuplicateResultsForADuplicateUUID)
|
TEST_F(BigFileFixture, GetAssetFlatbuffers_ShouldReturnEmptyForASingleUUIDThatDoesNotExist)
|
||||||
{
|
{
|
||||||
AssetA assetA;
|
const eastl::array<UUID, 1> uuids {UUID {}};
|
||||||
assetA.SetName("hello");
|
|
||||||
const eastl::vector<std::byte> flatbufferA = assetA.Pack();
|
|
||||||
m_bigFile.SaveAssetFlatbuffer(AssetMetadata {.m_uuid = assetA.GetHeader().uuid,
|
|
||||||
.m_name = assetA.GetHeader().name,
|
|
||||||
.m_typeID = assetA.GetHeader().type_id,
|
|
||||||
.m_typeName = assetA.GetHeader().type_name},
|
|
||||||
flatbufferA);
|
|
||||||
|
|
||||||
const eastl::vector<UUID> uuids {assetA.GetHeader().uuid, assetA.GetHeader().uuid};
|
|
||||||
|
|
||||||
const eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile.GetAssetFlatbuffers(uuids);
|
const eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile.GetAssetFlatbuffers(uuids);
|
||||||
|
|
||||||
ASSERT_EQ(flatbuffers.size(), 1);
|
ASSERT_EQ(flatbuffers.size(), 1);
|
||||||
EXPECT_EQ(flatbuffers[0], flatbufferA);
|
EXPECT_TRUE(flatbuffers[0].empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(BigFileFixture, GetAssetMetadata_ShouldReturnNulloptForNonExistentUUID)
|
TEST_F(BigFileFixture, GetAssetFlatbuffers_ShouldDuplicateResultsForADuplicateUUID)
|
||||||
{
|
|
||||||
const UUID uuid;
|
|
||||||
|
|
||||||
EXPECT_FALSE(m_bigFile.GetAssetMetadata(uuid).has_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(BigFileFixture, GetAssetMetadata_ShouldGetTheAssetMetadata)
|
|
||||||
{
|
|
||||||
AssetA asset;
|
|
||||||
asset.SetName("hello");
|
|
||||||
asset.GetAsset().health = 42;
|
|
||||||
asset.GetAsset().mana = 7;
|
|
||||||
const eastl::vector<std::byte> flatbuffer = asset.Pack();
|
|
||||||
|
|
||||||
const AssetMetadata metadata {.m_uuid = asset.GetHeader().uuid,
|
|
||||||
.m_name = asset.GetHeader().name,
|
|
||||||
.m_typeID = asset.GetHeader().type_id,
|
|
||||||
.m_typeName = asset.GetHeader().type_name};
|
|
||||||
|
|
||||||
m_bigFile.SaveAssetFlatbuffer(metadata, flatbuffer);
|
|
||||||
|
|
||||||
const eastl::optional<AssetMetadata> savedMetadata = m_bigFile.GetAssetMetadata(asset.GetHeader().uuid);
|
|
||||||
ASSERT_TRUE(savedMetadata.has_value());
|
|
||||||
|
|
||||||
EXPECT_EQ(savedMetadata->m_uuid, metadata.m_uuid);
|
|
||||||
EXPECT_EQ(savedMetadata->m_name, metadata.m_name);
|
|
||||||
EXPECT_EQ(savedMetadata->m_typeID, metadata.m_typeID);
|
|
||||||
EXPECT_EQ(savedMetadata->m_typeName, metadata.m_typeName);
|
|
||||||
EXPECT_GT(savedMetadata->m_creationTime, Time {0});
|
|
||||||
EXPECT_GT(savedMetadata->m_modificationTime, Time {0});
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
|
||||||
|
|
||||||
TEST_F(BigFileFixture, GetAssetMetadatas_ShouldOmitUUIDsThatDoNotExist)
|
|
||||||
{
|
{
|
||||||
AssetA assetA;
|
AssetA assetA;
|
||||||
assetA.SetName("hello");
|
assetA.SetName("hello");
|
||||||
m_bigFile.SaveAssetFlatbuffer(AssetMetadata {.m_uuid = assetA.GetHeader().uuid,
|
SaveAsset(assetA);
|
||||||
.m_name = assetA.GetHeader().name,
|
|
||||||
.m_typeID = assetA.GetHeader().type_id,
|
|
||||||
.m_typeName = assetA.GetHeader().type_name},
|
|
||||||
assetA.Pack());
|
|
||||||
|
|
||||||
AssetA assetB;
|
const eastl::array<UUID, 2> uuids {assetA.GetHeader().uuid, assetA.GetHeader().uuid};
|
||||||
assetB.SetName("world");
|
|
||||||
m_bigFile.SaveAssetFlatbuffer(AssetMetadata {.m_uuid = assetB.GetHeader().uuid,
|
const eastl::vector<eastl::vector<std::byte>> flatbuffers = m_bigFile.GetAssetFlatbuffers(uuids);
|
||||||
.m_name = assetB.GetHeader().name,
|
|
||||||
.m_typeID = assetB.GetHeader().type_id,
|
ASSERT_EQ(flatbuffers.size(), 2);
|
||||||
.m_typeName = assetB.GetHeader().type_name},
|
EXPECT_EQ(flatbuffers[0], assetA.Pack());
|
||||||
assetB.Pack());
|
EXPECT_EQ(flatbuffers[1], assetA.Pack());
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, GetAssetHardReference_ShouldReturnEmptyVectorForNonExistentUUID)
|
||||||
|
{
|
||||||
|
const UUID uuid;
|
||||||
|
|
||||||
|
const eastl::vector<UUID> hardReferences = m_bigFile.GetAssetHardReferences(uuid);
|
||||||
|
|
||||||
|
EXPECT_TRUE(hardReferences.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, GetAssetHardReference_ShouldGetTheAssetHardReferences)
|
||||||
|
{
|
||||||
|
AssetA referencedAssetX;
|
||||||
|
referencedAssetX.SetName("referencedX");
|
||||||
|
|
||||||
|
AssetA referencedAssetY;
|
||||||
|
referencedAssetY.SetName("referencedY");
|
||||||
|
|
||||||
|
AssetB asset;
|
||||||
|
asset.SetName("hello");
|
||||||
|
asset.GetAsset().ref_a = HardReference<AssetA> {referencedAssetX.GetHeader().uuid};
|
||||||
|
asset.GetAsset().refs_a.push_back(SoftReference<AssetA> {referencedAssetY.GetHeader().uuid});
|
||||||
|
SaveAsset(asset);
|
||||||
|
|
||||||
|
const eastl::vector<UUID> hardReferences = m_bigFile.GetAssetHardReferences(asset.GetHeader().uuid);
|
||||||
|
|
||||||
|
EXPECT_THAT(hardReferences, ::testing::ElementsAre(referencedAssetX.GetHeader().uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, GetAssetHardReferences_ShouldReturnEmptyVectorsForUUIDsThatDoNotExistOrHaveNoReferences)
|
||||||
|
{
|
||||||
|
AssetA referencedAsset;
|
||||||
|
referencedAsset.SetName("referenced");
|
||||||
|
|
||||||
|
AssetA assetWithoutReferences;
|
||||||
|
assetWithoutReferences.SetName("noRefs");
|
||||||
|
SaveAsset(assetWithoutReferences);
|
||||||
|
|
||||||
|
AssetB assetWithReferences;
|
||||||
|
assetWithReferences.SetName("withRefs");
|
||||||
|
assetWithReferences.GetAsset().ref_a = HardReference<AssetA> {referencedAsset.GetHeader().uuid};
|
||||||
|
SaveAsset(assetWithReferences);
|
||||||
|
|
||||||
const UUID missingUUID;
|
const UUID missingUUID;
|
||||||
const eastl::vector<UUID> uuids {assetA.GetHeader().uuid, missingUUID, assetB.GetHeader().uuid};
|
const eastl::array<UUID, 3> uuids {assetWithoutReferences.GetHeader().uuid,
|
||||||
|
missingUUID,
|
||||||
|
assetWithReferences.GetHeader().uuid};
|
||||||
|
|
||||||
const eastl::vector<AssetMetadata> metadatas = m_bigFile.GetAssetMetadatas(uuids);
|
const eastl::vector<eastl::vector<UUID>> hardReferences = m_bigFile.GetAssetsHardReferences(uuids);
|
||||||
|
|
||||||
ASSERT_EQ(metadatas.size(), 2);
|
ASSERT_EQ(hardReferences.size(), 3);
|
||||||
EXPECT_TRUE((metadatas[0].m_uuid == assetA.GetHeader().uuid && metadatas[0].m_name == "hello" &&
|
EXPECT_TRUE(hardReferences[0].empty());
|
||||||
metadatas[1].m_uuid == assetB.GetHeader().uuid && metadatas[1].m_name == "world") ||
|
EXPECT_TRUE(hardReferences[1].empty());
|
||||||
(metadatas[0].m_uuid == assetB.GetHeader().uuid && metadatas[0].m_name == "world" &&
|
ASSERT_EQ(hardReferences[2].size(), 1);
|
||||||
metadatas[1].m_uuid == assetA.GetHeader().uuid && metadatas[1].m_name == "hello"));
|
EXPECT_EQ(hardReferences[2][0], referencedAsset.GetHeader().uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, GetAssetHardReferences_ShouldDuplicateResultsForADuplicateUUID)
|
||||||
|
{
|
||||||
|
AssetA referencedAssetX;
|
||||||
|
referencedAssetX.SetName("referencedX");
|
||||||
|
|
||||||
|
AssetA referencedAssetY;
|
||||||
|
referencedAssetY.SetName("referencedY");
|
||||||
|
|
||||||
|
AssetB asset;
|
||||||
|
asset.SetName("hello");
|
||||||
|
asset.GetAsset().ref_a = HardReference<AssetA> {referencedAssetX.GetHeader().uuid};
|
||||||
|
asset.GetAsset().refs_a.push_back(SoftReference<AssetA> {referencedAssetY.GetHeader().uuid});
|
||||||
|
SaveAsset(asset);
|
||||||
|
|
||||||
|
const eastl::array<UUID, 2> uuids {asset.GetHeader().uuid, asset.GetHeader().uuid};
|
||||||
|
|
||||||
|
const eastl::vector<eastl::vector<UUID>> hardReferences = m_bigFile.GetAssetsHardReferences(uuids);
|
||||||
|
|
||||||
|
ASSERT_EQ(hardReferences.size(), 2);
|
||||||
|
for (const eastl::vector<UUID>& entry: hardReferences)
|
||||||
|
{
|
||||||
|
EXPECT_THAT(entry, ::testing::ElementsAre(referencedAssetX.GetHeader().uuid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, GetAssetTime_ShouldReturnNulloptForNonExistentUUID)
|
||||||
|
{
|
||||||
|
const UUID uuid;
|
||||||
|
|
||||||
|
EXPECT_FALSE(m_bigFile.GetAssetTime(uuid).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, GetAssetTime_ShouldReturnCreationAndModificationTimeOnFirstSave)
|
||||||
|
{
|
||||||
|
AssetA asset;
|
||||||
|
asset.SetName("hello");
|
||||||
|
|
||||||
|
const std::uint64_t beforeSave = Time::Now().GetEpoch();
|
||||||
|
SaveAsset(asset);
|
||||||
|
|
||||||
|
const eastl::optional<BigFile::AssetTime> assetTime = m_bigFile.GetAssetTime(asset.GetHeader().uuid);
|
||||||
|
ASSERT_TRUE(assetTime.has_value());
|
||||||
|
|
||||||
|
constexpr std::uint64_t TOLERANCE_MICROSECONDS = 1'000'000;
|
||||||
|
const std::uint64_t creationEpoch = assetTime->m_creationTime.GetEpoch();
|
||||||
|
const std::uint64_t delta = creationEpoch > beforeSave ? creationEpoch - beforeSave : beforeSave - creationEpoch;
|
||||||
|
EXPECT_LE(delta, TOLERANCE_MICROSECONDS);
|
||||||
|
EXPECT_EQ(assetTime->m_creationTime, assetTime->m_modificationTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, SaveAssetFlatbuffer_ShouldUpdateModificationTimeButNotCreationTimeOnSecondSave)
|
||||||
|
{
|
||||||
|
AssetA asset;
|
||||||
|
asset.SetName("hello");
|
||||||
|
SaveAsset(asset);
|
||||||
|
|
||||||
|
const eastl::optional<BigFile::AssetTime> firstAssetTime = m_bigFile.GetAssetTime(asset.GetHeader().uuid);
|
||||||
|
ASSERT_TRUE(firstAssetTime.has_value());
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
|
|
||||||
|
asset.GetAsset().health = 42;
|
||||||
|
SaveAsset(asset);
|
||||||
|
|
||||||
|
const eastl::optional<BigFile::AssetTime> secondAssetTime = m_bigFile.GetAssetTime(asset.GetHeader().uuid);
|
||||||
|
ASSERT_TRUE(secondAssetTime.has_value());
|
||||||
|
|
||||||
|
EXPECT_EQ(secondAssetTime->m_creationTime, firstAssetTime->m_creationTime);
|
||||||
|
EXPECT_GT(secondAssetTime->m_modificationTime.GetEpoch(), firstAssetTime->m_modificationTime.GetEpoch());
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, SaveAssetFlatbuffers_ShouldUpdateModificationTimeButNotCreationTimeOnSecondSave)
|
||||||
|
{
|
||||||
|
AssetA asset;
|
||||||
|
asset.SetName("hello");
|
||||||
|
SaveAssets({&asset});
|
||||||
|
|
||||||
|
const eastl::optional<BigFile::AssetTime> firstAssetTime = m_bigFile.GetAssetTime(asset.GetHeader().uuid);
|
||||||
|
ASSERT_TRUE(firstAssetTime.has_value());
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
|
|
||||||
|
asset.GetAsset().health = 42;
|
||||||
|
SaveAssets({&asset});
|
||||||
|
|
||||||
|
const eastl::optional<BigFile::AssetTime> secondAssetTime = m_bigFile.GetAssetTime(asset.GetHeader().uuid);
|
||||||
|
ASSERT_TRUE(secondAssetTime.has_value());
|
||||||
|
|
||||||
|
EXPECT_EQ(secondAssetTime->m_creationTime, firstAssetTime->m_creationTime);
|
||||||
|
EXPECT_GT(secondAssetTime->m_modificationTime.GetEpoch(), firstAssetTime->m_modificationTime.GetEpoch());
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, GetAssetsTime_ShouldReturnNulloptForUUIDsThatDoNotExist)
|
||||||
|
{
|
||||||
|
AssetA asset;
|
||||||
|
asset.SetName("hello");
|
||||||
|
SaveAsset(asset);
|
||||||
|
|
||||||
|
const UUID missingUUID;
|
||||||
|
const eastl::array<UUID, 2> uuids {asset.GetHeader().uuid, missingUUID};
|
||||||
|
|
||||||
|
const eastl::vector<eastl::optional<BigFile::AssetTime>> times = m_bigFile.GetAssetsTime(uuids);
|
||||||
|
|
||||||
|
ASSERT_EQ(times.size(), 2);
|
||||||
|
EXPECT_TRUE(times[0].has_value());
|
||||||
|
EXPECT_FALSE(times[1].has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, GetAssetsTime_ShouldDuplicateResultsForADuplicateUUID)
|
||||||
|
{
|
||||||
|
AssetA asset;
|
||||||
|
asset.SetName("hello");
|
||||||
|
SaveAsset(asset);
|
||||||
|
|
||||||
|
const eastl::optional<BigFile::AssetTime> expected = m_bigFile.GetAssetTime(asset.GetHeader().uuid);
|
||||||
|
ASSERT_TRUE(expected.has_value());
|
||||||
|
|
||||||
|
const eastl::array<UUID, 2> uuids {asset.GetHeader().uuid, asset.GetHeader().uuid};
|
||||||
|
|
||||||
|
const eastl::vector<eastl::optional<BigFile::AssetTime>> times = m_bigFile.GetAssetsTime(uuids);
|
||||||
|
|
||||||
|
ASSERT_EQ(times.size(), 2);
|
||||||
|
ASSERT_TRUE(times[0].has_value());
|
||||||
|
ASSERT_TRUE(times[1].has_value());
|
||||||
|
EXPECT_EQ(*times[0], *expected);
|
||||||
|
EXPECT_EQ(*times[1], *expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
TEST_F(BigFileFixture, Clear_ShouldRemoveAssetTime)
|
||||||
|
{
|
||||||
|
AssetA asset;
|
||||||
|
asset.SetName("hello");
|
||||||
|
SaveAsset(asset);
|
||||||
|
|
||||||
|
ASSERT_TRUE(m_bigFile.GetAssetTime(asset.GetHeader().uuid).has_value());
|
||||||
|
|
||||||
|
m_bigFile.Clear();
|
||||||
|
|
||||||
|
EXPECT_FALSE(m_bigFile.GetAssetTime(asset.GetHeader().uuid).has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(BigFileFixture, SaveAssetFlatbuffer_ShouldSaveTheAsset)
|
TEST_F(BigFileFixture, SaveAssetFlatbuffer_ShouldSaveTheAsset)
|
||||||
{
|
{
|
||||||
AssetA asset;
|
AssetA referencedAsset;
|
||||||
|
referencedAsset.SetName("referenced");
|
||||||
|
|
||||||
|
AssetB asset;
|
||||||
asset.SetName("hello");
|
asset.SetName("hello");
|
||||||
asset.GetAsset().health = 42;
|
asset.GetAsset().ref_a = HardReference<AssetA> {referencedAsset.GetHeader().uuid};
|
||||||
asset.GetAsset().mana = 7;
|
SaveAsset(asset);
|
||||||
const eastl::vector<std::byte> flatbuffer = asset.Pack();
|
|
||||||
|
|
||||||
const AssetMetadata metadata {.m_uuid = asset.GetHeader().uuid,
|
|
||||||
.m_name = asset.GetHeader().name,
|
|
||||||
.m_typeID = asset.GetHeader().type_id,
|
|
||||||
.m_typeName = asset.GetHeader().type_name};
|
|
||||||
|
|
||||||
m_bigFile.SaveAssetFlatbuffer(metadata, flatbuffer);
|
|
||||||
|
|
||||||
EXPECT_TRUE(m_bigFile.Has(asset.GetHeader().uuid));
|
EXPECT_TRUE(m_bigFile.Has(asset.GetHeader().uuid));
|
||||||
|
|
||||||
|
const eastl::vector<UUID> hardReferences = m_bigFile.GetAssetHardReferences(asset.GetHeader().uuid);
|
||||||
|
ASSERT_EQ(hardReferences.size(), 1);
|
||||||
|
EXPECT_EQ(hardReferences[0], referencedAsset.GetHeader().uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(BigFileFixture, SaveAssetFlatbuffer_ShouldUpdateTheDataWhenCalledTwice)
|
TEST_F(BigFileFixture, SaveAssetFlatbuffer_ShouldUpdateTheDataWhenCalledTwice)
|
||||||
{
|
{
|
||||||
const UUID uuid;
|
AssetA referencedAssetX;
|
||||||
|
referencedAssetX.SetName("referencedX");
|
||||||
|
|
||||||
AssetA asset;
|
AssetA referencedAssetY;
|
||||||
asset.GetAsset().health = 1;
|
referencedAssetY.SetName("referencedY");
|
||||||
m_bigFile.SaveAssetFlatbuffer(AssetMetadata {.m_uuid = uuid,
|
|
||||||
.m_name = "hello",
|
|
||||||
.m_typeID = AssetA::GetTypeID(),
|
|
||||||
.m_typeName = eastl::string {AssetA::GetTypeName()}},
|
|
||||||
asset.Pack());
|
|
||||||
|
|
||||||
const eastl::optional<AssetMetadata> savedMetadata1 = m_bigFile.GetAssetMetadata(uuid);
|
AssetB asset;
|
||||||
ASSERT_TRUE(savedMetadata1.has_value());
|
asset.GetAsset().count = 1;
|
||||||
EXPECT_EQ(savedMetadata1->m_name, "hello");
|
asset.GetAsset().ref_a = HardReference<AssetA> {referencedAssetX.GetHeader().uuid};
|
||||||
EXPECT_EQ(savedMetadata1->m_typeID, AssetA::GetTypeID());
|
SaveAsset(asset);
|
||||||
EXPECT_EQ(savedMetadata1->m_typeName, eastl::string {AssetA::GetTypeName()});
|
|
||||||
EXPECT_EQ(savedMetadata1->m_modificationTime, savedMetadata1->m_creationTime);
|
|
||||||
|
|
||||||
const eastl::optional<eastl::vector<std::byte>> savedFlatbuffer1 = m_bigFile.GetAssetFlatbuffer(uuid);
|
const eastl::vector<std::byte> savedFlatbuffer1 = m_bigFile.GetAssetFlatbuffer(asset.GetHeader().uuid);
|
||||||
ASSERT_TRUE(savedFlatbuffer1.has_value());
|
ASSERT_FALSE(savedFlatbuffer1.empty());
|
||||||
|
|
||||||
AssetA savedAsset1;
|
AssetB savedAsset1;
|
||||||
savedAsset1.Unpack(*savedFlatbuffer1);
|
savedAsset1.Unpack(savedFlatbuffer1);
|
||||||
EXPECT_EQ(savedAsset1.GetAsset().health, 1);
|
EXPECT_EQ(savedAsset1.GetAsset().count, 1);
|
||||||
|
|
||||||
|
const eastl::vector<UUID> hardReferences1 = m_bigFile.GetAssetHardReferences(asset.GetHeader().uuid);
|
||||||
|
ASSERT_EQ(hardReferences1.size(), 1);
|
||||||
|
EXPECT_EQ(hardReferences1[0], referencedAssetX.GetHeader().uuid);
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
|
|
||||||
asset.GetAsset().health = 2;
|
asset.GetAsset().count = 2;
|
||||||
m_bigFile.SaveAssetFlatbuffer(AssetMetadata {.m_uuid = uuid,
|
asset.GetAsset().ref_a = HardReference<AssetA> {referencedAssetY.GetHeader().uuid};
|
||||||
.m_name = "world",
|
SaveAsset(asset);
|
||||||
.m_typeID = AssetA::GetTypeID(),
|
|
||||||
.m_typeName = eastl::string {AssetA::GetTypeName()}},
|
|
||||||
asset.Pack());
|
|
||||||
|
|
||||||
const eastl::optional<AssetMetadata> savedMetadata2 = m_bigFile.GetAssetMetadata(uuid);
|
const eastl::vector<std::byte> savedFlatbuffer2 = m_bigFile.GetAssetFlatbuffer(asset.GetHeader().uuid);
|
||||||
ASSERT_TRUE(savedMetadata2.has_value());
|
ASSERT_FALSE(savedFlatbuffer2.empty());
|
||||||
EXPECT_EQ(savedMetadata2->m_name, "world");
|
|
||||||
EXPECT_EQ(savedMetadata2->m_typeID, AssetA::GetTypeID());
|
|
||||||
EXPECT_EQ(savedMetadata2->m_typeName, eastl::string {AssetA::GetTypeName()});
|
|
||||||
EXPECT_GT(savedMetadata2->m_modificationTime, savedMetadata2->m_creationTime);
|
|
||||||
|
|
||||||
EXPECT_LT(savedMetadata1->m_modificationTime, savedMetadata2->m_modificationTime);
|
AssetB savedAsset2;
|
||||||
|
savedAsset2.Unpack(savedFlatbuffer2);
|
||||||
|
EXPECT_EQ(savedAsset2.GetAsset().count, 2);
|
||||||
|
|
||||||
const eastl::optional<eastl::vector<std::byte>> savedFlatbuffer2 = m_bigFile.GetAssetFlatbuffer(uuid);
|
const eastl::vector<UUID> hardReferences2 = m_bigFile.GetAssetHardReferences(asset.GetHeader().uuid);
|
||||||
ASSERT_TRUE(savedFlatbuffer2.has_value());
|
ASSERT_EQ(hardReferences2.size(), 1);
|
||||||
|
EXPECT_EQ(hardReferences2[0], referencedAssetY.GetHeader().uuid);
|
||||||
AssetA savedAsset2;
|
EXPECT_NE(hardReferences2[0], referencedAssetX.GetHeader().uuid);
|
||||||
savedAsset2.Unpack(*savedFlatbuffer2);
|
|
||||||
EXPECT_EQ(savedAsset2.GetAsset().health, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(BigFileFixture, SaveAssetFlatbuffers_ShouldSaveTheAssets)
|
TEST_F(BigFileFixture, SaveAssetFlatbuffers_ShouldSaveTheAssets)
|
||||||
{
|
{
|
||||||
AssetA assetA;
|
AssetA referencedAssetA;
|
||||||
|
referencedAssetA.SetName("referencedA");
|
||||||
|
|
||||||
|
AssetA referencedAssetB;
|
||||||
|
referencedAssetB.SetName("referencedB");
|
||||||
|
|
||||||
|
AssetB assetA;
|
||||||
assetA.SetName("hello");
|
assetA.SetName("hello");
|
||||||
assetA.GetAsset().health = 42;
|
assetA.GetAsset().count = 42;
|
||||||
|
assetA.GetAsset().ref_a = HardReference<AssetA> {referencedAssetA.GetHeader().uuid};
|
||||||
|
|
||||||
AssetA assetB;
|
AssetB assetB;
|
||||||
assetB.SetName("world");
|
assetB.SetName("world");
|
||||||
assetB.GetAsset().health = 7;
|
assetB.GetAsset().count = 7;
|
||||||
|
assetB.GetAsset().ref_a = HardReference<AssetA> {referencedAssetB.GetHeader().uuid};
|
||||||
|
|
||||||
const eastl::vector<AssetMetadata> metadatas {AssetMetadata {.m_uuid = assetA.GetHeader().uuid,
|
SaveAssets({&assetA, &assetB});
|
||||||
.m_name = assetA.GetHeader().name,
|
|
||||||
.m_typeID = assetA.GetHeader().type_id,
|
|
||||||
.m_typeName = assetA.GetHeader().type_name},
|
|
||||||
AssetMetadata {.m_uuid = assetB.GetHeader().uuid,
|
|
||||||
.m_name = assetB.GetHeader().name,
|
|
||||||
.m_typeID = assetB.GetHeader().type_id,
|
|
||||||
.m_typeName = assetB.GetHeader().type_name}};
|
|
||||||
const eastl::vector<eastl::vector<std::byte>> flatbuffers {assetA.Pack(), assetB.Pack()};
|
|
||||||
|
|
||||||
m_bigFile.SaveAssetFlatbuffers(metadatas, flatbuffers);
|
|
||||||
|
|
||||||
EXPECT_TRUE(m_bigFile.Has(assetA.GetHeader().uuid));
|
EXPECT_TRUE(m_bigFile.Has(assetA.GetHeader().uuid));
|
||||||
EXPECT_TRUE(m_bigFile.Has(assetB.GetHeader().uuid));
|
EXPECT_TRUE(m_bigFile.Has(assetB.GetHeader().uuid));
|
||||||
|
|
||||||
|
const eastl::vector<UUID> hardReferencesA = m_bigFile.GetAssetHardReferences(assetA.GetHeader().uuid);
|
||||||
|
ASSERT_EQ(hardReferencesA.size(), 1);
|
||||||
|
EXPECT_EQ(hardReferencesA[0], referencedAssetA.GetHeader().uuid);
|
||||||
|
|
||||||
|
const eastl::vector<UUID> hardReferencesB = m_bigFile.GetAssetHardReferences(assetB.GetHeader().uuid);
|
||||||
|
ASSERT_EQ(hardReferencesB.size(), 1);
|
||||||
|
EXPECT_EQ(hardReferencesB[0], referencedAssetB.GetHeader().uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|
||||||
TEST_F(BigFileFixture, SaveAssetFlatbuffers_ShouldUpdateTheDataWhenCalledTwice)
|
TEST_F(BigFileFixture, SaveAssetFlatbuffers_ShouldUpdateTheDataWhenCalledTwice)
|
||||||
{
|
{
|
||||||
const UUID uuid;
|
AssetA referencedAssetX;
|
||||||
|
referencedAssetX.SetName("referencedX");
|
||||||
|
|
||||||
AssetA asset;
|
AssetA referencedAssetY;
|
||||||
asset.GetAsset().health = 1;
|
referencedAssetY.SetName("referencedY");
|
||||||
const eastl::vector<AssetMetadata> metadatas1 {AssetMetadata {.m_uuid = uuid,
|
|
||||||
.m_name = "hello",
|
|
||||||
.m_typeID = AssetA::GetTypeID(),
|
|
||||||
.m_typeName = eastl::string {AssetA::GetTypeName()}}};
|
|
||||||
const eastl::vector<eastl::vector<std::byte>> flatbuffers1 {asset.Pack()};
|
|
||||||
m_bigFile.SaveAssetFlatbuffers(metadatas1, flatbuffers1);
|
|
||||||
|
|
||||||
const eastl::optional<AssetMetadata> savedMetadata1 = m_bigFile.GetAssetMetadata(uuid);
|
AssetB asset;
|
||||||
ASSERT_TRUE(savedMetadata1.has_value());
|
asset.GetAsset().count = 1;
|
||||||
EXPECT_EQ(savedMetadata1->m_name, "hello");
|
asset.GetAsset().ref_a = HardReference<AssetA> {referencedAssetX.GetHeader().uuid};
|
||||||
EXPECT_EQ(savedMetadata1->m_modificationTime, savedMetadata1->m_creationTime);
|
SaveAssets({&asset});
|
||||||
|
|
||||||
const eastl::optional<eastl::vector<std::byte>> savedFlatbuffer1 = m_bigFile.GetAssetFlatbuffer(uuid);
|
eastl::vector<std::byte> savedFlatbuffer1 = m_bigFile.GetAssetFlatbuffer(asset.GetHeader().uuid);
|
||||||
ASSERT_TRUE(savedFlatbuffer1.has_value());
|
ASSERT_FALSE(savedFlatbuffer1.empty());
|
||||||
|
|
||||||
AssetA savedAsset1;
|
AssetB savedAsset1;
|
||||||
savedAsset1.Unpack(*savedFlatbuffer1);
|
savedAsset1.Unpack(savedFlatbuffer1);
|
||||||
EXPECT_EQ(savedAsset1.GetAsset().health, 1);
|
EXPECT_EQ(savedAsset1.GetAsset().count, 1);
|
||||||
|
|
||||||
|
const eastl::vector<UUID> hardReferences1 = m_bigFile.GetAssetHardReferences(asset.GetHeader().uuid);
|
||||||
|
ASSERT_EQ(hardReferences1.size(), 1);
|
||||||
|
EXPECT_EQ(hardReferences1[0], referencedAssetX.GetHeader().uuid);
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
|
|
||||||
asset.GetAsset().health = 2;
|
asset.GetAsset().count = 2;
|
||||||
const eastl::vector<AssetMetadata> metadatas2 {AssetMetadata {.m_uuid = uuid,
|
asset.GetAsset().ref_a = HardReference<AssetA> {referencedAssetY.GetHeader().uuid};
|
||||||
.m_name = "world",
|
SaveAssets({&asset});
|
||||||
.m_typeID = AssetA::GetTypeID(),
|
|
||||||
.m_typeName = eastl::string {AssetA::GetTypeName()}}};
|
|
||||||
const eastl::vector<eastl::vector<std::byte>> flatbuffers2 {asset.Pack()};
|
|
||||||
m_bigFile.SaveAssetFlatbuffers(metadatas2, flatbuffers2);
|
|
||||||
|
|
||||||
const eastl::optional<AssetMetadata> savedMetadata2 = m_bigFile.GetAssetMetadata(uuid);
|
const eastl::vector<std::byte> savedFlatbuffer2 = m_bigFile.GetAssetFlatbuffer(asset.GetHeader().uuid);
|
||||||
ASSERT_TRUE(savedMetadata2.has_value());
|
ASSERT_FALSE(savedFlatbuffer2.empty());
|
||||||
EXPECT_EQ(savedMetadata2->m_name, "world");
|
|
||||||
EXPECT_GT(savedMetadata2->m_modificationTime, savedMetadata2->m_creationTime);
|
|
||||||
|
|
||||||
EXPECT_LT(savedMetadata1->m_modificationTime, savedMetadata2->m_modificationTime);
|
AssetB savedAsset2;
|
||||||
|
savedAsset2.Unpack(savedFlatbuffer2);
|
||||||
|
EXPECT_EQ(savedAsset2.GetAsset().count, 2);
|
||||||
|
|
||||||
const eastl::optional<eastl::vector<std::byte>> savedFlatbuffer2 = m_bigFile.GetAssetFlatbuffer(uuid);
|
const eastl::vector<UUID> hardReferences2 = m_bigFile.GetAssetHardReferences(asset.GetHeader().uuid);
|
||||||
ASSERT_TRUE(savedFlatbuffer2.has_value());
|
ASSERT_EQ(hardReferences2.size(), 1);
|
||||||
|
EXPECT_EQ(hardReferences2[0], referencedAssetY.GetHeader().uuid);
|
||||||
AssetA savedAsset2;
|
|
||||||
savedAsset2.Unpack(*savedFlatbuffer2);
|
|
||||||
EXPECT_EQ(savedAsset2.GetAsset().health, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
@@ -347,14 +548,7 @@ TEST_F(BigFileFixture, Has_ShouldReturnTrueIfTheAssetExists)
|
|||||||
asset.SetName("hello");
|
asset.SetName("hello");
|
||||||
asset.GetAsset().health = 42;
|
asset.GetAsset().health = 42;
|
||||||
asset.GetAsset().mana = 7;
|
asset.GetAsset().mana = 7;
|
||||||
const eastl::vector<std::byte> flatbuffer = asset.Pack();
|
SaveAsset(asset);
|
||||||
|
|
||||||
const AssetMetadata metadata {.m_uuid = asset.GetHeader().uuid,
|
|
||||||
.m_name = asset.GetHeader().name,
|
|
||||||
.m_typeID = asset.GetHeader().type_id,
|
|
||||||
.m_typeName = asset.GetHeader().type_name};
|
|
||||||
|
|
||||||
m_bigFile.SaveAssetFlatbuffer(metadata, flatbuffer);
|
|
||||||
|
|
||||||
EXPECT_TRUE(m_bigFile.Has(asset.GetHeader().uuid));
|
EXPECT_TRUE(m_bigFile.Has(asset.GetHeader().uuid));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,3 +11,5 @@ bigfoot_create_package_tests(
|
|||||||
"")
|
"")
|
||||||
|
|
||||||
bigfoot_create_bigfile("Tests/Bigfoot")
|
bigfoot_create_bigfile("Tests/Bigfoot")
|
||||||
|
|
||||||
|
bigfoot_create_sasquatch_info()
|
||||||
@@ -6,7 +6,8 @@
|
|||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#include <Engine/DataAccessor/DataAccessor.hpp>
|
#include <Engine/DataAccessor/DataAccessor.hpp>
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
#include <EngineTests/DataAccessorMock.hpp>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
namespace Bigfoot
|
namespace Bigfoot
|
||||||
@@ -14,34 +15,6 @@ namespace Bigfoot
|
|||||||
class DataAccessorFixture: public ::testing::Test
|
class DataAccessorFixture: public ::testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
class DataAccessorMock: public DataAccessor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MOCK_METHOD(eastl::optional<eastl::vector<std::byte>>,
|
|
||||||
GetAssetFlatbuffer,
|
|
||||||
(const UUID& p_uuid),
|
|
||||||
(const, override));
|
|
||||||
MOCK_METHOD(eastl::vector<eastl::vector<std::byte>>,
|
|
||||||
GetAssetFlatbuffers,
|
|
||||||
(eastl::span<const UUID> p_uuids),
|
|
||||||
(const, override));
|
|
||||||
MOCK_METHOD(eastl::optional<AssetMetadata>, GetAssetMetadata, (const UUID& p_uuid), (const, override));
|
|
||||||
MOCK_METHOD(eastl::vector<AssetMetadata>,
|
|
||||||
GetAssetMetadatas,
|
|
||||||
(eastl::span<const UUID> p_uuids),
|
|
||||||
(const, override));
|
|
||||||
MOCK_METHOD(void,
|
|
||||||
SaveAssetFlatbuffer,
|
|
||||||
(const AssetMetadata& p_metaData, const eastl::span<const std::byte> p_flatbuffer),
|
|
||||||
(override));
|
|
||||||
MOCK_METHOD(void,
|
|
||||||
SaveAssetFlatbuffers,
|
|
||||||
(eastl::span<const AssetMetadata> p_metadatas,
|
|
||||||
eastl::span<const eastl::vector<std::byte>> p_flatbuffers),
|
|
||||||
(override));
|
|
||||||
MOCK_METHOD(bool, Has, (const UUID& p_uuid), (const, override));
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetUp() override
|
void SetUp() override
|
||||||
{
|
{
|
||||||
m_original = g_dataAccessor;
|
m_original = g_dataAccessor;
|
||||||
@@ -53,7 +26,7 @@ class DataAccessorFixture: public ::testing::Test
|
|||||||
}
|
}
|
||||||
|
|
||||||
DataAccessorMock m_accessor;
|
DataAccessorMock m_accessor;
|
||||||
DataAccessor* m_original;
|
DataAccessor* m_original = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ int main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
GTEST_FLAG_SET(death_test_style, "threadsafe");
|
||||||
|
|
||||||
BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime);
|
BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime);
|
||||||
|
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user